@vite-hub/workflow 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -1
- package/dist/_app-BVWpnNHo.d.ts +11 -0
- package/dist/app-BE3EYOWn.js +10 -0
- package/dist/cloudflare-CeHVSHoN.js +42 -0
- package/dist/cloudflare-env-BVUMOgFK.d.ts +21 -0
- package/dist/cloudflare-env-g0Rf3ClH.js +49 -0
- package/dist/cloudflare-shared-BIeY2kak.d.ts +1 -0
- package/dist/cloudflare-vite-DcM5YVTP.js +40 -0
- package/dist/config-DkgsQuXz.js +92 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +369 -0
- package/dist/module-UYEnVfxy.js +1546 -0
- package/dist/nitro.d.ts +19 -0
- package/dist/nitro.js +2 -0
- package/dist/openworkflow-amN7IkGO.d.ts +24 -0
- package/dist/runtime/cloudflare-runner.d.ts +27 -0
- package/dist/runtime/cloudflare-runner.js +23 -0
- package/dist/runtime/cloudflare-shared.d.ts +2 -0
- package/dist/runtime/cloudflare-shared.js +2 -0
- package/dist/runtime/cloudflare-vite.d.ts +17 -0
- package/dist/runtime/cloudflare-vite.js +2 -0
- package/dist/runtime/execute.d.ts +11 -0
- package/dist/runtime/execute.js +25 -0
- package/dist/runtime/nitro-plugin.d.ts +6 -0
- package/dist/runtime/nitro-plugin.js +14 -0
- package/dist/runtime/openworkflow-worker.d.ts +18 -0
- package/dist/runtime/openworkflow-worker.js +55 -0
- package/dist/runtime/openworkflow.d.ts +2 -0
- package/dist/runtime/openworkflow.js +143 -0
- package/dist/runtime/state.d.ts +35 -0
- package/dist/runtime/state.js +179 -0
- package/dist/runtime/vercel-vite.d.ts +14 -0
- package/dist/runtime/vercel-vite.js +48 -0
- package/dist/types-ThDitg7Z.d.ts +121 -0
- package/dist/vite.d.ts +16 -0
- package/dist/vite.js +503 -0
- package/package.json +93 -5
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { runWithWorkflowRuntimeEvent, setWorkflowRuntimeConfig, setWorkflowRuntimeRegistry } from "./state.js";
|
|
2
|
+
import { t as resolveAppFetch } from "../app-BE3EYOWn.js";
|
|
3
|
+
import { waitUntil } from "@vercel/functions";
|
|
4
|
+
import { H3 } from "h3";
|
|
5
|
+
//#region ../internal/src/runtime/vercel-hosted.ts
|
|
6
|
+
function createVercelHostedServer(adapter) {
|
|
7
|
+
const app = new H3();
|
|
8
|
+
const appHandler = resolveAppFetch(adapter.label, adapter.app);
|
|
9
|
+
let nodeHandlerPromise;
|
|
10
|
+
return function hostedVercelServer(req, res) {
|
|
11
|
+
const handle = async () => {
|
|
12
|
+
nodeHandlerPromise ||= (async () => {
|
|
13
|
+
if (appHandler) {
|
|
14
|
+
const { fromWebHandler } = await import("h3");
|
|
15
|
+
app.use(fromWebHandler(async (request, context) => await appHandler(request, context)));
|
|
16
|
+
}
|
|
17
|
+
const { toNodeHandler } = await import("h3/node");
|
|
18
|
+
return toNodeHandler(app);
|
|
19
|
+
})();
|
|
20
|
+
return (await nodeHandlerPromise)(req, res);
|
|
21
|
+
};
|
|
22
|
+
if (adapter.onRequest) return adapter.onRequest({
|
|
23
|
+
handle,
|
|
24
|
+
req,
|
|
25
|
+
res
|
|
26
|
+
});
|
|
27
|
+
return handle();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/runtime/vercel-vite.ts
|
|
32
|
+
function createWorkflowVercelServer(options = {}) {
|
|
33
|
+
return createVercelHostedServer({
|
|
34
|
+
app: options.app,
|
|
35
|
+
label: "workflow",
|
|
36
|
+
onRequest({ handle, req, res }) {
|
|
37
|
+
setWorkflowRuntimeConfig(options.workflow);
|
|
38
|
+
setWorkflowRuntimeRegistry(options.registry);
|
|
39
|
+
return runWithWorkflowRuntimeEvent({
|
|
40
|
+
req,
|
|
41
|
+
res,
|
|
42
|
+
waitUntil
|
|
43
|
+
}, handle);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { createWorkflowVercelServer };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
type WorkflowProvider = "cloudflare" | "openworkflow" | "vercel";
|
|
3
|
+
interface CloudflareWorkflowBinding<TPayload = unknown> {
|
|
4
|
+
create: (options?: {
|
|
5
|
+
id?: string;
|
|
6
|
+
params?: TPayload;
|
|
7
|
+
}) => Promise<CloudflareWorkflowInstance>;
|
|
8
|
+
get: (id: string) => Promise<CloudflareWorkflowInstance>;
|
|
9
|
+
}
|
|
10
|
+
interface CloudflareWorkflowInstance {
|
|
11
|
+
id: string;
|
|
12
|
+
status: () => Promise<unknown>;
|
|
13
|
+
}
|
|
14
|
+
interface WorkflowSharedOptions {
|
|
15
|
+
binding?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
}
|
|
18
|
+
interface CloudflareWorkflowProviderOptions extends WorkflowSharedOptions {
|
|
19
|
+
provider: "cloudflare";
|
|
20
|
+
}
|
|
21
|
+
interface VercelWorkflowProviderOptions extends WorkflowSharedOptions {
|
|
22
|
+
provider: "vercel";
|
|
23
|
+
}
|
|
24
|
+
interface OpenWorkflowPostgresOptions {
|
|
25
|
+
namespaceId?: string;
|
|
26
|
+
runMigrations?: boolean;
|
|
27
|
+
schema?: string;
|
|
28
|
+
url?: string;
|
|
29
|
+
}
|
|
30
|
+
interface OpenWorkflowWorkerOptions {
|
|
31
|
+
concurrency?: number;
|
|
32
|
+
}
|
|
33
|
+
interface OpenWorkflowProviderOptions extends WorkflowSharedOptions {
|
|
34
|
+
postgres?: OpenWorkflowPostgresOptions;
|
|
35
|
+
provider: "openworkflow";
|
|
36
|
+
worker?: OpenWorkflowWorkerOptions;
|
|
37
|
+
}
|
|
38
|
+
interface InferredWorkflowProviderOptions extends WorkflowSharedOptions {
|
|
39
|
+
postgres?: OpenWorkflowPostgresOptions;
|
|
40
|
+
provider?: undefined;
|
|
41
|
+
worker?: OpenWorkflowWorkerOptions;
|
|
42
|
+
}
|
|
43
|
+
type WorkflowProviderOptions = CloudflareWorkflowProviderOptions | OpenWorkflowProviderOptions | VercelWorkflowProviderOptions;
|
|
44
|
+
type WorkflowModuleProviderOptions = InferredWorkflowProviderOptions | WorkflowProviderOptions;
|
|
45
|
+
type WorkflowModuleOptions = false | WorkflowModuleProviderOptions;
|
|
46
|
+
type ResolvedWorkflowOptions = WorkflowProviderOptions;
|
|
47
|
+
interface WorkflowRun<TPayload = unknown, TResult = unknown> {
|
|
48
|
+
id: string;
|
|
49
|
+
provider: WorkflowProvider;
|
|
50
|
+
result?: TResult;
|
|
51
|
+
status: WorkflowRunStatus;
|
|
52
|
+
metadata?: unknown;
|
|
53
|
+
payload?: TPayload;
|
|
54
|
+
}
|
|
55
|
+
type WorkflowRunStatus = "queued" | "running" | "completed" | "failed" | "unknown";
|
|
56
|
+
interface WorkflowStepOptions {
|
|
57
|
+
retries?: {
|
|
58
|
+
backoff?: string;
|
|
59
|
+
delay?: string;
|
|
60
|
+
limit?: number;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
type WorkflowStepFunction<TInput = unknown, TResult = unknown> = (input: TInput) => TResult | Promise<TResult>;
|
|
64
|
+
interface WorkflowProviderStep {
|
|
65
|
+
do?: <TResult>(name: string, options: WorkflowStepOptions, run: () => TResult | Promise<TResult>) => Promise<TResult>;
|
|
66
|
+
}
|
|
67
|
+
type WorkflowStepRunner<TSteps extends Record<string, WorkflowStepFunction> = Record<string, WorkflowStepFunction>> = { [TName in keyof TSteps]: TSteps[TName] };
|
|
68
|
+
interface WorkflowExecutionContext<TPayload = unknown> {
|
|
69
|
+
id?: string;
|
|
70
|
+
name: string;
|
|
71
|
+
payload: TPayload;
|
|
72
|
+
provider: WorkflowProvider;
|
|
73
|
+
step?: WorkflowProviderStep;
|
|
74
|
+
steps?: WorkflowStepRunner;
|
|
75
|
+
}
|
|
76
|
+
type WorkflowHandler<TPayload = unknown, TResult = unknown> = (context: WorkflowExecutionContext<TPayload>) => TResult | Promise<TResult>;
|
|
77
|
+
type WorkflowRunIdValue = boolean | null | number | string | undefined | {
|
|
78
|
+
readonly [key: string]: WorkflowRunIdValue;
|
|
79
|
+
} | readonly WorkflowRunIdValue[];
|
|
80
|
+
interface WorkflowCreateOptions<TPayload = unknown, TResult = unknown> {
|
|
81
|
+
handler?: WorkflowHandler<TPayload, TResult>;
|
|
82
|
+
id?: (context: {
|
|
83
|
+
name: string;
|
|
84
|
+
payload?: TPayload;
|
|
85
|
+
}) => Promise<WorkflowRunIdValue> | WorkflowRunIdValue;
|
|
86
|
+
name?: string;
|
|
87
|
+
}
|
|
88
|
+
interface WorkflowDefinitionOptions {
|
|
89
|
+
id?: string;
|
|
90
|
+
rootStep?: boolean;
|
|
91
|
+
}
|
|
92
|
+
interface WorkflowDefinition<TPayload = unknown, TResult = unknown> {
|
|
93
|
+
handler: WorkflowHandler<TPayload, TResult>;
|
|
94
|
+
options?: WorkflowDefinitionOptions;
|
|
95
|
+
}
|
|
96
|
+
interface WorkflowHandle<TPayload = unknown, TResult = unknown> {
|
|
97
|
+
defer: (payload?: TPayload, options?: WorkflowStartOptions) => Promise<WorkflowRun<TPayload>>;
|
|
98
|
+
getRun: (id: string) => Promise<WorkflowRun<TPayload, TResult>>;
|
|
99
|
+
name: string;
|
|
100
|
+
run: (payload?: TPayload, options?: WorkflowStartOptions) => Promise<WorkflowRun<TPayload, TResult>>;
|
|
101
|
+
}
|
|
102
|
+
interface WorkflowStartOptions {
|
|
103
|
+
id?: string;
|
|
104
|
+
}
|
|
105
|
+
interface WorkflowDeferOptions extends WorkflowStartOptions {
|
|
106
|
+
deferred?: boolean;
|
|
107
|
+
}
|
|
108
|
+
interface WorkflowDefinitionRegistry {
|
|
109
|
+
[name: string]: () => Promise<{
|
|
110
|
+
default?: WorkflowDefinition;
|
|
111
|
+
[exportName: string]: unknown;
|
|
112
|
+
} | WorkflowDefinition>;
|
|
113
|
+
}
|
|
114
|
+
interface DiscoveredWorkflowDefinition {
|
|
115
|
+
handler: string;
|
|
116
|
+
name: string;
|
|
117
|
+
source?: "inline" | "nitro-server-workflows" | "vite-suffix";
|
|
118
|
+
steps?: string[];
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
export { WorkflowStepRunner as A, WorkflowProviderStep as C, WorkflowStartOptions as D, WorkflowSharedOptions as E, WorkflowStepFunction as O, WorkflowProviderOptions as S, WorkflowRunStatus as T, WorkflowHandle as _, InferredWorkflowProviderOptions as a, WorkflowModuleProviderOptions as b, OpenWorkflowWorkerOptions as c, WorkflowCreateOptions as d, WorkflowDeferOptions as f, WorkflowExecutionContext as g, WorkflowDefinitionRegistry as h, DiscoveredWorkflowDefinition as i, WorkflowStepOptions as k, ResolvedWorkflowOptions as l, WorkflowDefinitionOptions as m, CloudflareWorkflowInstance as n, OpenWorkflowPostgresOptions as o, WorkflowDefinition as p, CloudflareWorkflowProviderOptions as r, OpenWorkflowProviderOptions as s, CloudflareWorkflowBinding as t, VercelWorkflowProviderOptions as u, WorkflowHandler as v, WorkflowRun as w, WorkflowProvider as x, WorkflowModuleOptions as y };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { y as WorkflowModuleOptions } from "./types-ThDitg7Z.js";
|
|
2
|
+
import { NitroModule } from "nitro/types";
|
|
3
|
+
import { Plugin } from "vite";
|
|
4
|
+
|
|
5
|
+
//#region src/vite.d.ts
|
|
6
|
+
type WorkflowVitePlugin = Plugin & {
|
|
7
|
+
nitro: NitroModule;
|
|
8
|
+
};
|
|
9
|
+
declare function hubWorkflow(options?: WorkflowModuleOptions): WorkflowVitePlugin;
|
|
10
|
+
declare module "vite" {
|
|
11
|
+
interface UserConfig {
|
|
12
|
+
workflow?: WorkflowModuleOptions;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { WorkflowVitePlugin, hubWorkflow };
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
import { t as normalizeWorkflowOptions } from "./config-DkgsQuXz.js";
|
|
2
|
+
import { r as getCloudflareWorkflowClassName, t as createCloudflareWorkflowBindings } from "./cloudflare-CeHVSHoN.js";
|
|
3
|
+
import { a as createImportPath, i as computePackageDir, n as discoverWorkflowDefinitions, o as ensureGeneratedDir, r as createRuntimeRegistryContents, s as resolveRuntimeModule$1, t as workflowNitroModule } from "./module-UYEnVfxy.js";
|
|
4
|
+
import { cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { basename, resolve } from "node:path";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { dirname, relative as relative$1, resolve as resolve$1 } from "pathe";
|
|
8
|
+
import { build } from "esbuild";
|
|
9
|
+
const VITEHUB_MODES = {
|
|
10
|
+
e2e: "e2e",
|
|
11
|
+
blob: "blob",
|
|
12
|
+
chat: "chat",
|
|
13
|
+
db: "db",
|
|
14
|
+
env: "env",
|
|
15
|
+
kv: "kv",
|
|
16
|
+
queue: "queue",
|
|
17
|
+
schedule: "schedule",
|
|
18
|
+
sandbox: "sandbox",
|
|
19
|
+
workspace: "workspace",
|
|
20
|
+
workflow: "workflow"
|
|
21
|
+
};
|
|
22
|
+
function isViteCli(argv) {
|
|
23
|
+
return argv.some((arg) => /(?:^|[/\\])vite(?:\.[cm]?js)?$/.test(arg) || arg === "vite");
|
|
24
|
+
}
|
|
25
|
+
function getViteCliMode(argv = process.argv) {
|
|
26
|
+
if (!isViteCli(argv)) return;
|
|
27
|
+
const modes = new Set(Object.values(VITEHUB_MODES));
|
|
28
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
29
|
+
const arg = argv[index];
|
|
30
|
+
const mode = arg === "--mode" || arg === "-m" ? argv[index + 1] : arg.startsWith("--mode=") ? arg.slice(7) : void 0;
|
|
31
|
+
if (mode && modes.has(mode)) return mode;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function getViteMode(env = process.env) {
|
|
35
|
+
return env["VITEHUB_VITE_MODE"] ?? getViteCliMode();
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region ../internal/src/build/client-output.ts
|
|
39
|
+
function hasStaticIndex(clientDir) {
|
|
40
|
+
return existsSync(resolve$1(clientDir, "index.html"));
|
|
41
|
+
}
|
|
42
|
+
async function copyClientOutput(clientDir, targetDir) {
|
|
43
|
+
const resolvedClientDir = resolve$1(clientDir);
|
|
44
|
+
const resolvedTargetDir = resolve$1(targetDir);
|
|
45
|
+
if (resolvedClientDir === resolvedTargetDir) return;
|
|
46
|
+
await rm(resolvedTargetDir, {
|
|
47
|
+
force: true,
|
|
48
|
+
recursive: true
|
|
49
|
+
});
|
|
50
|
+
await mkdir(dirname(resolvedTargetDir), { recursive: true });
|
|
51
|
+
const targetRelativePath = relative$1(resolvedClientDir, resolvedTargetDir);
|
|
52
|
+
if (targetRelativePath && !targetRelativePath.startsWith("../")) {
|
|
53
|
+
const [targetRootEntry] = targetRelativePath.split("/", 1);
|
|
54
|
+
await mkdir(resolvedTargetDir, { recursive: true });
|
|
55
|
+
await Promise.all((await readdir(resolvedClientDir)).filter((entry) => entry !== targetRootEntry).map((entry) => cp(resolve$1(resolvedClientDir, entry), resolve$1(resolvedTargetDir, entry), { recursive: true })));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await cp(resolvedClientDir, resolvedTargetDir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region ../internal/src/build/esbuild.ts
|
|
62
|
+
async function bundleEsmEntry(entryFile, outfile, options = {}) {
|
|
63
|
+
const format = options.format || "esm";
|
|
64
|
+
const platform = options.platform || "neutral";
|
|
65
|
+
await build({
|
|
66
|
+
alias: options.alias,
|
|
67
|
+
banner: format === "esm" && platform === "node" ? { js: "import { createRequire as __createRequire } from \"node:module\";\nvar require = __createRequire(import.meta.url);\n" } : void 0,
|
|
68
|
+
bundle: true,
|
|
69
|
+
conditions: options.conditions,
|
|
70
|
+
entryPoints: [entryFile],
|
|
71
|
+
external: options.external,
|
|
72
|
+
format,
|
|
73
|
+
logLevel: "silent",
|
|
74
|
+
outfile,
|
|
75
|
+
platform,
|
|
76
|
+
sourcemap: false,
|
|
77
|
+
target: "es2022",
|
|
78
|
+
write: true
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region ../internal/src/build/user-entry.ts
|
|
83
|
+
function toSafeAppName(rootDir) {
|
|
84
|
+
return basename(rootDir).replace(/[^a-z0-9-]+/gi, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
|
|
85
|
+
}
|
|
86
|
+
const DEFAULT_ENTRY_NAMES = [
|
|
87
|
+
"server.ts",
|
|
88
|
+
"server.mts",
|
|
89
|
+
"server.js",
|
|
90
|
+
"server.mjs",
|
|
91
|
+
"worker.ts",
|
|
92
|
+
"worker.mts",
|
|
93
|
+
"worker.js",
|
|
94
|
+
"worker.mjs"
|
|
95
|
+
];
|
|
96
|
+
function resolveUserAppEntry(rootDir, options = {}) {
|
|
97
|
+
const names = options.names ?? DEFAULT_ENTRY_NAMES;
|
|
98
|
+
const srcSubdir = options.srcSubdir ?? "src";
|
|
99
|
+
return names.map((name) => resolve(rootDir, srcSubdir, name)).find(existsSync);
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region ../internal/src/build/vercel-config.ts
|
|
103
|
+
function createVercelConfigJson() {
|
|
104
|
+
return {
|
|
105
|
+
routes: [{ handle: "filesystem" }, {
|
|
106
|
+
src: "/(.*)",
|
|
107
|
+
dest: "/__server"
|
|
108
|
+
}],
|
|
109
|
+
version: 3
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function createNodeFunctionConfig(extra = {}) {
|
|
113
|
+
return {
|
|
114
|
+
handler: "index.mjs",
|
|
115
|
+
launcherType: "Nodejs",
|
|
116
|
+
runtime: "nodejs22.x",
|
|
117
|
+
shouldAddHelpers: false,
|
|
118
|
+
supportsResponseStreaming: true,
|
|
119
|
+
...extra
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region ../internal/src/build/deployment-output.ts
|
|
124
|
+
function resolveClientOutput(rootDir, clientOutDir) {
|
|
125
|
+
const clientDir = resolve(rootDir, clientOutDir);
|
|
126
|
+
return {
|
|
127
|
+
clientDir,
|
|
128
|
+
staticIndex: hasStaticIndex(clientDir)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
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
|
+
function createDefaultCloudflareStaticOutputDir(rootDir) {
|
|
182
|
+
return resolve(rootDir, "dist", "client");
|
|
183
|
+
}
|
|
184
|
+
function createDefaultVercelOutputRoot(rootDir) {
|
|
185
|
+
return resolve(rootDir, ".vercel", "output");
|
|
186
|
+
}
|
|
187
|
+
async function writeCloudflareDeploymentOutput(options) {
|
|
188
|
+
const { clientDir, staticIndex } = resolveClientOutput(options.rootDir, options.clientOutDir);
|
|
189
|
+
const outputRoot = options.outputRoot ?? createDefaultCloudflareOutputRoot(options.rootDir);
|
|
190
|
+
const workerOutfile = resolve(outputRoot, options.bundleOutfileName ?? "index.js");
|
|
191
|
+
await mkdir(outputRoot, { recursive: true });
|
|
192
|
+
await rm(workerOutfile, {
|
|
193
|
+
force: true,
|
|
194
|
+
recursive: true
|
|
195
|
+
});
|
|
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
|
+
}
|
|
202
|
+
async function writeVercelDeploymentOutput(options) {
|
|
203
|
+
const { clientDir, staticIndex } = resolveClientOutput(options.rootDir, options.clientOutDir);
|
|
204
|
+
const outputRoot = options.outputRoot ?? createDefaultVercelOutputRoot(options.rootDir);
|
|
205
|
+
const serverDir = resolve(outputRoot, "functions", options.serverFunctionName ?? "__server.func");
|
|
206
|
+
const serverEntry = resolve(serverDir, "index.mjs");
|
|
207
|
+
await rm(serverDir, {
|
|
208
|
+
force: true,
|
|
209
|
+
recursive: true
|
|
210
|
+
});
|
|
211
|
+
await mkdir(serverDir, { recursive: true });
|
|
212
|
+
await Promise.all([
|
|
213
|
+
bundleEsmEntry(options.bundleEntry, serverEntry, options.bundleOptions),
|
|
214
|
+
writeFile(resolve(serverDir, ".vc-config.json"), `${JSON.stringify(options.functionConfig ?? createNodeFunctionConfig(), null, 2)}\n`, "utf8"),
|
|
215
|
+
writeMergedJsonObject(resolve(outputRoot, "config.json"), options.config ?? createVercelConfigJson(), options.configKeys),
|
|
216
|
+
staticIndex ? copyClientOutput(clientDir, options.staticOutputDir ?? resolve(outputRoot, "static")) : Promise.resolve()
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
async function cleanupCloudflareDeploymentOutput(rootDir, cleanup) {
|
|
220
|
+
const outputRoot = cleanup.outputRoot ?? createDefaultCloudflareOutputRoot(rootDir);
|
|
221
|
+
const writes = [];
|
|
222
|
+
if (cleanup.bundleOutfileName) writes.push(rm(resolve(outputRoot, cleanup.bundleOutfileName), {
|
|
223
|
+
force: true,
|
|
224
|
+
recursive: true
|
|
225
|
+
}));
|
|
226
|
+
writes.push(deleteJsonObjectKeysFromFile(resolve(outputRoot, "wrangler.json"), cleanup.wranglerConfigKeys));
|
|
227
|
+
await Promise.all(writes);
|
|
228
|
+
}
|
|
229
|
+
async function cleanupVercelDeploymentOutput(rootDir, cleanup) {
|
|
230
|
+
const outputRoot = cleanup.outputRoot ?? createDefaultVercelOutputRoot(rootDir);
|
|
231
|
+
const writes = [];
|
|
232
|
+
if (cleanup.serverFunctionName) writes.push(rm(resolve(outputRoot, "functions", cleanup.serverFunctionName), {
|
|
233
|
+
force: true,
|
|
234
|
+
recursive: true
|
|
235
|
+
}));
|
|
236
|
+
writes.push(deleteJsonObjectKeysFromFile(resolve(outputRoot, "config.json"), cleanup.configKeys));
|
|
237
|
+
await Promise.all(writes);
|
|
238
|
+
}
|
|
239
|
+
async function writeProviderDeploymentOutputs(options) {
|
|
240
|
+
const writes = [];
|
|
241
|
+
if (options.cloudflare) writes.push(writeCloudflareDeploymentOutput({
|
|
242
|
+
...options.cloudflare,
|
|
243
|
+
clientOutDir: options.clientOutDir,
|
|
244
|
+
rootDir: options.rootDir
|
|
245
|
+
}));
|
|
246
|
+
else if (options.cleanup?.cloudflare) writes.push(cleanupCloudflareDeploymentOutput(options.rootDir, options.cleanup.cloudflare));
|
|
247
|
+
if (options.vercel) writes.push(writeVercelDeploymentOutput({
|
|
248
|
+
...options.vercel,
|
|
249
|
+
clientOutDir: options.clientOutDir,
|
|
250
|
+
rootDir: options.rootDir
|
|
251
|
+
}));
|
|
252
|
+
else if (options.cleanup?.vercel) writes.push(cleanupVercelDeploymentOutput(options.rootDir, options.cleanup.vercel));
|
|
253
|
+
await Promise.all(writes);
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region ../internal/src/build/vite.ts
|
|
257
|
+
function createNoExternalMerger(packageName) {
|
|
258
|
+
return (current) => {
|
|
259
|
+
if (current === true) return true;
|
|
260
|
+
if (!current) return [packageName];
|
|
261
|
+
const values = Array.isArray(current) ? current : [current];
|
|
262
|
+
return values.includes(packageName) ? values : [...values, packageName];
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function isServerEnvironment(name, config) {
|
|
266
|
+
return name === "ssr" || config.consumer === "server";
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region ../internal/src/build/cloudflare.ts
|
|
270
|
+
const defaultCloudflareCompatibilityDate = "2026-04-20";
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/internal/vite-build.ts
|
|
273
|
+
const workflowPackageName = "@vite-hub/workflow";
|
|
274
|
+
const productName = "workflow";
|
|
275
|
+
const generatedRegistryFileName = "registry.mjs";
|
|
276
|
+
const packageDir = computePackageDir(import.meta.url);
|
|
277
|
+
const resolveRuntimeModule = (modulePath) => resolveRuntimeModule$1(packageDir, modulePath);
|
|
278
|
+
const WORKFLOW_ENTRY_BASE_NAMES = [
|
|
279
|
+
"server.ts",
|
|
280
|
+
"server.mts",
|
|
281
|
+
"server.js",
|
|
282
|
+
"server.mjs",
|
|
283
|
+
"worker.ts",
|
|
284
|
+
"worker.mts",
|
|
285
|
+
"worker.js",
|
|
286
|
+
"worker.mjs"
|
|
287
|
+
];
|
|
288
|
+
const WORKFLOW_PRIORITY_NAMES = [
|
|
289
|
+
"server-workflow.ts",
|
|
290
|
+
"server-workflow.mts",
|
|
291
|
+
"server-workflow.js",
|
|
292
|
+
"server-workflow.mjs"
|
|
293
|
+
];
|
|
294
|
+
function resolveWorkflowUserAppEntry(rootDir) {
|
|
295
|
+
return resolveUserAppEntry(rootDir, { names: getViteMode() === VITEHUB_MODES.workflow ? [...WORKFLOW_PRIORITY_NAMES, ...WORKFLOW_ENTRY_BASE_NAMES] : [...WORKFLOW_ENTRY_BASE_NAMES] });
|
|
296
|
+
}
|
|
297
|
+
const providerEntrySpecs = [{
|
|
298
|
+
name: "cloudflare",
|
|
299
|
+
entryFile: "cloudflare-worker.mjs",
|
|
300
|
+
runtimeModule: "runtime/cloudflare-vite",
|
|
301
|
+
factory: "createWorkflowCloudflareWorker",
|
|
302
|
+
hosting: "cloudflare"
|
|
303
|
+
}, {
|
|
304
|
+
name: "vercel",
|
|
305
|
+
entryFile: "vercel-server.mjs",
|
|
306
|
+
runtimeModule: "runtime/vercel-vite",
|
|
307
|
+
factory: "createWorkflowVercelServer",
|
|
308
|
+
hosting: "vercel"
|
|
309
|
+
}];
|
|
310
|
+
function resolveWorkflowConfig(workflow, hosting) {
|
|
311
|
+
return normalizeWorkflowOptions(workflow, { hosting }) ?? false;
|
|
312
|
+
}
|
|
313
|
+
function renderCloudflareWorkerWrapper(definitions) {
|
|
314
|
+
return [
|
|
315
|
+
definitions.length ? `import { WorkflowEntrypoint, waitUntil as viteHubWaitUntil } from "cloudflare:workers"` : `import { waitUntil as viteHubWaitUntil } from "cloudflare:workers"`,
|
|
316
|
+
`import worker, { runViteHubWorkflowDefinition } from "./worker.mjs"`,
|
|
317
|
+
"",
|
|
318
|
+
...definitions.map((definition) => {
|
|
319
|
+
return [
|
|
320
|
+
`export class ${getCloudflareWorkflowClassName(definition.name)} extends WorkflowEntrypoint {`,
|
|
321
|
+
" async run(event, step) {",
|
|
322
|
+
` return await runViteHubWorkflowDefinition(${JSON.stringify(definition.name)}, this.env || {}, event, step)`,
|
|
323
|
+
" }",
|
|
324
|
+
"}",
|
|
325
|
+
""
|
|
326
|
+
].join("\n");
|
|
327
|
+
}),
|
|
328
|
+
"const viteHubWorker = {",
|
|
329
|
+
" async fetch(request, env, context) {",
|
|
330
|
+
" const waitUntil = typeof viteHubWaitUntil === \"function\" ? viteHubWaitUntil : context?.waitUntil?.bind(context)",
|
|
331
|
+
" return await worker.fetch(request, env, waitUntil ? { ...context, waitUntil } : context)",
|
|
332
|
+
" }",
|
|
333
|
+
"}",
|
|
334
|
+
"",
|
|
335
|
+
"export default viteHubWorker",
|
|
336
|
+
""
|
|
337
|
+
].join("\n");
|
|
338
|
+
}
|
|
339
|
+
function renderProviderEntry(spec, entryFile, userAppEntry, serializedWorkflowConfig) {
|
|
340
|
+
const imports = [`import { ${spec.factory} } from ${JSON.stringify(createImportPath(entryFile, resolveRuntimeModule(spec.runtimeModule)))}`, `import workflowRegistry from ${JSON.stringify(`./${generatedRegistryFileName}`)}`];
|
|
341
|
+
if (spec.name === "cloudflare") imports.push(`import { runCloudflareWorkflow } from ${JSON.stringify(createImportPath(entryFile, resolveRuntimeModule("runtime/cloudflare-runner")))}`);
|
|
342
|
+
if (userAppEntry) imports.push(`import workflowApp from ${JSON.stringify(createImportPath(entryFile, userAppEntry))}`);
|
|
343
|
+
const cloudflareDispatcher = spec.name === "cloudflare" ? [
|
|
344
|
+
"",
|
|
345
|
+
"export async function runViteHubWorkflowDefinition(name, env, event, step) {",
|
|
346
|
+
" return await runCloudflareWorkflow({ config: workflowConfig, env: env || {}, event, name, registry: workflowRegistry, step })",
|
|
347
|
+
"}"
|
|
348
|
+
] : [];
|
|
349
|
+
return [
|
|
350
|
+
...imports,
|
|
351
|
+
"",
|
|
352
|
+
`const workflowConfig = ${serializedWorkflowConfig}`,
|
|
353
|
+
...cloudflareDispatcher,
|
|
354
|
+
"",
|
|
355
|
+
`export default ${spec.factory}({`,
|
|
356
|
+
userAppEntry ? " app: workflowApp," : "",
|
|
357
|
+
" registry: workflowRegistry,",
|
|
358
|
+
" workflow: workflowConfig,",
|
|
359
|
+
"})",
|
|
360
|
+
""
|
|
361
|
+
].filter(Boolean).join("\n");
|
|
362
|
+
}
|
|
363
|
+
async function writeProviderEntries(rootDir, workflow) {
|
|
364
|
+
const generatedDir = ensureGeneratedDir(rootDir, productName);
|
|
365
|
+
await mkdir(generatedDir, { recursive: true });
|
|
366
|
+
const registryFile = resolve(generatedDir, generatedRegistryFileName);
|
|
367
|
+
const definitions = discoverWorkflowDefinitions({ rootDir });
|
|
368
|
+
const providerDefinitions = definitions;
|
|
369
|
+
const userAppEntry = resolveWorkflowUserAppEntry(rootDir);
|
|
370
|
+
const cloudflareWorkflowConfig = resolveWorkflowConfig(workflow, "cloudflare");
|
|
371
|
+
await writeFile(registryFile, createRuntimeRegistryContents(registryFile, definitions), "utf8");
|
|
372
|
+
const entryFiles = {
|
|
373
|
+
cloudflare: "",
|
|
374
|
+
openworkflow: "",
|
|
375
|
+
vercel: ""
|
|
376
|
+
};
|
|
377
|
+
await Promise.all(providerEntrySpecs.map(async (spec) => {
|
|
378
|
+
const entryFile = resolve(generatedDir, spec.entryFile);
|
|
379
|
+
const workflowConfig = spec.name === "cloudflare" ? cloudflareWorkflowConfig : resolveWorkflowConfig(workflow, spec.hosting);
|
|
380
|
+
await writeFile(entryFile, renderProviderEntry(spec, entryFile, userAppEntry, JSON.stringify(workflowConfig, null, 2)), "utf8");
|
|
381
|
+
entryFiles[spec.name] = entryFile;
|
|
382
|
+
}));
|
|
383
|
+
return {
|
|
384
|
+
cloudflareWorkerFile: entryFiles.cloudflare,
|
|
385
|
+
cloudflareWorkflowConfig,
|
|
386
|
+
definitions,
|
|
387
|
+
generatedDir,
|
|
388
|
+
providerDefinitions,
|
|
389
|
+
registryFile,
|
|
390
|
+
vercelServerFile: entryFiles.vercel
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function createCloudflareOutput(rootDir, artifacts) {
|
|
394
|
+
const workflowConfig = artifacts.cloudflareWorkflowConfig && artifacts.cloudflareWorkflowConfig.provider === "cloudflare" ? artifacts.cloudflareWorkflowConfig : false;
|
|
395
|
+
const workflows = createCloudflareWorkflowBindings(workflowConfig ? artifacts.providerDefinitions : [], workflowConfig);
|
|
396
|
+
const wranglerConfig = {
|
|
397
|
+
compatibility_date: defaultCloudflareCompatibilityDate,
|
|
398
|
+
compatibility_flags: ["nodejs_compat"],
|
|
399
|
+
main: "index.js",
|
|
400
|
+
observability: { enabled: true },
|
|
401
|
+
...workflows ? { workflows } : {}
|
|
402
|
+
};
|
|
403
|
+
return {
|
|
404
|
+
bundleEntry: artifacts.cloudflareWorkerFile,
|
|
405
|
+
bundleOptions: {
|
|
406
|
+
conditions: [
|
|
407
|
+
"workerd",
|
|
408
|
+
"worker",
|
|
409
|
+
"browser",
|
|
410
|
+
"default"
|
|
411
|
+
],
|
|
412
|
+
external: [
|
|
413
|
+
"@cloudflare/sandbox",
|
|
414
|
+
"@vercel/blob",
|
|
415
|
+
"@vercel/functions",
|
|
416
|
+
"@vercel/queue",
|
|
417
|
+
"@vercel/sandbox",
|
|
418
|
+
"cloudflare:workers",
|
|
419
|
+
"node:async_hooks",
|
|
420
|
+
"workflow",
|
|
421
|
+
"workflow/api",
|
|
422
|
+
"workflow/runtime"
|
|
423
|
+
],
|
|
424
|
+
format: "esm",
|
|
425
|
+
platform: "neutral"
|
|
426
|
+
},
|
|
427
|
+
bundleOutfileName: "worker.mjs",
|
|
428
|
+
outputRoot: createDefaultCloudflareOutputRoot(rootDir),
|
|
429
|
+
wranglerConfigKeys: ["workflows"],
|
|
430
|
+
wranglerConfig
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
async function writeCloudflareWorkflowWrapper(rootDir, artifacts) {
|
|
434
|
+
const outputRoot = createDefaultCloudflareOutputRoot(rootDir);
|
|
435
|
+
const workflowDefinitions = (artifacts.cloudflareWorkflowConfig && artifacts.cloudflareWorkflowConfig.provider === "cloudflare" ? artifacts.cloudflareWorkflowConfig : false) ? artifacts.providerDefinitions : [];
|
|
436
|
+
await writeFile(resolve(outputRoot, "index.js"), renderCloudflareWorkerWrapper(workflowDefinitions), "utf8");
|
|
437
|
+
}
|
|
438
|
+
function createVercelOutput(artifacts) {
|
|
439
|
+
return {
|
|
440
|
+
bundleEntry: artifacts.vercelServerFile,
|
|
441
|
+
bundleOptions: {
|
|
442
|
+
external: [
|
|
443
|
+
"@cloudflare/sandbox",
|
|
444
|
+
"cloudflare:workers",
|
|
445
|
+
"workflow",
|
|
446
|
+
"workflow/api",
|
|
447
|
+
"workflow/runtime"
|
|
448
|
+
],
|
|
449
|
+
format: "esm",
|
|
450
|
+
platform: "node"
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
async function generateProviderOutputs(options) {
|
|
455
|
+
const artifacts = await writeProviderEntries(options.rootDir, options.workflow);
|
|
456
|
+
const cloudflareWorkflowConfig = resolveWorkflowConfig(options.workflow, "cloudflare");
|
|
457
|
+
const vercelWorkflowConfig = resolveWorkflowConfig(options.workflow, "vercel");
|
|
458
|
+
await writeProviderDeploymentOutputs({
|
|
459
|
+
clientOutDir: options.clientOutDir,
|
|
460
|
+
...cloudflareWorkflowConfig && cloudflareWorkflowConfig.provider === "cloudflare" ? { cloudflare: createCloudflareOutput(options.rootDir, artifacts) } : {},
|
|
461
|
+
cleanup: { cloudflare: {
|
|
462
|
+
bundleOutfileName: "worker.mjs",
|
|
463
|
+
outputRoot: createDefaultCloudflareOutputRoot(options.rootDir),
|
|
464
|
+
wranglerConfigKeys: ["workflows"]
|
|
465
|
+
} },
|
|
466
|
+
rootDir: options.rootDir,
|
|
467
|
+
...vercelWorkflowConfig && vercelWorkflowConfig.provider === "vercel" ? { vercel: createVercelOutput(artifacts) } : {}
|
|
468
|
+
});
|
|
469
|
+
if (cloudflareWorkflowConfig && cloudflareWorkflowConfig.provider === "cloudflare") await writeCloudflareWorkflowWrapper(options.rootDir, artifacts);
|
|
470
|
+
return artifacts;
|
|
471
|
+
}
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/vite.ts
|
|
474
|
+
const mergeNoExternal = createNoExternalMerger(workflowPackageName);
|
|
475
|
+
function hubWorkflow(options) {
|
|
476
|
+
let resolved;
|
|
477
|
+
let workflow = options;
|
|
478
|
+
return {
|
|
479
|
+
name: "@vite-hub/workflow/vite",
|
|
480
|
+
nitro: workflowNitroModule,
|
|
481
|
+
config(config) {
|
|
482
|
+
workflow = config.workflow ?? workflow;
|
|
483
|
+
},
|
|
484
|
+
configResolved(config) {
|
|
485
|
+
resolved = config;
|
|
486
|
+
workflow = config.workflow ?? workflow;
|
|
487
|
+
},
|
|
488
|
+
configEnvironment(name, config) {
|
|
489
|
+
if (!isServerEnvironment(name, config)) return;
|
|
490
|
+
return { resolve: { noExternal: mergeNoExternal(config.resolve?.noExternal) } };
|
|
491
|
+
},
|
|
492
|
+
async closeBundle() {
|
|
493
|
+
if (!resolved || shouldSkipViteProviderBuild(resolved.command, getViteMode())) return;
|
|
494
|
+
await generateProviderOutputs({
|
|
495
|
+
clientOutDir: resolved.build.outDir,
|
|
496
|
+
rootDir: resolved.root,
|
|
497
|
+
workflow
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
//#endregion
|
|
503
|
+
export { hubWorkflow };
|