@envsync-cloud/deploy 0.8.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 +15 -0
- package/dist/index.js +370 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# EnvSync OSS Deploy
|
|
2
|
+
|
|
3
|
+
Public OSS deploy package.
|
|
4
|
+
|
|
5
|
+
Current responsibilities:
|
|
6
|
+
|
|
7
|
+
- validate OSS deploy configs against edition rules
|
|
8
|
+
- render an OSS topology plan
|
|
9
|
+
- omit landing and management API artifacts
|
|
10
|
+
- keep observability opt-in
|
|
11
|
+
|
|
12
|
+
Commands:
|
|
13
|
+
|
|
14
|
+
- `envsync-deploy validate [deploy.yaml]`
|
|
15
|
+
- `envsync-deploy plan [deploy.yaml]`
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
|
|
7
|
+
// ../deploy-core/src/index.ts
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import YAML from "yaml";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
var DeployPlanError = class extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "DeployPlanError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var deployConfigSchema = z.object({
|
|
19
|
+
edition: z.enum(["oss", "enterprise"]).optional(),
|
|
20
|
+
source: z.object({
|
|
21
|
+
repo_url: z.string().default("https://github.com/EnvSync-Cloud/envsync.git"),
|
|
22
|
+
ref: z.string().default("main")
|
|
23
|
+
}).default({}),
|
|
24
|
+
release: z.object({
|
|
25
|
+
version: z.string().default("0.8.1"),
|
|
26
|
+
channel: z.string().default("stable")
|
|
27
|
+
}).default({}),
|
|
28
|
+
domain: z.object({
|
|
29
|
+
root_domain: z.string().default("example.com"),
|
|
30
|
+
acme_email: z.string().default("ops@example.com")
|
|
31
|
+
}).default({}),
|
|
32
|
+
services: z.object({
|
|
33
|
+
stack_name: z.string().default("envsync"),
|
|
34
|
+
api_port: z.number().int().positive().default(4e3),
|
|
35
|
+
management_api_port: z.number().int().positive().default(4001),
|
|
36
|
+
public_http_port: z.number().int().positive().default(80),
|
|
37
|
+
public_https_port: z.number().int().positive().default(443)
|
|
38
|
+
}).default({}),
|
|
39
|
+
images: z.object({
|
|
40
|
+
api: z.string().default("ghcr.io/envsync-cloud/envsync-api:stable"),
|
|
41
|
+
management_api: z.string().default("ghcr.io/envsync-cloud/envsync-management-api:stable"),
|
|
42
|
+
web: z.string().default("ghcr.io/envsync-cloud/envsync-web-oss-static:stable"),
|
|
43
|
+
enterprise_web: z.string().default("ghcr.io/envsync-cloud/envsync-web-static:stable"),
|
|
44
|
+
landing: z.string().default("ghcr.io/envsync-cloud/envsync-landing-static:stable"),
|
|
45
|
+
keycloak: z.string().default("envsync-keycloak:stable"),
|
|
46
|
+
clickstack: z.string().default("ghcr.io/envsync-cloud/clickstack:stable"),
|
|
47
|
+
otel_agent: z.string().default("otel/opentelemetry-collector-contrib:latest")
|
|
48
|
+
}).default({}),
|
|
49
|
+
features: z.object({
|
|
50
|
+
management_api: z.boolean().optional(),
|
|
51
|
+
management_web: z.boolean().optional(),
|
|
52
|
+
landing: z.boolean().optional()
|
|
53
|
+
}).default({}),
|
|
54
|
+
observability: z.object({
|
|
55
|
+
enabled: z.boolean().optional(),
|
|
56
|
+
public_obs: z.boolean().optional()
|
|
57
|
+
}).default({}),
|
|
58
|
+
license: z.object({
|
|
59
|
+
required: z.boolean().optional(),
|
|
60
|
+
server_url: z.string().optional(),
|
|
61
|
+
key: z.string().optional(),
|
|
62
|
+
install_fingerprint: z.string().optional(),
|
|
63
|
+
lease_ttl_seconds: z.number().int().positive().default(300)
|
|
64
|
+
}).default({}),
|
|
65
|
+
frontend: z.object({
|
|
66
|
+
dashboard_variant: z.enum(["oss", "enterprise"]).optional(),
|
|
67
|
+
include_manage_subtree: z.boolean().optional()
|
|
68
|
+
}).default({})
|
|
69
|
+
});
|
|
70
|
+
function readDeployConfigFile(filePath) {
|
|
71
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
72
|
+
if (!fs.existsSync(absolutePath)) {
|
|
73
|
+
throw new DeployPlanError(`Deploy config file not found: ${absolutePath}`);
|
|
74
|
+
}
|
|
75
|
+
const raw = fs.readFileSync(absolutePath, "utf8");
|
|
76
|
+
if (absolutePath.endsWith(".json")) {
|
|
77
|
+
return JSON.parse(raw);
|
|
78
|
+
}
|
|
79
|
+
return YAML.parse(raw);
|
|
80
|
+
}
|
|
81
|
+
function validateEditionRules(config, edition) {
|
|
82
|
+
const errors = [];
|
|
83
|
+
if (edition === "oss") {
|
|
84
|
+
if (config.edition === "enterprise") {
|
|
85
|
+
errors.push("OSS deploy tooling cannot consume a config explicitly marked as enterprise.");
|
|
86
|
+
}
|
|
87
|
+
if (config.features.management_api === true) {
|
|
88
|
+
errors.push("OSS edition cannot enable management_api.");
|
|
89
|
+
}
|
|
90
|
+
if (config.features.landing === true) {
|
|
91
|
+
errors.push("OSS edition cannot enable landing.");
|
|
92
|
+
}
|
|
93
|
+
if (config.license.required === true) {
|
|
94
|
+
errors.push("OSS edition cannot require enterprise licensing.");
|
|
95
|
+
}
|
|
96
|
+
if (config.license.server_url || config.license.key || config.license.install_fingerprint) {
|
|
97
|
+
errors.push("OSS edition cannot include enterprise license server settings.");
|
|
98
|
+
}
|
|
99
|
+
if (config.frontend.dashboard_variant === "enterprise") {
|
|
100
|
+
errors.push("OSS edition cannot use the enterprise dashboard variant.");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (edition === "enterprise") {
|
|
104
|
+
if (config.edition === "oss") {
|
|
105
|
+
errors.push("Enterprise deploy tooling cannot consume a config explicitly marked as oss.");
|
|
106
|
+
}
|
|
107
|
+
if (config.features.management_api === false) {
|
|
108
|
+
errors.push("Enterprise edition must enable management_api.");
|
|
109
|
+
}
|
|
110
|
+
if (config.features.landing === false) {
|
|
111
|
+
errors.push("Enterprise edition must enable landing.");
|
|
112
|
+
}
|
|
113
|
+
if (config.license.required === false) {
|
|
114
|
+
errors.push("Enterprise edition must require licensing.");
|
|
115
|
+
}
|
|
116
|
+
if (!config.license.server_url) {
|
|
117
|
+
errors.push("Enterprise edition requires license.server_url.");
|
|
118
|
+
}
|
|
119
|
+
if (config.frontend.dashboard_variant === "oss") {
|
|
120
|
+
errors.push("Enterprise edition cannot use the OSS dashboard variant.");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (errors.length > 0) {
|
|
124
|
+
throw new DeployPlanError(errors.join(" "));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function buildServicePlans(config, edition) {
|
|
128
|
+
const observabilityEnabled = config.observability.enabled ?? edition === "enterprise";
|
|
129
|
+
const managementEnabled = edition === "enterprise";
|
|
130
|
+
const landingEnabled = edition === "enterprise";
|
|
131
|
+
return [
|
|
132
|
+
{ id: "api", enabled: true, tier: "core", reason: "Required in all editions.", image: config.images.api },
|
|
133
|
+
{ id: "web", enabled: true, tier: "core", reason: "Primary dashboard artifact.", image: edition === "enterprise" ? config.images.enterprise_web : config.images.web },
|
|
134
|
+
{ id: "postgres", enabled: true, tier: "core", reason: "Core persistence.", image: null },
|
|
135
|
+
{ id: "redis", enabled: true, tier: "core", reason: "Core cache and sessions.", image: null },
|
|
136
|
+
{ id: "rustfs", enabled: true, tier: "core", reason: "Object storage for artifacts.", image: null },
|
|
137
|
+
{ id: "openfga", enabled: true, tier: "core", reason: "Authorization service.", image: null },
|
|
138
|
+
{ id: "minikms", enabled: true, tier: "core", reason: "Secret encryption service.", image: null },
|
|
139
|
+
{ id: "keycloak", enabled: true, tier: "core", reason: "Authentication provider.", image: config.images.keycloak },
|
|
140
|
+
{ id: "management-api", enabled: managementEnabled, tier: "enterprise", reason: managementEnabled ? "Enterprise control plane API." : "Not deployed in OSS.", image: managementEnabled ? config.images.management_api : null },
|
|
141
|
+
{ id: "landing", enabled: landingEnabled, tier: "enterprise", reason: landingEnabled ? "Enterprise/public onboarding surface." : "Omitted in OSS.", image: landingEnabled ? config.images.landing : null },
|
|
142
|
+
{ id: "clickstack", enabled: observabilityEnabled, tier: observabilityEnabled ? "optional" : "optional", reason: observabilityEnabled ? "Observability enabled for this topology." : "Observability disabled.", image: observabilityEnabled ? config.images.clickstack : null },
|
|
143
|
+
{ id: "otel-agent", enabled: observabilityEnabled, tier: "optional", reason: observabilityEnabled ? "OTEL pipeline enabled for this topology." : "OTEL disabled.", image: observabilityEnabled ? config.images.otel_agent : null }
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
function buildFrontendArtifacts(config, edition) {
|
|
147
|
+
const enterprise = edition === "enterprise";
|
|
148
|
+
return [
|
|
149
|
+
{
|
|
150
|
+
id: "dashboard",
|
|
151
|
+
package_name: "envsync-web",
|
|
152
|
+
build_command: enterprise ? "bun run --filter envsync-web build:enterprise" : "bun run --filter envsync-web build:oss",
|
|
153
|
+
mount_path: "/",
|
|
154
|
+
included: true,
|
|
155
|
+
image: enterprise ? config.images.enterprise_web : config.images.web
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "landing",
|
|
159
|
+
package_name: "envsync-landing",
|
|
160
|
+
build_command: "bun run --filter envsync-landing build",
|
|
161
|
+
mount_path: "/",
|
|
162
|
+
included: enterprise,
|
|
163
|
+
image: enterprise ? config.images.landing : null
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
}
|
|
167
|
+
function buildRuntimeEnv(config, edition) {
|
|
168
|
+
const enterprise = edition === "enterprise";
|
|
169
|
+
const observabilityEnabled = config.observability.enabled ?? enterprise;
|
|
170
|
+
return {
|
|
171
|
+
ENVSYNC_EDITION: edition,
|
|
172
|
+
ENVSYNC_OBSERVABILITY_ENABLED: String(observabilityEnabled),
|
|
173
|
+
ENVSYNC_MANAGEMENT_ENABLED: String(enterprise),
|
|
174
|
+
ENVSYNC_LANDING_ENABLED: String(enterprise),
|
|
175
|
+
ENVSYNC_SINGLE_ORG_MODE: String(edition === "oss"),
|
|
176
|
+
ENVSYNC_LICENSE_ENFORCEMENT: String(enterprise),
|
|
177
|
+
MANAGEMENT_API_URL: enterprise ? `https://manage-api.${config.domain.root_domain}` : "",
|
|
178
|
+
ENVSYNC_LICENSE_SERVER_URL: enterprise ? config.license.server_url ?? "" : "",
|
|
179
|
+
ENVSYNC_LICENSE_KEY: enterprise ? config.license.key ?? "" : "",
|
|
180
|
+
ENVSYNC_INSTALL_FINGERPRINT: enterprise ? config.license.install_fingerprint ?? "" : "",
|
|
181
|
+
ENVSYNC_LICENSE_LEASE_TTL_SECONDS: String(config.license.lease_ttl_seconds),
|
|
182
|
+
ENVSYNC_STACK_NAME: config.services.stack_name,
|
|
183
|
+
ENVSYNC_RELEASE_VERSION: config.release.version
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function buildReleaseArtifacts(config, edition) {
|
|
187
|
+
const npmPackages = [
|
|
188
|
+
{
|
|
189
|
+
name: "@envsync-cloud/deploy",
|
|
190
|
+
registry: "npm",
|
|
191
|
+
edition: "oss",
|
|
192
|
+
publish: edition === "oss"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: "@envsync-cloud/deploy-cli",
|
|
196
|
+
registry: "github-packages",
|
|
197
|
+
edition: "enterprise",
|
|
198
|
+
publish: edition === "enterprise"
|
|
199
|
+
}
|
|
200
|
+
];
|
|
201
|
+
const container_images = [
|
|
202
|
+
{
|
|
203
|
+
name: "envsync-api",
|
|
204
|
+
image: config.images.api,
|
|
205
|
+
build_target: "packages/envsync-api",
|
|
206
|
+
edition: "shared"
|
|
207
|
+
}
|
|
208
|
+
];
|
|
209
|
+
if (edition === "enterprise") {
|
|
210
|
+
container_images.push(
|
|
211
|
+
{
|
|
212
|
+
name: "envsync-management-api",
|
|
213
|
+
image: config.images.management_api,
|
|
214
|
+
build_target: "packages/envsync-management-api",
|
|
215
|
+
edition: "enterprise"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: "envsync-web-static",
|
|
219
|
+
image: config.images.enterprise_web,
|
|
220
|
+
build_target: "apps/envsync-web#build:enterprise",
|
|
221
|
+
edition: "enterprise"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: "envsync-landing-static",
|
|
225
|
+
image: config.images.landing,
|
|
226
|
+
build_target: "apps/envsync-landing#build",
|
|
227
|
+
edition: "enterprise"
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
} else {
|
|
231
|
+
container_images.push({
|
|
232
|
+
name: "envsync-web-oss-static",
|
|
233
|
+
image: config.images.web,
|
|
234
|
+
build_target: "apps/envsync-web#build:oss",
|
|
235
|
+
edition: "oss"
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
npm_packages: npmPackages,
|
|
240
|
+
container_images
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function createDeploymentPlan(rawConfig, forcedEdition) {
|
|
244
|
+
const config = deployConfigSchema.parse(rawConfig);
|
|
245
|
+
const edition = forcedEdition ?? config.edition ?? "oss";
|
|
246
|
+
validateEditionRules(config, edition);
|
|
247
|
+
const warnings = [];
|
|
248
|
+
if (edition === "oss" && (config.observability.enabled ?? false) === false) {
|
|
249
|
+
warnings.push("Observability is disabled for OSS. ClickStack and OTEL services will be omitted.");
|
|
250
|
+
}
|
|
251
|
+
if (edition === "enterprise" && !config.license.key) {
|
|
252
|
+
warnings.push("Enterprise topology is valid, but license.key is empty. Activation will fail until a real key is supplied.");
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
edition,
|
|
256
|
+
config,
|
|
257
|
+
services: buildServicePlans(config, edition),
|
|
258
|
+
frontend: buildFrontendArtifacts(config, edition),
|
|
259
|
+
runtime_env: buildRuntimeEnv(config, edition),
|
|
260
|
+
release_artifacts: buildReleaseArtifacts(config, edition),
|
|
261
|
+
warnings
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function loadDeploymentPlanFromFile(filePath, forcedEdition) {
|
|
265
|
+
return createDeploymentPlan(readDeployConfigFile(filePath), forcedEdition);
|
|
266
|
+
}
|
|
267
|
+
function formatDeploymentPlan(plan, format = "yaml") {
|
|
268
|
+
if (format === "json") {
|
|
269
|
+
return JSON.stringify(plan, null, 2);
|
|
270
|
+
}
|
|
271
|
+
return YAML.stringify(plan);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/index.ts
|
|
275
|
+
function printHelp() {
|
|
276
|
+
console.log(`
|
|
277
|
+
${chalk.bold("EnvSync OSS Deploy")}
|
|
278
|
+
|
|
279
|
+
Commands:
|
|
280
|
+
bootstrap [--force] Bootstrap an OSS self-host topology
|
|
281
|
+
deploy Deploy the OSS self-host topology
|
|
282
|
+
health [--json] Inspect OSS self-host health
|
|
283
|
+
backup Create a self-host backup
|
|
284
|
+
validate [deploy.yaml] [--json] Validate an OSS topology config
|
|
285
|
+
plan [deploy.yaml] [--json] Render the OSS topology plan
|
|
286
|
+
validate-topology [deploy.yaml] Alias for validate
|
|
287
|
+
plan-topology [deploy.yaml] Alias for plan
|
|
288
|
+
`);
|
|
289
|
+
}
|
|
290
|
+
function getPositionals(argv) {
|
|
291
|
+
return argv.filter((arg) => !arg.startsWith("--"));
|
|
292
|
+
}
|
|
293
|
+
function getPlan(filePath, edition) {
|
|
294
|
+
return loadDeploymentPlanFromFile(filePath ?? "deploy.yaml", edition);
|
|
295
|
+
}
|
|
296
|
+
function runLifecycleCommand(args) {
|
|
297
|
+
const result = spawnSync("bun", ["run", "packages/deploy-cli/src/index.ts", ...args], {
|
|
298
|
+
cwd: process.cwd(),
|
|
299
|
+
stdio: "inherit",
|
|
300
|
+
env: process.env
|
|
301
|
+
});
|
|
302
|
+
if ((result.status ?? 1) !== 0) {
|
|
303
|
+
process.exit(result.status ?? 1);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async function main() {
|
|
307
|
+
const argv = process.argv.slice(2);
|
|
308
|
+
const command = argv[0];
|
|
309
|
+
const rest = argv.slice(1);
|
|
310
|
+
const json = rest.includes("--json");
|
|
311
|
+
const positionals = getPositionals(rest);
|
|
312
|
+
const filePath = positionals[0];
|
|
313
|
+
if (!command || command === "--help" || command === "help") {
|
|
314
|
+
printHelp();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
switch (command) {
|
|
318
|
+
case "bootstrap":
|
|
319
|
+
case "deploy":
|
|
320
|
+
case "health":
|
|
321
|
+
case "backup":
|
|
322
|
+
case "restore":
|
|
323
|
+
case "promote":
|
|
324
|
+
case "rollback":
|
|
325
|
+
case "upgrade":
|
|
326
|
+
case "upgrade-deps": {
|
|
327
|
+
runLifecycleCommand([command, ...rest]);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case "validate": {
|
|
331
|
+
const plan = getPlan(filePath, "oss");
|
|
332
|
+
if (json) {
|
|
333
|
+
console.log(JSON.stringify({ valid: true, edition: plan.edition, warnings: plan.warnings }, null, 2));
|
|
334
|
+
} else {
|
|
335
|
+
console.log(chalk.green("OSS topology is valid."));
|
|
336
|
+
if (plan.warnings.length > 0) {
|
|
337
|
+
for (const warning of plan.warnings) {
|
|
338
|
+
console.log(chalk.yellow(`warning: ${warning}`));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
case "plan": {
|
|
345
|
+
const plan = getPlan(filePath, "oss");
|
|
346
|
+
console.log(formatDeploymentPlan(plan, json ? "json" : "yaml"));
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case "validate-topology": {
|
|
350
|
+
const plan = getPlan(filePath, "oss");
|
|
351
|
+
if (json) {
|
|
352
|
+
console.log(JSON.stringify({ valid: true, edition: plan.edition, warnings: plan.warnings }, null, 2));
|
|
353
|
+
} else {
|
|
354
|
+
console.log(chalk.green("OSS topology is valid."));
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
case "plan-topology": {
|
|
359
|
+
const plan = getPlan(filePath, "oss");
|
|
360
|
+
console.log(formatDeploymentPlan(plan, json ? "json" : "yaml"));
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
default:
|
|
364
|
+
throw new Error(`Unknown command: ${command}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
main().catch((error) => {
|
|
368
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
369
|
+
process.exit(1);
|
|
370
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@envsync-cloud/deploy",
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"envsync-deploy": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup --config tsup.config.ts",
|
|
14
|
+
"prepack": "bun run build",
|
|
15
|
+
"check:pack": "npm pack --dry-run",
|
|
16
|
+
"test": "bun run build && bun test"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/EnvSync-Cloud/envsync.git",
|
|
21
|
+
"directory": "packages/deploy"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/EnvSync-Cloud/envsync/tree/main/packages/deploy#readme",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/EnvSync-Cloud/envsync/issues"
|
|
26
|
+
},
|
|
27
|
+
"author": "EnvSync Cloud",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"envsync",
|
|
31
|
+
"deploy",
|
|
32
|
+
"self-hosted",
|
|
33
|
+
"docker-swarm",
|
|
34
|
+
"cli",
|
|
35
|
+
"secrets",
|
|
36
|
+
"oss"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"chalk": "^5.6.2",
|
|
40
|
+
"yaml": "^2.8.1",
|
|
41
|
+
"zod": "^3.25.76"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"tsup": "^8.5.0",
|
|
45
|
+
"typescript": "^5.9.2"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|