@vibesdotdev/infra-deploy 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 +125 -0
- package/SPEC.md +181 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.descriptor.d.ts +39 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.descriptor.js +61 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.descriptor.js.map +1 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.impl.d.ts +13 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.impl.js +109 -0
- package/dist/cli/alerts/infra-alerts-create.cli-command.impl.js.map +1 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.descriptor.d.ts +31 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.descriptor.js +36 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.descriptor.js.map +1 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.impl.d.ts +11 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.impl.js +67 -0
- package/dist/cli/alerts/infra-alerts-delete.cli-command.impl.js.map +1 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.descriptor.d.ts +21 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.descriptor.js +27 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.descriptor.js.map +1 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.impl.d.ts +12 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.impl.js +74 -0
- package/dist/cli/alerts/infra-alerts-list.cli-command.impl.js.map +1 -0
- package/dist/cli/alerts/infra-alerts.cli-group.descriptor.d.ts +12 -0
- package/dist/cli/alerts/infra-alerts.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/alerts/infra-alerts.cli-group.descriptor.js +12 -0
- package/dist/cli/alerts/infra-alerts.cli-group.descriptor.js.map +1 -0
- package/dist/cli/audit/infra-audit.cli-command.descriptor.d.ts +21 -0
- package/dist/cli/audit/infra-audit.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/audit/infra-audit.cli-command.descriptor.js +28 -0
- package/dist/cli/audit/infra-audit.cli-command.descriptor.js.map +1 -0
- package/dist/cli/audit/infra-audit.cli-command.impl.d.ts +18 -0
- package/dist/cli/audit/infra-audit.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/audit/infra-audit.cli-command.impl.js +219 -0
- package/dist/cli/audit/infra-audit.cli-command.impl.js.map +1 -0
- package/dist/cli/infra-deploy.cli-group.descriptor.d.ts +12 -0
- package/dist/cli/infra-deploy.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/infra-deploy.cli-group.descriptor.js +12 -0
- package/dist/cli/infra-deploy.cli-group.descriptor.js.map +1 -0
- package/dist/cli/infra.cli-group.descriptor.d.ts +11 -0
- package/dist/cli/infra.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/infra.cli-group.descriptor.js +11 -0
- package/dist/cli/infra.cli-group.descriptor.js.map +1 -0
- package/dist/cli/list/infra-deploy.list.cli-command.descriptor.d.ts +34 -0
- package/dist/cli/list/infra-deploy.list.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/list/infra-deploy.list.cli-command.descriptor.js +29 -0
- package/dist/cli/list/infra-deploy.list.cli-command.descriptor.js.map +1 -0
- package/dist/cli/list/infra-deploy.list.cli-command.impl.d.ts +5 -0
- package/dist/cli/list/infra-deploy.list.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/list/infra-deploy.list.cli-command.impl.js +110 -0
- package/dist/cli/list/infra-deploy.list.cli-command.impl.js.map +1 -0
- package/dist/cli/logs/infra-logs.cli-command.descriptor.d.ts +39 -0
- package/dist/cli/logs/infra-logs.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/logs/infra-logs.cli-command.descriptor.js +64 -0
- package/dist/cli/logs/infra-logs.cli-command.descriptor.js.map +1 -0
- package/dist/cli/logs/infra-logs.cli-command.impl.d.ts +5 -0
- package/dist/cli/logs/infra-logs.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/logs/infra-logs.cli-command.impl.js +323 -0
- package/dist/cli/logs/infra-logs.cli-command.impl.js.map +1 -0
- package/dist/cli/logs/stream-worker-tail.d.ts +62 -0
- package/dist/cli/logs/stream-worker-tail.d.ts.map +1 -0
- package/dist/cli/logs/stream-worker-tail.js +165 -0
- package/dist/cli/logs/stream-worker-tail.js.map +1 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.descriptor.d.ts +27 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.descriptor.js +75 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.descriptor.js.map +1 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.impl.d.ts +5 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.impl.js +383 -0
- package/dist/cli/npm/infra-npm-publish.cli-command.impl.js.map +1 -0
- package/dist/cli/npm/infra-npm.cli-group.descriptor.d.ts +12 -0
- package/dist/cli/npm/infra-npm.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/npm/infra-npm.cli-group.descriptor.js +12 -0
- package/dist/cli/npm/infra-npm.cli-group.descriptor.js.map +1 -0
- package/dist/cli/observability/infra-observability-set.cli-command.descriptor.d.ts +25 -0
- package/dist/cli/observability/infra-observability-set.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/observability/infra-observability-set.cli-command.descriptor.js +57 -0
- package/dist/cli/observability/infra-observability-set.cli-command.descriptor.js.map +1 -0
- package/dist/cli/observability/infra-observability-set.cli-command.impl.d.ts +17 -0
- package/dist/cli/observability/infra-observability-set.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/observability/infra-observability-set.cli-command.impl.js +152 -0
- package/dist/cli/observability/infra-observability-set.cli-command.impl.js.map +1 -0
- package/dist/cli/observability/infra-observability-status.cli-command.descriptor.d.ts +21 -0
- package/dist/cli/observability/infra-observability-status.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/observability/infra-observability-status.cli-command.descriptor.js +35 -0
- package/dist/cli/observability/infra-observability-status.cli-command.descriptor.js.map +1 -0
- package/dist/cli/observability/infra-observability-status.cli-command.impl.d.ts +17 -0
- package/dist/cli/observability/infra-observability-status.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/observability/infra-observability-status.cli-command.impl.js +99 -0
- package/dist/cli/observability/infra-observability-status.cli-command.impl.js.map +1 -0
- package/dist/cli/observability/infra-observability.cli-group.descriptor.d.ts +12 -0
- package/dist/cli/observability/infra-observability.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/observability/infra-observability.cli-group.descriptor.js +12 -0
- package/dist/cli/observability/infra-observability.cli-group.descriptor.js.map +1 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.descriptor.d.ts +27 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.descriptor.js +35 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.descriptor.js.map +1 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.impl.d.ts +5 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.impl.js +99 -0
- package/dist/cli/regenerate/infra-deploy.regenerate.cli-command.impl.js.map +1 -0
- package/dist/cli/rum/infra-rum-status.cli-command.descriptor.d.ts +21 -0
- package/dist/cli/rum/infra-rum-status.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/rum/infra-rum-status.cli-command.descriptor.js +27 -0
- package/dist/cli/rum/infra-rum-status.cli-command.descriptor.js.map +1 -0
- package/dist/cli/rum/infra-rum-status.cli-command.impl.d.ts +12 -0
- package/dist/cli/rum/infra-rum-status.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/rum/infra-rum-status.cli-command.impl.js +88 -0
- package/dist/cli/rum/infra-rum-status.cli-command.impl.js.map +1 -0
- package/dist/cli/rum/infra-rum.cli-group.descriptor.d.ts +12 -0
- package/dist/cli/rum/infra-rum.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/rum/infra-rum.cli-group.descriptor.js +12 -0
- package/dist/cli/rum/infra-rum.cli-group.descriptor.js.map +1 -0
- package/dist/cli/run/infra-deploy.run.cli-command.descriptor.d.ts +27 -0
- package/dist/cli/run/infra-deploy.run.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/run/infra-deploy.run.cli-command.descriptor.js +49 -0
- package/dist/cli/run/infra-deploy.run.cli-command.descriptor.js.map +1 -0
- package/dist/cli/run/infra-deploy.run.cli-command.impl.d.ts +5 -0
- package/dist/cli/run/infra-deploy.run.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/run/infra-deploy.run.cli-command.impl.js +272 -0
- package/dist/cli/run/infra-deploy.run.cli-command.impl.js.map +1 -0
- package/dist/cli/shared/discover-deployments.d.ts +41 -0
- package/dist/cli/shared/discover-deployments.d.ts.map +1 -0
- package/dist/cli/shared/discover-deployments.js +95 -0
- package/dist/cli/shared/discover-deployments.js.map +1 -0
- package/dist/config-loader.d.ts +24 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +135 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/infra-deploy.plugin.d.ts +3 -0
- package/dist/infra-deploy.plugin.d.ts.map +1 -0
- package/dist/infra-deploy.plugin.js +59 -0
- package/dist/infra-deploy.plugin.js.map +1 -0
- package/dist/regenerate.d.ts +55 -0
- package/dist/regenerate.d.ts.map +1 -0
- package/dist/regenerate.js +206 -0
- package/dist/regenerate.js.map +1 -0
- package/package.json +85 -0
- package/src/cli/alerts/infra-alerts-create.cli-command.descriptor.ts +61 -0
- package/src/cli/alerts/infra-alerts-create.cli-command.impl.ts +131 -0
- package/src/cli/alerts/infra-alerts-delete.cli-command.descriptor.ts +36 -0
- package/src/cli/alerts/infra-alerts-delete.cli-command.impl.ts +75 -0
- package/src/cli/alerts/infra-alerts-list.cli-command.descriptor.ts +27 -0
- package/src/cli/alerts/infra-alerts-list.cli-command.impl.ts +88 -0
- package/src/cli/alerts/infra-alerts.cli-group.descriptor.ts +12 -0
- package/src/cli/audit/infra-audit.cli-command.descriptor.ts +28 -0
- package/src/cli/audit/infra-audit.cli-command.impl.ts +293 -0
- package/src/cli/infra-deploy.cli-group.descriptor.ts +12 -0
- package/src/cli/infra.cli-group.descriptor.ts +11 -0
- package/src/cli/list/infra-deploy.list.cli-command.descriptor.ts +29 -0
- package/src/cli/list/infra-deploy.list.cli-command.impl.ts +125 -0
- package/src/cli/logs/infra-logs.cli-command.descriptor.ts +65 -0
- package/src/cli/logs/infra-logs.cli-command.impl.ts +354 -0
- package/src/cli/logs/stream-worker-tail.ts +202 -0
- package/src/cli/npm/infra-npm-publish.cli-command.descriptor.ts +75 -0
- package/src/cli/npm/infra-npm-publish.cli-command.impl.ts +474 -0
- package/src/cli/npm/infra-npm.cli-group.descriptor.ts +12 -0
- package/src/cli/observability/infra-observability-set.cli-command.descriptor.ts +57 -0
- package/src/cli/observability/infra-observability-set.cli-command.impl.ts +173 -0
- package/src/cli/observability/infra-observability-status.cli-command.descriptor.ts +35 -0
- package/src/cli/observability/infra-observability-status.cli-command.impl.ts +124 -0
- package/src/cli/observability/infra-observability.cli-group.descriptor.ts +12 -0
- package/src/cli/regenerate/infra-deploy.regenerate.cli-command.descriptor.ts +36 -0
- package/src/cli/regenerate/infra-deploy.regenerate.cli-command.impl.ts +103 -0
- package/src/cli/rum/infra-rum-status.cli-command.descriptor.ts +27 -0
- package/src/cli/rum/infra-rum-status.cli-command.impl.ts +112 -0
- package/src/cli/rum/infra-rum.cli-group.descriptor.ts +12 -0
- package/src/cli/run/infra-deploy.run.cli-command.descriptor.ts +49 -0
- package/src/cli/run/infra-deploy.run.cli-command.impl.ts +330 -0
- package/src/cli/shared/discover-deployments.ts +127 -0
- package/src/config-loader.ts +179 -0
- package/src/index.ts +11 -0
- package/src/infra-deploy.plugin.ts +83 -0
- package/src/regenerate.ts +230 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { getVibesRuntime } from '@vibesdotdev/runtime';
|
|
2
|
+
import type { UIContext } from '@vibesdotdev/cli/providers';
|
|
3
|
+
import { resolveCurrentEnvironmentConfig } from '@vibesdotdev/config/environment/current';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { getCloudflareWorkersDeployClient } from '@vibesdotdev/connector-cloudflare/client';
|
|
7
|
+
import { getDigitalOceanAppDeployClient } from '@vibesdotdev/infra-doks/client';
|
|
8
|
+
import { loadDeploymentConfig } from '../../config-loader.ts';
|
|
9
|
+
import { regenerateApp } from '../../regenerate.ts';
|
|
10
|
+
|
|
11
|
+
function readString(v: unknown): string | undefined {
|
|
12
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
13
|
+
}
|
|
14
|
+
function readBoolean(v: unknown): boolean {
|
|
15
|
+
return v === true || v === 'true';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function resolveWorkspaceRoot(
|
|
19
|
+
workspaceRootDir: string | undefined,
|
|
20
|
+
appDir: string,
|
|
21
|
+
override: string | undefined
|
|
22
|
+
): string {
|
|
23
|
+
if (override) return resolve(override);
|
|
24
|
+
if (!workspaceRootDir || workspaceRootDir === '.') return process.cwd();
|
|
25
|
+
return resolve(appDir, workspaceRootDir);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const CLOUDFLARE_API_TOKEN_KEY = 'CLOUDFLARE_API_TOKEN';
|
|
29
|
+
const CLOUDFLARE_ACCOUNT_ID_KEY = 'CLOUDFLARE_ACCOUNT_ID';
|
|
30
|
+
|
|
31
|
+
async function resolveCloudflareEnvFromSecretsStore(
|
|
32
|
+
runtime: ReturnType<typeof getVibesRuntime>,
|
|
33
|
+
ui: UIContext,
|
|
34
|
+
environmentOverride?: string
|
|
35
|
+
): Promise<Record<string, string>> {
|
|
36
|
+
if (process.env.CLOUDFLARE_API_TOKEN && process.env.CLOUDFLARE_ACCOUNT_ID) {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
if (!runtime.hasKind('secrets/store')) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Missing secrets/store kind in runtime. Enable secrets backends via plugin config ` +
|
|
42
|
+
`(for example plugins.auth.secrets=true and plugins.auth.secretsBackends.*) before running deploy.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let envName = environmentOverride ?? 'local';
|
|
47
|
+
let envTier = 'local';
|
|
48
|
+
if (environmentOverride) {
|
|
49
|
+
envTier = environmentOverride;
|
|
50
|
+
} else {
|
|
51
|
+
try {
|
|
52
|
+
const envConfig = await resolveCurrentEnvironmentConfig();
|
|
53
|
+
envName = envConfig.name;
|
|
54
|
+
envTier = envConfig.tier ?? 'local';
|
|
55
|
+
} catch {
|
|
56
|
+
// Fall back to local when config environment resolution is unavailable.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const descriptors = runtime.assets('secrets/store').descriptors() as Array<{
|
|
61
|
+
id: string;
|
|
62
|
+
priority?: number;
|
|
63
|
+
tiers?: string[];
|
|
64
|
+
}>;
|
|
65
|
+
const tierCandidates = new Set([envTier]);
|
|
66
|
+
if (envTier === 'local' || envTier === 'dev') {
|
|
67
|
+
// Deploy auth is often run from local shells while credentials live in
|
|
68
|
+
// staging/production backends (Vault/Cloudflare). Include those tiers as
|
|
69
|
+
// fallbacks instead of hard-filtering them out.
|
|
70
|
+
tierCandidates.add('staging');
|
|
71
|
+
tierCandidates.add('production');
|
|
72
|
+
}
|
|
73
|
+
const candidates = descriptors
|
|
74
|
+
.filter((d) => {
|
|
75
|
+
if (environmentOverride) return true;
|
|
76
|
+
if (!d.tiers || d.tiers.length === 0) return true;
|
|
77
|
+
return d.tiers.some((tier) => tierCandidates.has(tier));
|
|
78
|
+
})
|
|
79
|
+
.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
80
|
+
|
|
81
|
+
const out: Record<string, string> = {};
|
|
82
|
+
for (const descriptor of candidates) {
|
|
83
|
+
const store = (await runtime
|
|
84
|
+
.query('secrets/store')
|
|
85
|
+
.withId(descriptor.id)
|
|
86
|
+
.resolve()) as {
|
|
87
|
+
get(environment: string, key: string): Promise<string | undefined>;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (!process.env.CLOUDFLARE_API_TOKEN && !out.CLOUDFLARE_API_TOKEN) {
|
|
91
|
+
const value = await store.get(envName, CLOUDFLARE_API_TOKEN_KEY);
|
|
92
|
+
if (value && value.length > 0) {
|
|
93
|
+
out.CLOUDFLARE_API_TOKEN = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!process.env.CLOUDFLARE_ACCOUNT_ID && !out.CLOUDFLARE_ACCOUNT_ID) {
|
|
98
|
+
const value = await store.get(envName, CLOUDFLARE_ACCOUNT_ID_KEY);
|
|
99
|
+
if (value && value.length > 0) {
|
|
100
|
+
out.CLOUDFLARE_ACCOUNT_ID = value;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (out.CLOUDFLARE_API_TOKEN && out.CLOUDFLARE_ACCOUNT_ID) break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (Object.keys(out).length > 0) {
|
|
108
|
+
ui.info(
|
|
109
|
+
`Resolved Cloudflare deploy credentials from secrets store (${envName}/${envTier}).`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export default {
|
|
116
|
+
async execute(args: Record<string, unknown>, opts: Record<string, unknown>): Promise<void> {
|
|
117
|
+
const runtime = getVibesRuntime();
|
|
118
|
+
const ui = (await runtime.context('cli/ui')) as UIContext;
|
|
119
|
+
|
|
120
|
+
const pathArg = readString(args.path) ?? process.cwd();
|
|
121
|
+
const output = readString(opts.output) ?? 'text';
|
|
122
|
+
const skipBuild = readBoolean(opts.skipBuild);
|
|
123
|
+
const skipD1Migrations = readBoolean(opts.skipD1Migrations);
|
|
124
|
+
const dryRun = readBoolean(opts.dryRun);
|
|
125
|
+
const workspaceRootOverride = readString(opts.workspaceRoot);
|
|
126
|
+
const targetEnvironment = readString(opts.environment);
|
|
127
|
+
let loaded;
|
|
128
|
+
try {
|
|
129
|
+
loaded = await loadDeploymentConfig(pathArg);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
ui.error(`Failed to load deployment config: ${(err as Error).message}`);
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const { deployment, provider, appDir } = loaded;
|
|
137
|
+
if (output === 'text') {
|
|
138
|
+
ui.info(`Deploying ${deployment.appName} (${deployment.appId}) via ${provider}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const onLine = (_stream: 'stdout' | 'stderr', line: string) => {
|
|
142
|
+
if (output === 'text') ui.log(line);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
switch (provider) {
|
|
147
|
+
case 'cloudflare-workers': {
|
|
148
|
+
const environment = readString(opts.wranglerEnv);
|
|
149
|
+
const workspaceRoot = resolveWorkspaceRoot(
|
|
150
|
+
deployment.build.workspaceRootDir,
|
|
151
|
+
appDir,
|
|
152
|
+
workspaceRootOverride
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Run generic pre-deploy commands (provider-agnostic hooks)
|
|
156
|
+
if (deployment.preDeployCommands.length > 0) {
|
|
157
|
+
onLine('stdout', `Running ${deployment.preDeployCommands.length} pre-deploy command(s)...`);
|
|
158
|
+
for (const cmd of deployment.preDeployCommands) {
|
|
159
|
+
if (cmd.description) {
|
|
160
|
+
onLine('stdout', ` ${cmd.description}`);
|
|
161
|
+
}
|
|
162
|
+
if (dryRun) {
|
|
163
|
+
onLine('stdout', ` [dry-run] ${cmd.command}`);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const [bin, ...args] = cmd.command.split(' ').filter(Boolean);
|
|
167
|
+
if (!bin) continue;
|
|
168
|
+
const child = spawnSync(bin, args, {
|
|
169
|
+
cwd: appDir,
|
|
170
|
+
stdio: 'inherit',
|
|
171
|
+
env: process.env
|
|
172
|
+
});
|
|
173
|
+
if (child.status !== 0) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`Pre-deploy command failed: ${cmd.command} (exit=${child.status ?? child.error?.message ?? 'unknown'})`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
onLine('stdout', 'Pre-deploy commands complete.');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Regen gate: refuse to deploy a stale wrangler.jsonc. For apps with
|
|
183
|
+
// `managed: true` in deployment.config.ts, this enforces that what's
|
|
184
|
+
// on disk matches what the typed config would produce. Unmanaged apps
|
|
185
|
+
// pass through (the gate is opt-in until every app is migrated).
|
|
186
|
+
const regen = await regenerateApp(appDir, { mode: 'check' });
|
|
187
|
+
if (regen.status === 'drift') {
|
|
188
|
+
const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
189
|
+
const isKvIdDrift =
|
|
190
|
+
regen.diff &&
|
|
191
|
+
/^[\+\-]\s+"id":\s*"[^"]*"/m.test(regen.diff) &&
|
|
192
|
+
!uuidRe.test(regen.diff.replace(/"id":\s*"([^"]*)"/g, '$1').slice(0, 36));
|
|
193
|
+
if (!isKvIdDrift) {
|
|
194
|
+
const detail = regen.diff ? `\n${regen.diff}` : '';
|
|
195
|
+
throw new Error(
|
|
196
|
+
`wrangler.jsonc drift for ${regen.appId} — regenerate before deploy (run \`vibes infra deploy regenerate ${appDir}\`)${detail}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
onLine('stdout', `[regen] wrangler.jsonc verified (unchanged — kv namespace IDs resolved)`);
|
|
200
|
+
}
|
|
201
|
+
if (regen.status === 'error') {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`regenerate check failed for ${appDir}: ${regen.reason ?? 'unknown error'}`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
if (regen.status === 'updated' || regen.status === 'unchanged') {
|
|
207
|
+
onLine('stdout', `[regen] wrangler.jsonc verified (${regen.status})`);
|
|
208
|
+
} else if (regen.status === 'skipped') {
|
|
209
|
+
onLine('stdout', `[regen] skipped: ${regen.reason ?? 'not managed'}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const client = await getCloudflareWorkersDeployClient();
|
|
213
|
+
const envOverrides = await resolveCloudflareEnvFromSecretsStore(
|
|
214
|
+
runtime,
|
|
215
|
+
ui,
|
|
216
|
+
targetEnvironment
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// Provisioning for KV, D1, R2 is now always attempted when declared
|
|
220
|
+
// (creation + ID reconciliation happens in the client using REST API).
|
|
221
|
+
// Migrations remain opt-in via autoMigrateD1 for safety.
|
|
222
|
+
const rawConfig = loaded.raw as Record<string, unknown>;
|
|
223
|
+
const autoMigrateD1 = rawConfig.autoMigrateD1 === true && !skipD1Migrations;
|
|
224
|
+
if (skipD1Migrations) {
|
|
225
|
+
onLine('stdout', 'Skipping D1 migrations for this deploy.');
|
|
226
|
+
}
|
|
227
|
+
const generatedWranglerConfig =
|
|
228
|
+
typeof rawConfig.generateWranglerConfig === 'function'
|
|
229
|
+
? (rawConfig.generateWranglerConfig() as Record<string, unknown>)
|
|
230
|
+
: loaded.wranglerJsoncString
|
|
231
|
+
? (JSON.parse(
|
|
232
|
+
loaded.wranglerJsoncString.replace(/^\s*\/\/.*$/gm, '')
|
|
233
|
+
) as Record<string, unknown>)
|
|
234
|
+
: rawConfig;
|
|
235
|
+
|
|
236
|
+
const d1Databases =
|
|
237
|
+
((rawConfig.d1Databases ??
|
|
238
|
+
rawConfig.d1_databases ??
|
|
239
|
+
generatedWranglerConfig.d1Databases ??
|
|
240
|
+
generatedWranglerConfig.d1_databases) as
|
|
241
|
+
| Array<{ binding: string; database_name: string; migrations_dir?: string }>
|
|
242
|
+
| undefined) ?? undefined;
|
|
243
|
+
|
|
244
|
+
const r2Buckets = (rawConfig.r2_buckets as
|
|
245
|
+
| Array<{ binding?: string; bucket_name: string }>
|
|
246
|
+
| undefined) ?? undefined;
|
|
247
|
+
|
|
248
|
+
const result = await client.deployWorker({
|
|
249
|
+
appDir,
|
|
250
|
+
workspaceRoot,
|
|
251
|
+
workerName: deployment.appId,
|
|
252
|
+
buildCommand: deployment.build.buildCommand,
|
|
253
|
+
skipBuild,
|
|
254
|
+
dryRun,
|
|
255
|
+
environment,
|
|
256
|
+
envOverrides,
|
|
257
|
+
kvNamespaces: (deployment as Record<string, unknown>).kvNamespaces as
|
|
258
|
+
| Array<{ binding: string; id: string; preview_id?: string }>
|
|
259
|
+
| undefined,
|
|
260
|
+
d1Databases: autoMigrateD1 ? d1Databases : undefined,
|
|
261
|
+
r2Buckets,
|
|
262
|
+
onLine
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (output === 'json') {
|
|
266
|
+
ui.json({
|
|
267
|
+
ok: true,
|
|
268
|
+
provider: 'cloudflare-workers',
|
|
269
|
+
workerName: result.workerName,
|
|
270
|
+
deployedUrl: result.deployedUrl
|
|
271
|
+
});
|
|
272
|
+
} else if (!dryRun) {
|
|
273
|
+
ui.success(
|
|
274
|
+
result.deployedUrl
|
|
275
|
+
? `Deployed Worker ${result.workerName} at ${result.deployedUrl}`
|
|
276
|
+
: `Deployed Worker ${result.workerName}`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
case 'digitalocean-app': {
|
|
282
|
+
const doAppId = readString(opts.doAppId);
|
|
283
|
+
const doRegion = readString(opts.doRegion);
|
|
284
|
+
const doGitRepo = readString(opts.doGitRepo);
|
|
285
|
+
const doGitBranch = readString(opts.doGitBranch);
|
|
286
|
+
|
|
287
|
+
const client = await getDigitalOceanAppDeployClient();
|
|
288
|
+
const result = await client.deployApp({
|
|
289
|
+
deployment,
|
|
290
|
+
appId: doAppId,
|
|
291
|
+
region: doRegion,
|
|
292
|
+
git: doGitRepo ? { repoCloneUrl: doGitRepo, branch: doGitBranch ?? 'main' } : undefined,
|
|
293
|
+
dryRun,
|
|
294
|
+
onLine
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
if (output === 'json') {
|
|
298
|
+
ui.json({
|
|
299
|
+
ok: true,
|
|
300
|
+
provider: 'digitalocean-app',
|
|
301
|
+
appId: result.appId,
|
|
302
|
+
liveUrl: result.liveUrl
|
|
303
|
+
});
|
|
304
|
+
} else if (!dryRun) {
|
|
305
|
+
ui.success(
|
|
306
|
+
result.liveUrl
|
|
307
|
+
? `Deployed DO App ${result.appId} at ${result.liveUrl}`
|
|
308
|
+
: `Deployed DO App ${result.appId}`
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
default: {
|
|
314
|
+
ui.error(`Unsupported provider: ${provider}`);
|
|
315
|
+
ui.info('Supported providers: cloudflare-workers, digitalocean-app');
|
|
316
|
+
process.exitCode = 1;
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} catch (err) {
|
|
321
|
+
const message = (err as Error).message;
|
|
322
|
+
if (output === 'json') {
|
|
323
|
+
ui.json({ ok: false, error: message });
|
|
324
|
+
} else {
|
|
325
|
+
ui.error(message);
|
|
326
|
+
}
|
|
327
|
+
process.exitCode = 1;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover deployed apps in a workspace by scanning for `deployment.config.ts`
|
|
3
|
+
* files. Used by infra CLI commands that need the live inventory of deployed
|
|
4
|
+
* workers/sites without hardcoding app names in framework packages.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
8
|
+
import { join, isAbsolute, resolve } from 'node:path';
|
|
9
|
+
import type { DeploymentDependency } from '@vibesdotdev/infra-core/deployment';
|
|
10
|
+
import { loadDeploymentConfig } from '../../config-loader.ts';
|
|
11
|
+
|
|
12
|
+
const CONFIG_NAMES = new Set([
|
|
13
|
+
'deployment.config.ts',
|
|
14
|
+
'deployment.config.js',
|
|
15
|
+
'deployment.config.mjs'
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const IGNORED_DIRS = new Set([
|
|
19
|
+
'node_modules',
|
|
20
|
+
'.git',
|
|
21
|
+
'.svelte-kit',
|
|
22
|
+
'dist',
|
|
23
|
+
'.next',
|
|
24
|
+
'.turbo',
|
|
25
|
+
'.vite',
|
|
26
|
+
'.wrangler'
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
export interface DiscoveredDeployment {
|
|
30
|
+
appId: string;
|
|
31
|
+
appName: string;
|
|
32
|
+
provider: string;
|
|
33
|
+
appDir: string;
|
|
34
|
+
workerName: string | null;
|
|
35
|
+
dependsOn: DeploymentDependency[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface DiscoverErrorInfo {
|
|
39
|
+
configPath: string;
|
|
40
|
+
appDir: string;
|
|
41
|
+
error: Error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DiscoverOptions {
|
|
45
|
+
/** Root to scan. Absolute, or relative to cwd. Defaults to cwd. */
|
|
46
|
+
root?: string;
|
|
47
|
+
/** Max directory depth. Defaults to 4. */
|
|
48
|
+
maxDepth?: number;
|
|
49
|
+
/** When set, only return deployments whose provider matches. */
|
|
50
|
+
provider?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Invoked once per config that fails to load. The default behavior is to
|
|
53
|
+
* silently skip — `vibes infra deploy list` overrides this to surface
|
|
54
|
+
* unparseable rows.
|
|
55
|
+
*/
|
|
56
|
+
onError?: (info: DiscoverErrorInfo) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function findConfigs(root: string, maxDepth: number): Promise<string[]> {
|
|
60
|
+
const found: string[] = [];
|
|
61
|
+
async function walk(dir: string, depth: number): Promise<void> {
|
|
62
|
+
if (depth > maxDepth) return;
|
|
63
|
+
let entries: string[];
|
|
64
|
+
try {
|
|
65
|
+
entries = await readdir(dir);
|
|
66
|
+
} catch {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
if (CONFIG_NAMES.has(entry)) found.push(join(dir, entry));
|
|
71
|
+
}
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
if (IGNORED_DIRS.has(entry) || entry.startsWith('.')) continue;
|
|
74
|
+
const full = join(dir, entry);
|
|
75
|
+
let info;
|
|
76
|
+
try {
|
|
77
|
+
info = await stat(full);
|
|
78
|
+
} catch {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (info.isDirectory()) await walk(full, depth + 1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
await walk(root, 0);
|
|
85
|
+
return found;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Scan `root` for every `deployment.config.ts` and return the loaded
|
|
90
|
+
* deployment descriptors. Configs that fail to load are skipped; pass
|
|
91
|
+
* `onError` to be notified about each failure (e.g. to render
|
|
92
|
+
* `(unparseable)` rows in the list command).
|
|
93
|
+
*/
|
|
94
|
+
export async function discoverDeployments(
|
|
95
|
+
opts: DiscoverOptions = {}
|
|
96
|
+
): Promise<DiscoveredDeployment[]> {
|
|
97
|
+
const rootInput = opts.root ?? process.cwd();
|
|
98
|
+
const root = isAbsolute(rootInput) ? rootInput : resolve(process.cwd(), rootInput);
|
|
99
|
+
const maxDepth = opts.maxDepth ?? 4;
|
|
100
|
+
|
|
101
|
+
const configPaths = await findConfigs(root, maxDepth);
|
|
102
|
+
const results: DiscoveredDeployment[] = [];
|
|
103
|
+
|
|
104
|
+
for (const configPath of configPaths) {
|
|
105
|
+
const appDir = configPath.replace(/\/deployment\.config\.(ts|js|mjs)$/, '');
|
|
106
|
+
try {
|
|
107
|
+
const loaded = await loadDeploymentConfig(appDir);
|
|
108
|
+
if (opts.provider && loaded.provider !== opts.provider) continue;
|
|
109
|
+
results.push({
|
|
110
|
+
appId: loaded.deployment.appId,
|
|
111
|
+
appName: loaded.deployment.appName,
|
|
112
|
+
provider: loaded.provider,
|
|
113
|
+
appDir: loaded.appDir,
|
|
114
|
+
workerName: loaded.workerName,
|
|
115
|
+
dependsOn: loaded.deployment.dependsOn ?? []
|
|
116
|
+
});
|
|
117
|
+
} catch (err) {
|
|
118
|
+
opts.onError?.({
|
|
119
|
+
configPath,
|
|
120
|
+
appDir,
|
|
121
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return results;
|
|
127
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { resolve, isAbsolute, join, dirname } from 'node:path';
|
|
2
|
+
import { existsSync, statSync } from 'node:fs';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import type { AppDeployment } from '@vibesdotdev/infra-core/deployment';
|
|
5
|
+
|
|
6
|
+
export interface LoadedDeployment {
|
|
7
|
+
configPath: string;
|
|
8
|
+
appDir: string;
|
|
9
|
+
deployment: AppDeployment;
|
|
10
|
+
provider: string;
|
|
11
|
+
raw: unknown;
|
|
12
|
+
/**
|
|
13
|
+
* Canonical wrangler.jsonc render output, when the default export is a
|
|
14
|
+
* managed Cloudflare web-app deployment (see
|
|
15
|
+
* `@vibesdotdev/infra-cloudflare/regen`). `null` when the export isn't
|
|
16
|
+
* a managed deployment — used by the regen orchestrator to gate writes
|
|
17
|
+
* and the CI drift check.
|
|
18
|
+
*/
|
|
19
|
+
wranglerJsoncString: string | null;
|
|
20
|
+
/** Mirrors `webAppDeployment.managed`; `false` when not a managed export. */
|
|
21
|
+
managed: boolean;
|
|
22
|
+
/** Cloudflare Workers script name, when emitted by the managed export. */
|
|
23
|
+
workerName: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const CONFIG_FILENAMES = ['deployment.config.ts', 'deployment.config.js', 'deployment.config.mjs'];
|
|
27
|
+
|
|
28
|
+
export function resolveAppDir(input: string): string {
|
|
29
|
+
const absolute = isAbsolute(input) ? input : resolve(process.cwd(), input);
|
|
30
|
+
if (!existsSync(absolute)) {
|
|
31
|
+
throw new Error(`Path does not exist: ${absolute}`);
|
|
32
|
+
}
|
|
33
|
+
const stat = statSync(absolute);
|
|
34
|
+
if (!stat.isDirectory()) {
|
|
35
|
+
throw new Error(`Expected directory, got file: ${absolute}`);
|
|
36
|
+
}
|
|
37
|
+
return absolute;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function findConfigFile(appDir: string): string {
|
|
41
|
+
for (const name of CONFIG_FILENAMES) {
|
|
42
|
+
const candidate = join(appDir, name);
|
|
43
|
+
if (existsSync(candidate)) return candidate;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(
|
|
46
|
+
`No deployment config found in ${appDir}. Expected one of: ${CONFIG_FILENAMES.join(', ')}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function extractDeployment(raw: unknown): { deployment: AppDeployment; provider: string } {
|
|
51
|
+
if (!raw || typeof raw !== 'object') {
|
|
52
|
+
throw new Error('deployment.config default export must be an object');
|
|
53
|
+
}
|
|
54
|
+
const record = raw as Record<string, unknown>;
|
|
55
|
+
const deployment = (record.deployment ?? record) as AppDeployment | undefined;
|
|
56
|
+
if (!deployment || typeof deployment !== 'object' || !('appId' in deployment)) {
|
|
57
|
+
throw new Error('deployment.config must export an AppDeployment (or { deployment })');
|
|
58
|
+
}
|
|
59
|
+
const provider = (deployment as AppDeployment).provider;
|
|
60
|
+
if (!provider || typeof provider !== 'string') {
|
|
61
|
+
throw new Error('deployment.provider is required');
|
|
62
|
+
}
|
|
63
|
+
return { deployment: deployment as AppDeployment, provider };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Walk upward from `from` looking for the workspace root (the directory
|
|
68
|
+
* with a `bun.lock` or `package.json` containing `workspaces`).
|
|
69
|
+
*/
|
|
70
|
+
function findWorkspaceRoot(from: string): string {
|
|
71
|
+
let dir = from;
|
|
72
|
+
while (dir !== dirname(dir)) {
|
|
73
|
+
if (existsSync(join(dir, 'bun.lock'))) return dir;
|
|
74
|
+
const pkgPath = join(dir, 'package.json');
|
|
75
|
+
if (existsSync(pkgPath)) {
|
|
76
|
+
try {
|
|
77
|
+
const pkg = JSON.parse(require('node:fs').readFileSync(pkgPath, 'utf8'));
|
|
78
|
+
if (pkg.workspaces) return dir;
|
|
79
|
+
} catch {
|
|
80
|
+
// not a parseable package.json; keep walking
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
dir = dirname(dir);
|
|
84
|
+
}
|
|
85
|
+
return from;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface SubprocessOutput {
|
|
89
|
+
raw: unknown;
|
|
90
|
+
render: {
|
|
91
|
+
managed: boolean;
|
|
92
|
+
rendered: string | null;
|
|
93
|
+
workerName: string | null;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Load a deployment.config.ts via a `bun` subprocess from the workspace
|
|
99
|
+
* root. Direct `await import(configPath)` doesn't work when the compiled
|
|
100
|
+
* `vibes` binary runs against a workspace symlink — its bundled module
|
|
101
|
+
* resolver has no idea where `@vibesdotdev/infra-core` lives. Subprocess
|
|
102
|
+
* inherits the workspace's bun (path + node_modules), so workspace
|
|
103
|
+
* package imports resolve as if you ran `bun apps/<app>/deployment.config.ts`
|
|
104
|
+
* directly.
|
|
105
|
+
*
|
|
106
|
+
* The subprocess also tries to import `@vibesdotdev/infra-cloudflare/web-app`
|
|
107
|
+
* and call `renderWranglerJsoncFromDefaultExport(raw)` so the canonical
|
|
108
|
+
* wrangler.jsonc string is returned alongside the raw config. This lets
|
|
109
|
+
* the regen orchestrator stay agnostic of provider-specific rendering.
|
|
110
|
+
* If the import fails (SDK consumer without infra-cloudflare in their
|
|
111
|
+
* tree), the render block is reported as `{ managed: false, rendered: null }`.
|
|
112
|
+
*/
|
|
113
|
+
async function loadConfigViaSubprocess(
|
|
114
|
+
configPath: string,
|
|
115
|
+
workspaceRoot: string
|
|
116
|
+
): Promise<SubprocessOutput> {
|
|
117
|
+
return new Promise((resolvePromise, reject) => {
|
|
118
|
+
const script = `
|
|
119
|
+
const mod = await import(${JSON.stringify(configPath)});
|
|
120
|
+
const raw = mod.default ?? mod;
|
|
121
|
+
let render = { managed: false, rendered: null, workerName: null };
|
|
122
|
+
try {
|
|
123
|
+
const cf = await import('@vibesdotdev/infra-cloudflare/web-app');
|
|
124
|
+
if (typeof cf.renderWranglerJsoncFromDefaultExport === 'function') {
|
|
125
|
+
render = cf.renderWranglerJsoncFromDefaultExport(raw);
|
|
126
|
+
}
|
|
127
|
+
} catch (_) {
|
|
128
|
+
// infra-cloudflare not resolvable; leave render as the default null block.
|
|
129
|
+
}
|
|
130
|
+
process.stdout.write(JSON.stringify({ raw, render }));
|
|
131
|
+
`;
|
|
132
|
+
const child = spawn('bun', ['--bun', '-e', script], {
|
|
133
|
+
cwd: workspaceRoot,
|
|
134
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
135
|
+
});
|
|
136
|
+
let stdout = '';
|
|
137
|
+
let stderr = '';
|
|
138
|
+
child.stdout?.on('data', (chunk) => (stdout += String(chunk)));
|
|
139
|
+
child.stderr?.on('data', (chunk) => (stderr += String(chunk)));
|
|
140
|
+
child.on('error', reject);
|
|
141
|
+
child.on('close', (code) => {
|
|
142
|
+
if (code !== 0) {
|
|
143
|
+
reject(
|
|
144
|
+
new Error(
|
|
145
|
+
`bun subprocess exited with code ${code}\nstderr: ${stderr.trim()}\nstdout: ${stdout.trim()}`
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
resolvePromise(JSON.parse(stdout) as SubprocessOutput);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
reject(
|
|
154
|
+
new Error(
|
|
155
|
+
`Failed to parse subprocess JSON output: ${err instanceof Error ? err.message : String(err)}\nstdout: ${stdout.slice(0, 500)}`
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function loadDeploymentConfig(appDir: string): Promise<LoadedDeployment> {
|
|
164
|
+
const dir = resolveAppDir(appDir);
|
|
165
|
+
const configPath = findConfigFile(dir);
|
|
166
|
+
const workspaceRoot = findWorkspaceRoot(dir);
|
|
167
|
+
const output = await loadConfigViaSubprocess(configPath, workspaceRoot);
|
|
168
|
+
const { deployment, provider } = extractDeployment(output.raw);
|
|
169
|
+
return {
|
|
170
|
+
configPath,
|
|
171
|
+
appDir: dir,
|
|
172
|
+
deployment,
|
|
173
|
+
provider,
|
|
174
|
+
raw: output.raw,
|
|
175
|
+
wranglerJsoncString: output.render.rendered,
|
|
176
|
+
managed: output.render.managed,
|
|
177
|
+
workerName: output.render.workerName
|
|
178
|
+
};
|
|
179
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default as infraDeployPlugin } from './infra-deploy.plugin';
|
|
2
|
+
export { loadDeploymentConfig } from './config-loader.ts';
|
|
3
|
+
export type { LoadedDeployment } from './config-loader.ts';
|
|
4
|
+
export {
|
|
5
|
+
regenerateApp,
|
|
6
|
+
regenerateAll,
|
|
7
|
+
regenExitCode,
|
|
8
|
+
type RegenResult,
|
|
9
|
+
type RegenStatus,
|
|
10
|
+
type RegenerateOptions
|
|
11
|
+
} from './regenerate.ts';
|