@rmartz/envctl 3.1.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 +79 -0
- package/dist/envctl.d.ts +3 -0
- package/dist/envctl.d.ts.map +1 -0
- package/dist/envctl.js +36 -0
- package/dist/envctl.js.map +1 -0
- package/dist/lib/auth.d.ts +21 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +148 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/check-firebase.d.ts +6 -0
- package/dist/lib/check-firebase.d.ts.map +1 -0
- package/dist/lib/check-firebase.js +81 -0
- package/dist/lib/check-firebase.js.map +1 -0
- package/dist/lib/check-live.d.ts +3 -0
- package/dist/lib/check-live.d.ts.map +1 -0
- package/dist/lib/check-live.js +50 -0
- package/dist/lib/check-live.js.map +1 -0
- package/dist/lib/check.d.ts +9 -0
- package/dist/lib/check.d.ts.map +1 -0
- package/dist/lib/check.js +165 -0
- package/dist/lib/check.js.map +1 -0
- package/dist/lib/cli/help.d.ts +4 -0
- package/dist/lib/cli/help.d.ts.map +1 -0
- package/dist/lib/cli/help.js +52 -0
- package/dist/lib/cli/help.js.map +1 -0
- package/dist/lib/cli/registry.d.ts +19 -0
- package/dist/lib/cli/registry.d.ts.map +1 -0
- package/dist/lib/cli/registry.js +111 -0
- package/dist/lib/cli/registry.js.map +1 -0
- package/dist/lib/cli/router.d.ts +22 -0
- package/dist/lib/cli/router.d.ts.map +1 -0
- package/dist/lib/cli/router.js +98 -0
- package/dist/lib/cli/router.js.map +1 -0
- package/dist/lib/cli/version.d.ts +2 -0
- package/dist/lib/cli/version.d.ts.map +1 -0
- package/dist/lib/cli/version.js +58 -0
- package/dist/lib/cli/version.js.map +1 -0
- package/dist/lib/commands/auth.d.ts +2 -0
- package/dist/lib/commands/auth.d.ts.map +1 -0
- package/dist/lib/commands/auth.js +33 -0
- package/dist/lib/commands/auth.js.map +1 -0
- package/dist/lib/commands/bootstrap-args.d.ts +11 -0
- package/dist/lib/commands/bootstrap-args.d.ts.map +1 -0
- package/dist/lib/commands/bootstrap-args.js +111 -0
- package/dist/lib/commands/bootstrap-args.js.map +1 -0
- package/dist/lib/commands/bootstrap.d.ts +5 -0
- package/dist/lib/commands/bootstrap.d.ts.map +1 -0
- package/dist/lib/commands/bootstrap.js +166 -0
- package/dist/lib/commands/bootstrap.js.map +1 -0
- package/dist/lib/commands/check.d.ts +3 -0
- package/dist/lib/commands/check.d.ts.map +1 -0
- package/dist/lib/commands/check.js +47 -0
- package/dist/lib/commands/check.js.map +1 -0
- package/dist/lib/commands/config-pull.d.ts +12 -0
- package/dist/lib/commands/config-pull.d.ts.map +1 -0
- package/dist/lib/commands/config-pull.js +161 -0
- package/dist/lib/commands/config-pull.js.map +1 -0
- package/dist/lib/commands/config-push-args.d.ts +9 -0
- package/dist/lib/commands/config-push-args.d.ts.map +1 -0
- package/dist/lib/commands/config-push-args.js +108 -0
- package/dist/lib/commands/config-push-args.js.map +1 -0
- package/dist/lib/commands/config-push.d.ts +6 -0
- package/dist/lib/commands/config-push.d.ts.map +1 -0
- package/dist/lib/commands/config-push.js +166 -0
- package/dist/lib/commands/config-push.js.map +1 -0
- package/dist/lib/commands/deployment-config.d.ts +9 -0
- package/dist/lib/commands/deployment-config.d.ts.map +1 -0
- package/dist/lib/commands/deployment-config.js +73 -0
- package/dist/lib/commands/deployment-config.js.map +1 -0
- package/dist/lib/commands/env-plan.d.ts +4 -0
- package/dist/lib/commands/env-plan.d.ts.map +1 -0
- package/dist/lib/commands/env-plan.js +85 -0
- package/dist/lib/commands/env-plan.js.map +1 -0
- package/dist/lib/commands/env.d.ts +4 -0
- package/dist/lib/commands/env.d.ts.map +1 -0
- package/dist/lib/commands/env.js +122 -0
- package/dist/lib/commands/env.js.map +1 -0
- package/dist/lib/commands/init.d.ts +3 -0
- package/dist/lib/commands/init.d.ts.map +1 -0
- package/dist/lib/commands/init.js +59 -0
- package/dist/lib/commands/init.js.map +1 -0
- package/dist/lib/commands/secrets-args.d.ts +13 -0
- package/dist/lib/commands/secrets-args.d.ts.map +1 -0
- package/dist/lib/commands/secrets-args.js +136 -0
- package/dist/lib/commands/secrets-args.js.map +1 -0
- package/dist/lib/commands/secrets-plan.d.ts +9 -0
- package/dist/lib/commands/secrets-plan.d.ts.map +1 -0
- package/dist/lib/commands/secrets-plan.js +109 -0
- package/dist/lib/commands/secrets-plan.js.map +1 -0
- package/dist/lib/commands/secrets.d.ts +7 -0
- package/dist/lib/commands/secrets.d.ts.map +1 -0
- package/dist/lib/commands/secrets.js +191 -0
- package/dist/lib/commands/secrets.js.map +1 -0
- package/dist/lib/deployments.d.ts +4 -0
- package/dist/lib/deployments.d.ts.map +1 -0
- package/dist/lib/deployments.js +83 -0
- package/dist/lib/deployments.js.map +1 -0
- package/dist/lib/environments.d.ts +4 -0
- package/dist/lib/environments.d.ts.map +1 -0
- package/dist/lib/environments.js +97 -0
- package/dist/lib/environments.js.map +1 -0
- package/dist/lib/firebase-credential.d.ts +28 -0
- package/dist/lib/firebase-credential.d.ts.map +1 -0
- package/dist/lib/firebase-credential.js +50 -0
- package/dist/lib/firebase-credential.js.map +1 -0
- package/dist/lib/firebase-invalidate.d.ts +4 -0
- package/dist/lib/firebase-invalidate.d.ts.map +1 -0
- package/dist/lib/firebase-invalidate.js +61 -0
- package/dist/lib/firebase-invalidate.js.map +1 -0
- package/dist/lib/firebase-vars.d.ts +14 -0
- package/dist/lib/firebase-vars.d.ts.map +1 -0
- package/dist/lib/firebase-vars.js +40 -0
- package/dist/lib/firebase-vars.js.map +1 -0
- package/dist/lib/firebase.d.ts +20 -0
- package/dist/lib/firebase.d.ts.map +1 -0
- package/dist/lib/firebase.js +189 -0
- package/dist/lib/firebase.js.map +1 -0
- package/dist/lib/gcp.d.ts +4 -0
- package/dist/lib/gcp.d.ts.map +1 -0
- package/dist/lib/gcp.js +53 -0
- package/dist/lib/gcp.js.map +1 -0
- package/dist/lib/generated-secrets.d.ts +16 -0
- package/dist/lib/generated-secrets.d.ts.map +1 -0
- package/dist/lib/generated-secrets.js +68 -0
- package/dist/lib/generated-secrets.js.map +1 -0
- package/dist/lib/logger.d.ts +7 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +60 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/manifest/index.d.ts +6 -0
- package/dist/lib/manifest/index.d.ts.map +1 -0
- package/dist/lib/manifest/index.js +15 -0
- package/dist/lib/manifest/index.js.map +1 -0
- package/dist/lib/manifest/parse.d.ts +11 -0
- package/dist/lib/manifest/parse.d.ts.map +1 -0
- package/dist/lib/manifest/parse.js +214 -0
- package/dist/lib/manifest/parse.js.map +1 -0
- package/dist/lib/manifest/resolve.d.ts +9 -0
- package/dist/lib/manifest/resolve.d.ts.map +1 -0
- package/dist/lib/manifest/resolve.js +34 -0
- package/dist/lib/manifest/resolve.js.map +1 -0
- package/dist/lib/manifest/types.d.ts +57 -0
- package/dist/lib/manifest/types.d.ts.map +1 -0
- package/dist/lib/manifest/types.js +12 -0
- package/dist/lib/manifest/types.js.map +1 -0
- package/dist/lib/manifest/write.d.ts +3 -0
- package/dist/lib/manifest/write.d.ts.map +1 -0
- package/dist/lib/manifest/write.js +110 -0
- package/dist/lib/manifest/write.js.map +1 -0
- package/dist/lib/project.d.ts +6 -0
- package/dist/lib/project.d.ts.map +1 -0
- package/dist/lib/project.js +56 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/providers/deployment.d.ts +19 -0
- package/dist/lib/providers/deployment.d.ts.map +1 -0
- package/dist/lib/providers/deployment.js +62 -0
- package/dist/lib/providers/deployment.js.map +1 -0
- package/dist/lib/providers/registry.d.ts +5 -0
- package/dist/lib/providers/registry.d.ts.map +1 -0
- package/dist/lib/providers/registry.js +31 -0
- package/dist/lib/providers/registry.js.map +1 -0
- package/dist/lib/providers/service.d.ts +35 -0
- package/dist/lib/providers/service.d.ts.map +1 -0
- package/dist/lib/providers/service.js +81 -0
- package/dist/lib/providers/service.js.map +1 -0
- package/dist/lib/rotation-preflight.d.ts +11 -0
- package/dist/lib/rotation-preflight.d.ts.map +1 -0
- package/dist/lib/rotation-preflight.js +47 -0
- package/dist/lib/rotation-preflight.js.map +1 -0
- package/dist/lib/rotation.d.ts +33 -0
- package/dist/lib/rotation.d.ts.map +1 -0
- package/dist/lib/rotation.js +168 -0
- package/dist/lib/rotation.js.map +1 -0
- package/dist/lib/sentry.d.ts +5 -0
- package/dist/lib/sentry.d.ts.map +1 -0
- package/dist/lib/sentry.js +132 -0
- package/dist/lib/sentry.js.map +1 -0
- package/dist/lib/subprocess.d.ts +8 -0
- package/dist/lib/subprocess.d.ts.map +1 -0
- package/dist/lib/subprocess.js +30 -0
- package/dist/lib/subprocess.js.map +1 -0
- package/dist/lib/targets.d.ts +3 -0
- package/dist/lib/targets.d.ts.map +1 -0
- package/dist/lib/targets.js +25 -0
- package/dist/lib/targets.js.map +1 -0
- package/dist/lib/vercel-api.d.ts +50 -0
- package/dist/lib/vercel-api.d.ts.map +1 -0
- package/dist/lib/vercel-api.js +176 -0
- package/dist/lib/vercel-api.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.rotateFirebase = rotateFirebase;
|
|
37
|
+
exports.initFirebase = initFirebase;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const logger_1 = require("./logger");
|
|
41
|
+
const gcp_1 = require("./gcp");
|
|
42
|
+
const firebase_credential_1 = require("./firebase-credential");
|
|
43
|
+
const firebase_vars_1 = require("./firebase-vars");
|
|
44
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
45
|
+
function targetEnvs(targetEnv) {
|
|
46
|
+
if (targetEnv === "all")
|
|
47
|
+
return ["production", "preview", "development"];
|
|
48
|
+
return [targetEnv];
|
|
49
|
+
}
|
|
50
|
+
// Write the split credential for one environment under the resolved names.
|
|
51
|
+
// `includeIdentity` also writes the projectId/clientEmail vars — needed on init,
|
|
52
|
+
// skipped on a plain rotation where those identity vars are unchanged.
|
|
53
|
+
async function writeCredential(client, names, vercelEnv, sa, minted, envs, includeIdentity) {
|
|
54
|
+
if (includeIdentity) {
|
|
55
|
+
await client.setEnvForTarget(names.projectId, sa.gcpProject, vercelEnv, envs);
|
|
56
|
+
await client.setEnvForTarget(names.clientEmail, sa.email, vercelEnv, envs);
|
|
57
|
+
}
|
|
58
|
+
await client.setEnvForTarget(names.privateKey, minted.private_key, vercelEnv, envs);
|
|
59
|
+
await client.setEnvForTarget(names.privateKeyId, minted.private_key_id, vercelEnv, envs);
|
|
60
|
+
}
|
|
61
|
+
// Read the SA identity (email + GCP project) currently in Vercel — the account
|
|
62
|
+
// a rotation mints a fresh key for.
|
|
63
|
+
async function detectSaIdentity(envs, names, client) {
|
|
64
|
+
for (const env of ["production", "preview", "development"]) {
|
|
65
|
+
const sa = await (0, firebase_vars_1.getFirebaseSaForEnv)(env, envs, names, client);
|
|
66
|
+
if (sa?.email) {
|
|
67
|
+
const gcpProject = process.env.GCLOUD_PROJECT ?? sa.gcpProject;
|
|
68
|
+
if (!gcpProject)
|
|
69
|
+
return (0, logger_1.err)("Could not determine GCP project: set GCLOUD_PROJECT or ensure the Firebase project id var is present in Vercel");
|
|
70
|
+
return { email: sa.email, gcpProject };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return (0, logger_1.err)("Could not determine Firebase service account identity from Vercel");
|
|
74
|
+
}
|
|
75
|
+
// The GCP project a service-account email belongs to:
|
|
76
|
+
// `firebase-adminsdk-…@<project>.iam.gserviceaccount.com` → `<project>`.
|
|
77
|
+
// Returns undefined for an unrecognized shape (the caller's guard is
|
|
78
|
+
// best-effort — it only fires when the project is unambiguously encoded).
|
|
79
|
+
function gcpProjectFromSaEmail(saEmail) {
|
|
80
|
+
return /@([^.@]+)\.iam\.gserviceaccount\.com$/.exec(saEmail)?.[1];
|
|
81
|
+
}
|
|
82
|
+
// ─── Firebase rotation ────────────────────────────────────────────────────────
|
|
83
|
+
async function rotateFirebase(targetEnv, client, tempDir, spec = (0, firebase_credential_1.resolveFirebaseCredential)(), allowedTargets) {
|
|
84
|
+
(0, logger_1.log)("Rotating Firebase service account keys...");
|
|
85
|
+
const { names } = spec;
|
|
86
|
+
let allEnvs = await client.listEnvVars();
|
|
87
|
+
if (!(0, firebase_vars_1.hasFirebaseCredential)(allEnvs.envs, names))
|
|
88
|
+
return (0, logger_1.err)("No Firebase service account keys found in Vercel");
|
|
89
|
+
const identity = await detectSaIdentity(allEnvs.envs, names, client);
|
|
90
|
+
const fp = {
|
|
91
|
+
saEmail: identity.email,
|
|
92
|
+
gcpProject: identity.gcpProject,
|
|
93
|
+
names,
|
|
94
|
+
};
|
|
95
|
+
(0, logger_1.log)(` Service account : ${fp.saEmail}`);
|
|
96
|
+
(0, logger_1.log)(` GCP project : ${fp.gcpProject}`);
|
|
97
|
+
const oldKeys = [];
|
|
98
|
+
let rotatedAny = false;
|
|
99
|
+
for (const vercelEnv of targetEnvs(targetEnv)) {
|
|
100
|
+
// Environment-scoped service (#89): skip targets outside the service's
|
|
101
|
+
// declared scope. rotation.run excludes a service that is wholly out of
|
|
102
|
+
// scope, so at least one target always survives here (no false "no keys
|
|
103
|
+
// rotated" error).
|
|
104
|
+
if (allowedTargets && !allowedTargets.includes(vercelEnv))
|
|
105
|
+
continue;
|
|
106
|
+
if (targetEnv === "all" &&
|
|
107
|
+
!(0, firebase_vars_1.hasFirebaseCredentialForEnv)(allEnvs.envs, names, vercelEnv)) {
|
|
108
|
+
(0, logger_1.log)(` [${vercelEnv}] No existing key — skipping (use --env ${vercelEnv} to explicitly add)`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const oldKeyId = await (0, firebase_vars_1.getFirebaseKeyIdForEnv)(vercelEnv, allEnvs.envs, names, client);
|
|
112
|
+
if (oldKeyId) {
|
|
113
|
+
(0, logger_1.log)(` [${vercelEnv}] Current key ID: ${oldKeyId}`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
(0, logger_1.log)(` [${vercelEnv}] No key ID tracked — old key will be swept after redeployment`);
|
|
117
|
+
}
|
|
118
|
+
let envSa = await (0, firebase_vars_1.getFirebaseSaForEnv)(vercelEnv, allEnvs.envs, names, client);
|
|
119
|
+
if (!envSa) {
|
|
120
|
+
if (vercelEnv !== "production") {
|
|
121
|
+
envSa =
|
|
122
|
+
(await (0, firebase_vars_1.getFirebaseSaForEnv)("preview", allEnvs.envs, names, client)) ??
|
|
123
|
+
(await (0, firebase_vars_1.getFirebaseSaForEnv)("development", allEnvs.envs, names, client));
|
|
124
|
+
}
|
|
125
|
+
envSa ??= { email: fp.saEmail, gcpProject: fp.gcpProject };
|
|
126
|
+
}
|
|
127
|
+
(0, logger_1.log)(` [${vercelEnv}] Rotating... (SA: ${envSa.email})`);
|
|
128
|
+
const keyFile = path.join(tempDir, `key-${vercelEnv}.json`);
|
|
129
|
+
(0, gcp_1.createGcpKey)(keyFile, envSa.email, envSa.gcpProject);
|
|
130
|
+
const minted = JSON.parse(fs.readFileSync(keyFile, "utf-8"));
|
|
131
|
+
(0, logger_1.log)(` [${vercelEnv}] New key ID: ${minted.private_key_id}`);
|
|
132
|
+
await writeCredential(client, names, vercelEnv, envSa, minted, (await client.listEnvVars()).envs, false);
|
|
133
|
+
if (oldKeyId) {
|
|
134
|
+
oldKeys.push({
|
|
135
|
+
vercelEnv,
|
|
136
|
+
keyId: oldKeyId,
|
|
137
|
+
saEmail: envSa.email,
|
|
138
|
+
gcpProject: envSa.gcpProject,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
allEnvs = await client.listEnvVars();
|
|
142
|
+
rotatedAny = true;
|
|
143
|
+
}
|
|
144
|
+
if (!rotatedAny)
|
|
145
|
+
(0, logger_1.err)("No Firebase keys rotated — check --env and project configuration");
|
|
146
|
+
(0, logger_1.log)("Firebase key rotation complete.");
|
|
147
|
+
return { oldKeys, fp };
|
|
148
|
+
}
|
|
149
|
+
// ─── Firebase init ────────────────────────────────────────────────────────────
|
|
150
|
+
async function initFirebase(targetEnv, client, tempDir, saEmailOverride, gcpProjectOverride, spec = (0, firebase_credential_1.resolveFirebaseCredential)(), allowedTargets) {
|
|
151
|
+
(0, logger_1.log)("Initializing Firebase service account keys...");
|
|
152
|
+
const currentEnvs = await client.listEnvVars();
|
|
153
|
+
// Resolve the SA identity strictly from THIS target's own declared identity
|
|
154
|
+
// (#126). `init` must never derive the SA from another target's credential (or
|
|
155
|
+
// a local `.env.local`): a blank production target must be minted from
|
|
156
|
+
// production's own `FIREBASE_SA_EMAIL`, not from whatever credential happens to
|
|
157
|
+
// be in scope — cross-deriving pushed staging creds to production. (The run
|
|
158
|
+
// guard already blocks init when the target itself has a credential, so there
|
|
159
|
+
// is nothing on the target to derive from anyway; `rotate` is where an
|
|
160
|
+
// existing credential's identity is reused.) FIREBASE_SA_EMAIL is the
|
|
161
|
+
// deprecated cold-start input; automatic discovery is gated on #70.
|
|
162
|
+
const saEmail = saEmailOverride ?? process.env.FIREBASE_SA_EMAIL;
|
|
163
|
+
if (!saEmail)
|
|
164
|
+
return (0, logger_1.err)(`FIREBASE_SA_EMAIL is required for --init firebase (target: ${targetEnv}). Set FIREBASE_SA_EMAIL in the ${targetEnv} deployment YAML or your shell environment.`);
|
|
165
|
+
const gcpProject = gcpProjectOverride ?? process.env.GCLOUD_PROJECT;
|
|
166
|
+
if (!gcpProject)
|
|
167
|
+
return (0, logger_1.err)(`GCLOUD_PROJECT is required for --init firebase (target: ${targetEnv}). Set FIREBASE_PROJECT_ID in the ${targetEnv} deployment YAML or GCLOUD_PROJECT in your shell environment.`);
|
|
168
|
+
// Refuse a cross-project mixup (#126): the SA's own project (encoded in its
|
|
169
|
+
// email) must match the target's declared GCP project. A mismatch means the
|
|
170
|
+
// wrong SA email is declared for this environment — never push a foreign
|
|
171
|
+
// project's credential to the target.
|
|
172
|
+
const saProject = gcpProjectFromSaEmail(saEmail);
|
|
173
|
+
if (saProject && saProject !== gcpProject)
|
|
174
|
+
return (0, logger_1.err)(`Refusing to init firebase for '${targetEnv}': FIREBASE_SA_EMAIL (${saEmail}) belongs to GCP project '${saProject}', but the target's project is '${gcpProject}'. They must match — check the ${targetEnv} deployment YAML (FIREBASE_SA_EMAIL vs FIREBASE_PROJECT_ID).`);
|
|
175
|
+
(0, logger_1.warn)("FIREBASE_SA_EMAIL is deprecated as a cold-start input — it is only needed for a first-ever (blank) init; `rotate` derives the service account from the target's own credential, and automatic discovery (#70) will remove even the init need.");
|
|
176
|
+
for (const vercelEnv of targetEnvs(targetEnv)) {
|
|
177
|
+
// Environment-scoped service (#89): skip targets outside the service's scope.
|
|
178
|
+
if (allowedTargets && !allowedTargets.includes(vercelEnv))
|
|
179
|
+
continue;
|
|
180
|
+
const keyFile = path.join(tempDir, `key-${vercelEnv}.json`);
|
|
181
|
+
(0, gcp_1.createGcpKey)(keyFile, saEmail, gcpProject);
|
|
182
|
+
const minted = JSON.parse(fs.readFileSync(keyFile, "utf-8"));
|
|
183
|
+
(0, logger_1.log)(` [${vercelEnv}] Created key ID: ${minted.private_key_id}`);
|
|
184
|
+
await writeCredential(client, spec.names, vercelEnv, { email: saEmail, gcpProject }, minted, currentEnvs.envs, true);
|
|
185
|
+
(0, logger_1.log)(` [${vercelEnv}] Pushed split Firebase credential vars`);
|
|
186
|
+
}
|
|
187
|
+
(0, logger_1.log)("Firebase initialization complete.");
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=firebase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase.js","sourceRoot":"","sources":["../../src/lib/firebase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function createGcpKey(outputFile: string, saEmail: string, gcpProject: string): void;
|
|
2
|
+
export declare function listUserManagedGcpKeys(saEmail: string, gcpProject: string): string[];
|
|
3
|
+
export declare function deleteGcpKey(keyId: string, saEmail: string, gcpProject: string): void;
|
|
4
|
+
//# sourceMappingURL=gcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp.d.ts","sourceRoot":"","sources":["../../src/lib/gcp.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,IAAI,CAaN;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAgBV;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,IAAI,CAaN"}
|
package/dist/lib/gcp.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createGcpKey = createGcpKey;
|
|
4
|
+
exports.listUserManagedGcpKeys = listUserManagedGcpKeys;
|
|
5
|
+
exports.deleteGcpKey = deleteGcpKey;
|
|
6
|
+
const subprocess_1 = require("./subprocess");
|
|
7
|
+
// ─── GCP helpers ──────────────────────────────────────────────────────────────
|
|
8
|
+
function createGcpKey(outputFile, saEmail, gcpProject) {
|
|
9
|
+
(0, subprocess_1.run)("gcloud", [
|
|
10
|
+
"iam",
|
|
11
|
+
"service-accounts",
|
|
12
|
+
"keys",
|
|
13
|
+
"create",
|
|
14
|
+
outputFile,
|
|
15
|
+
"--iam-account",
|
|
16
|
+
saEmail,
|
|
17
|
+
"--project",
|
|
18
|
+
gcpProject,
|
|
19
|
+
"--quiet",
|
|
20
|
+
]);
|
|
21
|
+
}
|
|
22
|
+
function listUserManagedGcpKeys(saEmail, gcpProject) {
|
|
23
|
+
const output = (0, subprocess_1.run)("gcloud", [
|
|
24
|
+
"iam",
|
|
25
|
+
"service-accounts",
|
|
26
|
+
"keys",
|
|
27
|
+
"list",
|
|
28
|
+
"--iam-account",
|
|
29
|
+
saEmail,
|
|
30
|
+
"--project",
|
|
31
|
+
gcpProject,
|
|
32
|
+
"--managed-by",
|
|
33
|
+
"user",
|
|
34
|
+
"--format",
|
|
35
|
+
"value(name.basename())",
|
|
36
|
+
]);
|
|
37
|
+
return output.trim().split("\n").filter(Boolean);
|
|
38
|
+
}
|
|
39
|
+
function deleteGcpKey(keyId, saEmail, gcpProject) {
|
|
40
|
+
(0, subprocess_1.run)("gcloud", [
|
|
41
|
+
"iam",
|
|
42
|
+
"service-accounts",
|
|
43
|
+
"keys",
|
|
44
|
+
"delete",
|
|
45
|
+
keyId,
|
|
46
|
+
"--iam-account",
|
|
47
|
+
saEmail,
|
|
48
|
+
"--project",
|
|
49
|
+
gcpProject,
|
|
50
|
+
"--quiet",
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=gcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gcp.js","sourceRoot":"","sources":["../../src/lib/gcp.ts"],"names":[],"mappings":";;AAIA,oCAiBC;AAED,wDAmBC;AAED,oCAiBC;AA7DD,6CAA6C;AAE7C,iFAAiF;AAEjF,SAAgB,YAAY,CAC1B,UAAkB,EAClB,OAAe,EACf,UAAkB;IAElB,IAAA,gBAAM,EAAC,QAAQ,EAAE;QACf,KAAK;QACL,kBAAkB;QAClB,MAAM;QACN,QAAQ;QACR,UAAU;QACV,eAAe;QACf,OAAO;QACP,WAAW;QACX,UAAU;QACV,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,sBAAsB,CACpC,OAAe,EACf,UAAkB;IAElB,MAAM,MAAM,GAAG,IAAA,gBAAM,EAAC,QAAQ,EAAE;QAC9B,KAAK;QACL,kBAAkB;QAClB,MAAM;QACN,MAAM;QACN,eAAe;QACf,OAAO;QACP,WAAW;QACX,UAAU;QACV,cAAc;QACd,MAAM;QACN,UAAU;QACV,wBAAwB;KACzB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,SAAgB,YAAY,CAC1B,KAAa,EACb,OAAe,EACf,UAAkB;IAElB,IAAA,gBAAM,EAAC,QAAQ,EAAE;QACf,KAAK;QACL,kBAAkB;QAClB,MAAM;QACN,QAAQ;QACR,KAAK;QACL,eAAe;QACf,OAAO;QACP,WAAW;QACX,UAAU;QACV,SAAS;KACV,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DeploymentProvider } from "./providers/deployment";
|
|
2
|
+
export declare function generateSecretValue(): string;
|
|
3
|
+
export interface GeneratedSecret {
|
|
4
|
+
name: string;
|
|
5
|
+
/** The distinct provider targets this secret is scoped to. */
|
|
6
|
+
targets: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveGeneratedSecrets(deploymentDir: string): GeneratedSecret[];
|
|
9
|
+
export interface GeneratedSecretPushOptions {
|
|
10
|
+
/** rotate re-mints every value; init only fills targets that lack one. */
|
|
11
|
+
overwrite: boolean;
|
|
12
|
+
/** The run's requested environment target ("all" or a specific target). */
|
|
13
|
+
targetEnv: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function pushGeneratedSecrets(deployment: DeploymentProvider, secrets: GeneratedSecret[], opts: GeneratedSecretPushOptions): Promise<boolean>;
|
|
16
|
+
//# sourceMappingURL=generated-secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated-secrets.d.ts","sourceRoot":"","sources":["../../src/lib/generated-secrets.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AASjE,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAQD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,GACpB,eAAe,EAAE,CAsBnB;AAED,MAAM,WAAW,0BAA0B;IACzC,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,kBAAkB,EAC9B,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,OAAO,CAAC,CA0BlB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSecretValue = generateSecretValue;
|
|
4
|
+
exports.resolveGeneratedSecrets = resolveGeneratedSecrets;
|
|
5
|
+
exports.pushGeneratedSecrets = pushGeneratedSecrets;
|
|
6
|
+
const crypto_1 = require("crypto");
|
|
7
|
+
const logger_1 = require("./logger");
|
|
8
|
+
const manifest_1 = require("./manifest");
|
|
9
|
+
const targets_1 = require("./targets");
|
|
10
|
+
// Project-owned generated secrets (#88): variables declared `generate: true` in
|
|
11
|
+
// the manifest that envctl itself mints — a strong random value per environment,
|
|
12
|
+
// pushed to the deployment target, never stored in git. The motivating case is a
|
|
13
|
+
// Vercel-cron `CRON_SECRET`.
|
|
14
|
+
// One strong built-in format, no knobs (v1): 32 random bytes, base64url-encoded.
|
|
15
|
+
function generateSecretValue() {
|
|
16
|
+
return (0, crypto_1.randomBytes)(32).toString("base64url");
|
|
17
|
+
}
|
|
18
|
+
// Resolve the manifest's `generate: true` variables into (name → target set),
|
|
19
|
+
// honoring variable-group environment scoping: a top-level generated variable
|
|
20
|
+
// applies to every environment; one inside a scoped group applies only to the
|
|
21
|
+
// group's environments. Each environment maps to its provider target
|
|
22
|
+
// (`resolveEnvTarget`); duplicate targets collapse. A project with no manifest
|
|
23
|
+
// (or no generated variables) yields an empty list — a no-op.
|
|
24
|
+
function resolveGeneratedSecrets(deploymentDir) {
|
|
25
|
+
const manifest = (0, manifest_1.parseManifest)(deploymentDir);
|
|
26
|
+
const resolveTarget = (0, targets_1.envTargetResolver)(deploymentDir);
|
|
27
|
+
const secrets = [];
|
|
28
|
+
const record = (name, environments) => {
|
|
29
|
+
const targets = [...new Set(environments.map((env) => resolveTarget(env)))];
|
|
30
|
+
if (targets.length > 0)
|
|
31
|
+
secrets.push({ name, targets });
|
|
32
|
+
};
|
|
33
|
+
for (const variable of manifest.variables)
|
|
34
|
+
if (variable.source.kind === "generate")
|
|
35
|
+
record(variable.name, manifest.environments);
|
|
36
|
+
for (const group of manifest.variableGroups) {
|
|
37
|
+
const environments = group.environments ?? manifest.environments;
|
|
38
|
+
for (const variable of group.variables)
|
|
39
|
+
if (variable.source.kind === "generate")
|
|
40
|
+
record(variable.name, environments);
|
|
41
|
+
}
|
|
42
|
+
return secrets;
|
|
43
|
+
}
|
|
44
|
+
// Mint and push generated secrets to their scoped targets, minting a **distinct**
|
|
45
|
+
// value per target. On init (`overwrite: false`) a target that already has the
|
|
46
|
+
// value is left untouched (idempotent); on rotate (`overwrite: true`) every
|
|
47
|
+
// scoped target gets a fresh value. Returns whether anything was written (so the
|
|
48
|
+
// caller can decide whether a redeploy is needed). Does not redeploy itself.
|
|
49
|
+
async function pushGeneratedSecrets(deployment, secrets, opts) {
|
|
50
|
+
if (secrets.length === 0)
|
|
51
|
+
return false;
|
|
52
|
+
const { envs } = await deployment.listEnvVars();
|
|
53
|
+
let wrote = false;
|
|
54
|
+
for (const secret of secrets) {
|
|
55
|
+
for (const target of secret.targets) {
|
|
56
|
+
if (opts.targetEnv !== "all" && target !== opts.targetEnv)
|
|
57
|
+
continue;
|
|
58
|
+
const existing = deployment.findEnvVar(envs, secret.name, target);
|
|
59
|
+
if (existing && !opts.overwrite)
|
|
60
|
+
continue;
|
|
61
|
+
await deployment.setEnvForTarget(secret.name, generateSecretValue(), target, envs, "encrypted");
|
|
62
|
+
(0, logger_1.log)(` [${target}] ${existing ? "Rotated" : "Minted"} generated secret ${secret.name}`);
|
|
63
|
+
wrote = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return wrote;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=generated-secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generated-secrets.js","sourceRoot":"","sources":["../../src/lib/generated-secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class FatalError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare const log: (msg: string) => void;
|
|
5
|
+
export declare const warn: (msg: string) => void;
|
|
6
|
+
export declare const err: (msg: string) => never;
|
|
7
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAMA,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,SAE9B,CAAC;AACF,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,SAE/B,CAAC;AACF,eAAO,MAAM,GAAG,GAAI,KAAK,MAAM,KAAG,KAEjC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.err = exports.warn = exports.log = exports.FatalError = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const scriptName = process.argv[1]
|
|
39
|
+
? path.basename(process.argv[1], ".js")
|
|
40
|
+
: "vercel-scripts";
|
|
41
|
+
class FatalError extends Error {
|
|
42
|
+
constructor(message) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = "FatalError";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.FatalError = FatalError;
|
|
48
|
+
const log = (msg) => {
|
|
49
|
+
console.log(`[${scriptName}] ${msg}`);
|
|
50
|
+
};
|
|
51
|
+
exports.log = log;
|
|
52
|
+
const warn = (msg) => {
|
|
53
|
+
console.error(`[${scriptName}] WARNING: ${msg}`);
|
|
54
|
+
};
|
|
55
|
+
exports.warn = warn;
|
|
56
|
+
const err = (msg) => {
|
|
57
|
+
throw new FatalError(msg);
|
|
58
|
+
};
|
|
59
|
+
exports.err = err;
|
|
60
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA6B;AAE7B,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;IACvC,CAAC,CAAC,gBAAgB,CAAC;AAErB,MAAa,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AALD,gCAKC;AAEM,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE;IACjC,OAAO,CAAC,GAAG,CAAC,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC,CAAC;AACxC,CAAC,CAAC;AAFW,QAAA,GAAG,OAEd;AACK,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;IAClC,OAAO,CAAC,KAAK,CAAC,IAAI,UAAU,cAAc,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC;AAFW,QAAA,IAAI,QAEf;AACK,MAAM,GAAG,GAAG,CAAC,GAAW,EAAS,EAAE;IACxC,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC,CAAC;AAFW,QAAA,GAAG,OAEd"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { DeploymentDecl, ResolvedManifest, ServiceDecl, VariableDecl, VariableGroup, VariableSource, Visibility, } from "./types";
|
|
2
|
+
export { variableVisibility } from "./types";
|
|
3
|
+
export { MANIFEST_FILENAME, manifestFilePath, parseManifest } from "./parse";
|
|
4
|
+
export { effectiveValue } from "./resolve";
|
|
5
|
+
export { setManifestEnvironments, setManifestTarget } from "./write";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/manifest/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setManifestTarget = exports.setManifestEnvironments = exports.effectiveValue = exports.parseManifest = exports.manifestFilePath = exports.MANIFEST_FILENAME = exports.variableVisibility = void 0;
|
|
4
|
+
var types_1 = require("./types");
|
|
5
|
+
Object.defineProperty(exports, "variableVisibility", { enumerable: true, get: function () { return types_1.variableVisibility; } });
|
|
6
|
+
var parse_1 = require("./parse");
|
|
7
|
+
Object.defineProperty(exports, "MANIFEST_FILENAME", { enumerable: true, get: function () { return parse_1.MANIFEST_FILENAME; } });
|
|
8
|
+
Object.defineProperty(exports, "manifestFilePath", { enumerable: true, get: function () { return parse_1.manifestFilePath; } });
|
|
9
|
+
Object.defineProperty(exports, "parseManifest", { enumerable: true, get: function () { return parse_1.parseManifest; } });
|
|
10
|
+
var resolve_1 = require("./resolve");
|
|
11
|
+
Object.defineProperty(exports, "effectiveValue", { enumerable: true, get: function () { return resolve_1.effectiveValue; } });
|
|
12
|
+
var write_1 = require("./write");
|
|
13
|
+
Object.defineProperty(exports, "setManifestEnvironments", { enumerable: true, get: function () { return write_1.setManifestEnvironments; } });
|
|
14
|
+
Object.defineProperty(exports, "setManifestTarget", { enumerable: true, get: function () { return write_1.setManifestTarget; } });
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/manifest/index.ts"],"names":[],"mappings":";;;AASA,iCAA6C;AAApC,2GAAA,kBAAkB,OAAA;AAC3B,iCAA6E;AAApE,0GAAA,iBAAiB,OAAA;AAAE,yGAAA,gBAAgB,OAAA;AAAE,sGAAA,aAAa,OAAA;AAC3D,qCAA2C;AAAlC,yGAAA,cAAc,OAAA;AACvB,iCAAqE;AAA5D,gHAAA,uBAAuB,OAAA;AAAE,0GAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ResolvedManifest } from "./types";
|
|
2
|
+
export declare const MANIFEST_FILENAME = "manifest.yml";
|
|
3
|
+
export declare function manifestFilePath(deploymentDir: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Parse a project's deployment configuration into the resolved model. Reads
|
|
6
|
+
* `deployment/manifest.yml` when present; otherwise falls back to the legacy
|
|
7
|
+
* flat format (`environments.yml` + per-env value files) mapped onto the same
|
|
8
|
+
* model, so existing projects parse unchanged.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseManifest(deploymentDir: string): ResolvedManifest;
|
|
11
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/lib/manifest/parse.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,gBAAgB,EAKjB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9D;AAuHD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,gBAAgB,CAKrE"}
|