@penvhq/cli 0.11.0 → 0.13.0
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/dist/bin.cjs +269 -55
- package/dist/bin.cjs.map +1 -1
- package/dist/{chunk-JJY4RLDJ.js → chunk-OBIHFXCK.js} +252 -46
- package/dist/chunk-OBIHFXCK.js.map +1 -0
- package/dist/index.cjs +259 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -88
- package/dist/index.js.map +1 -1
- package/dist/install.cjs +252 -43
- package/dist/install.cjs.map +1 -1
- package/dist/install.d.cts +65 -7
- package/dist/install.d.ts +65 -7
- package/dist/install.js +7 -1
- package/package.json +13 -7
- package/dist/chunk-JJY4RLDJ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
detectPackageManager,
|
|
3
3
|
engineVersion,
|
|
4
4
|
installWithPackageManager,
|
|
5
|
+
installedPackages,
|
|
5
6
|
noCommand,
|
|
6
7
|
planInstall,
|
|
7
8
|
renderInstallPlan,
|
|
8
9
|
startChild
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-OBIHFXCK.js";
|
|
10
11
|
|
|
11
12
|
// src/index.ts
|
|
12
13
|
import { setKeychain } from "@penvhq/core";
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
formatValueFile as formatValueFile2,
|
|
23
24
|
isSecret as isSecret2,
|
|
24
25
|
keySourceIdentifier,
|
|
25
|
-
PenvError as
|
|
26
|
+
PenvError as PenvError6,
|
|
26
27
|
parameterId as parameterId3,
|
|
27
28
|
serializeArtifact,
|
|
28
29
|
variableName as variableName3
|
|
@@ -453,7 +454,7 @@ function refsFrom(files) {
|
|
|
453
454
|
}
|
|
454
455
|
|
|
455
456
|
// src/ui.ts
|
|
456
|
-
import {
|
|
457
|
+
import { isPenvErrorLike } from "@penvhq/core";
|
|
457
458
|
|
|
458
459
|
// src/style.ts
|
|
459
460
|
function supportsColor(stream) {
|
|
@@ -586,7 +587,7 @@ function writeError(lines) {
|
|
|
586
587
|
}
|
|
587
588
|
}
|
|
588
589
|
function reportError(error) {
|
|
589
|
-
if (error
|
|
590
|
+
if (isPenvErrorLike(error)) {
|
|
590
591
|
process.stderr.write(`${err.red(CROSS)} ${error.summary}
|
|
591
592
|
`);
|
|
592
593
|
if (error.remedy !== void 0) {
|
|
@@ -629,7 +630,7 @@ import {
|
|
|
629
630
|
MissingMaterializationError,
|
|
630
631
|
openSealed,
|
|
631
632
|
own,
|
|
632
|
-
PenvError as
|
|
633
|
+
PenvError as PenvError5,
|
|
633
634
|
parseArtifact,
|
|
634
635
|
RECORDS_PATH,
|
|
635
636
|
UndecryptableValueError,
|
|
@@ -878,7 +879,7 @@ import {
|
|
|
878
879
|
checkNameCollisions,
|
|
879
880
|
jitiFor,
|
|
880
881
|
NameCollisionError,
|
|
881
|
-
PenvError as
|
|
882
|
+
PenvError as PenvError4,
|
|
882
883
|
ReservedTokenError as ReservedTokenError2,
|
|
883
884
|
resolveAll,
|
|
884
885
|
SCHEMA_HARVEST_ENV,
|
|
@@ -1227,7 +1228,7 @@ async function checkEnvironment(project, environment) {
|
|
|
1227
1228
|
try {
|
|
1228
1229
|
files = await project.provider.list();
|
|
1229
1230
|
} catch (error) {
|
|
1230
|
-
if (!(error instanceof
|
|
1231
|
+
if (!(error instanceof PenvError4)) {
|
|
1231
1232
|
throw error;
|
|
1232
1233
|
}
|
|
1233
1234
|
return {
|
|
@@ -1379,7 +1380,7 @@ function assertNotNested(host, inner) {
|
|
|
1379
1380
|
if (outer === void 0) {
|
|
1380
1381
|
return;
|
|
1381
1382
|
}
|
|
1382
|
-
throw new
|
|
1383
|
+
throw new PenvError5(
|
|
1383
1384
|
"RUN_NESTED",
|
|
1384
1385
|
`\`${inner}\` is starting inside \`${outer}\`, and two penv environments cannot own one process`,
|
|
1385
1386
|
`Drop one of the two wrappers \u2014 the inner one is in a package.json script \u2014 then run \`${outer}\` again.`
|
|
@@ -1389,7 +1390,7 @@ function assertSource(source, inner) {
|
|
|
1389
1390
|
if (source === "project" || source === "snapshot") {
|
|
1390
1391
|
return source;
|
|
1391
1392
|
}
|
|
1392
|
-
throw new
|
|
1393
|
+
throw new PenvError5(
|
|
1393
1394
|
"RUN_SOURCE_UNKNOWN",
|
|
1394
1395
|
`\`--source ${source}\` names no source penv reads`,
|
|
1395
1396
|
`A run reads ${SOURCES.map((name) => `\`${name}\``).join(" or ")}, and \`project\` is the default \u2014 so \`${inner}\` reads the local tree.`
|
|
@@ -1410,7 +1411,7 @@ async function assertNoPublicSecret(project, environment, refs, retry) {
|
|
|
1410
1411
|
}
|
|
1411
1412
|
const parameter = [...ref.namespace, ref.name].join("/");
|
|
1412
1413
|
const prefix = prefixes.find((candidate) => variable.startsWith(candidate));
|
|
1413
|
-
throw new
|
|
1414
|
+
throw new PenvError5(
|
|
1414
1415
|
"RUN_PUBLIC_SECRET",
|
|
1415
1416
|
`The secret ${parameter} maps to ${variable}, which the \`${prefix}\` prefix publishes to the browser`,
|
|
1416
1417
|
`Rename the parameter, or drop \`secret\` from its meta if it is not one \u2014 then \`${retry}\`.`
|
|
@@ -1419,7 +1420,7 @@ async function assertNoPublicSecret(project, environment, refs, retry) {
|
|
|
1419
1420
|
}
|
|
1420
1421
|
function invalidConfiguration(result2, inner) {
|
|
1421
1422
|
const lines = result2.issues.map((issue) => ` ${issue.subject}: ${issue.message}`).join("\n");
|
|
1422
|
-
return new
|
|
1423
|
+
return new PenvError5(
|
|
1423
1424
|
"RUN_INVALID_CONFIGURATION",
|
|
1424
1425
|
`Configuration for environment ${result2.environment} is not valid, so nothing was started:
|
|
1425
1426
|
${lines}`,
|
|
@@ -1441,7 +1442,7 @@ function assertNoActiveDotenv(project) {
|
|
|
1441
1442
|
if (first === void 0) {
|
|
1442
1443
|
return;
|
|
1443
1444
|
}
|
|
1444
|
-
throw new
|
|
1445
|
+
throw new PenvError5(
|
|
1445
1446
|
"RUN_DOTENV_ACTIVE",
|
|
1446
1447
|
`${first.name} is active configuration again, and your framework would read it beside penv's records`,
|
|
1447
1448
|
`Adopt it with \`penv init\`, or delete ${first.name} \u2014 its values belong in ${RECORDS_PATH}/.`
|
|
@@ -1489,7 +1490,7 @@ function declaredCredentials(config, root) {
|
|
|
1489
1490
|
continue;
|
|
1490
1491
|
}
|
|
1491
1492
|
if (!Array.isArray(credentials) || credentials.some((name) => typeof name !== "string" || !VARIABLE.test(name))) {
|
|
1492
|
-
throw new
|
|
1493
|
+
throw new PenvError5(
|
|
1493
1494
|
"PROVIDER_CREDENTIALS_INVALID",
|
|
1494
1495
|
`\`${provider.type}\` declares \`penv.credentials\`, and it is not a list of variable names`,
|
|
1495
1496
|
`Its package.json should read \`"penv": { "credentials": ["ACME_TOKEN"] }\` \u2014 penv strips exactly what an extension declares, so it will not guess at a declaration it cannot read.`
|
|
@@ -1525,7 +1526,7 @@ async function prepare(project, environment, host, inner) {
|
|
|
1525
1526
|
function snapshotPath(host) {
|
|
1526
1527
|
const path = host[SNAPSHOT_VARIABLE]?.trim();
|
|
1527
1528
|
if (path === void 0 || path.length === 0) {
|
|
1528
|
-
throw new
|
|
1529
|
+
throw new PenvError5(
|
|
1529
1530
|
"RUN_SNAPSHOT_UNSET",
|
|
1530
1531
|
`\`--source snapshot\` reads the sealed artifact ${SNAPSHOT_VARIABLE} names, and ${SNAPSHOT_VARIABLE} is not set`,
|
|
1531
1532
|
`Build one with \`${ARTIFACT_BUILD_COMMAND}\` and point ${SNAPSHOT_VARIABLE} at it.`
|
|
@@ -1537,7 +1538,7 @@ function readSnapshot(path) {
|
|
|
1537
1538
|
try {
|
|
1538
1539
|
return readFileSync3(path, "utf8");
|
|
1539
1540
|
} catch {
|
|
1540
|
-
throw new
|
|
1541
|
+
throw new PenvError5(
|
|
1541
1542
|
"RUN_SNAPSHOT_MISSING",
|
|
1542
1543
|
`${SNAPSHOT_VARIABLE} names ${path}, and penv cannot read a sealed artifact there`,
|
|
1543
1544
|
`Point ${SNAPSHOT_VARIABLE} at the artifact your release mounted \u2014 \`${ARTIFACT_BUILD_COMMAND}\` writes one.`
|
|
@@ -1653,7 +1654,7 @@ async function runRun(options) {
|
|
|
1653
1654
|
}
|
|
1654
1655
|
if (source === "snapshot") {
|
|
1655
1656
|
if (options.watch === true) {
|
|
1656
|
-
throw new
|
|
1657
|
+
throw new PenvError5(
|
|
1657
1658
|
"RUN_SNAPSHOT_WATCH",
|
|
1658
1659
|
"`--watch` re-syncs the project tree, and a run from a sealed artifact has no tree to watch",
|
|
1659
1660
|
"Drop `--watch` \u2014 an artifact is built once and read unchanged. Watch the project instead: `penv run --watch -- <command>`."
|
|
@@ -1797,7 +1798,7 @@ function buildCommand(environment, out2) {
|
|
|
1797
1798
|
function targetOf(options) {
|
|
1798
1799
|
const environment = options.environment?.trim();
|
|
1799
1800
|
if (environment === void 0 || environment.length === 0) {
|
|
1800
|
-
throw new
|
|
1801
|
+
throw new PenvError6(
|
|
1801
1802
|
"ARTIFACT_ENV_REQUIRED",
|
|
1802
1803
|
"`penv artifact build` names the environment it builds for, and `--env` was not given",
|
|
1803
1804
|
`Name it: \`${buildCommand(void 0, options.out)}\`. An artifact carries one environment, and penv will not pick which.`
|
|
@@ -1808,7 +1809,7 @@ function targetOf(options) {
|
|
|
1808
1809
|
function outputOf(options, environment) {
|
|
1809
1810
|
const out2 = options.out?.trim();
|
|
1810
1811
|
if (out2 === void 0 || out2.length === 0) {
|
|
1811
|
-
throw new
|
|
1812
|
+
throw new PenvError6(
|
|
1812
1813
|
"ARTIFACT_OUT_REQUIRED",
|
|
1813
1814
|
"`penv artifact build` writes where it is told, and `--out` was not given",
|
|
1814
1815
|
`Name the path: \`${buildCommand(environment, void 0)}\`. The artifact belongs outside the repository, so there is no default worth having.`
|
|
@@ -1826,7 +1827,7 @@ async function winnerOf(project, ref, environment) {
|
|
|
1826
1827
|
return void 0;
|
|
1827
1828
|
}
|
|
1828
1829
|
function plaintextSecret(parameter, location, environment) {
|
|
1829
|
-
return new
|
|
1830
|
+
return new PenvError6(
|
|
1830
1831
|
"ARTIFACT_PLAINTEXT_SECRET",
|
|
1831
1832
|
`${parameter} is a secret for environment ${environment}, and its value comes from ${location}, which is not sealed`,
|
|
1832
1833
|
`Seal it with \`penv encrypt ${parameter} --env ${environment}\` \u2014 an artifact carries ciphertext or nothing.`
|
|
@@ -1840,7 +1841,7 @@ async function runArtifactBuild(options) {
|
|
|
1840
1841
|
const { schema, issues } = await loadSchema(project, environment);
|
|
1841
1842
|
if (schema === void 0) {
|
|
1842
1843
|
const lines = issues.map((issue) => ` ${issue.subject}: ${issue.message}`).join("\n");
|
|
1843
|
-
throw new
|
|
1844
|
+
throw new PenvError6(
|
|
1844
1845
|
"ARTIFACT_NO_SCHEMA",
|
|
1845
1846
|
`The schema did not load, so penv cannot tell what this artifact should deliver:
|
|
1846
1847
|
${lines}`,
|
|
@@ -1965,7 +1966,7 @@ import { dirname as dirname4, join as join4, resolve as resolve4 } from "path";
|
|
|
1965
1966
|
import {
|
|
1966
1967
|
CUTOVER_PATH,
|
|
1967
1968
|
findConfigFile,
|
|
1968
|
-
PenvError as
|
|
1969
|
+
PenvError as PenvError7,
|
|
1969
1970
|
ROLLBACK_DOTENV_PATH,
|
|
1970
1971
|
ROLLBACK_PATH
|
|
1971
1972
|
} from "@penvhq/core";
|
|
@@ -2026,7 +2027,7 @@ function readCutover(root) {
|
|
|
2026
2027
|
};
|
|
2027
2028
|
}
|
|
2028
2029
|
function unreadable(what) {
|
|
2029
|
-
return new
|
|
2030
|
+
return new PenvError7(
|
|
2030
2031
|
"CUTOVER_UNREADABLE",
|
|
2031
2032
|
`${CUTOVER_PATH} records the last dotenv cutover, and ${what}`,
|
|
2032
2033
|
`Run \`penv cleanup\` to drop that record and the rollback bundle it names.`
|
|
@@ -2067,7 +2068,7 @@ function runUndo(options) {
|
|
|
2067
2068
|
const cutover = readCutover(root);
|
|
2068
2069
|
const bundled = bundledFiles(root);
|
|
2069
2070
|
if (cutover === void 0 && bundled.length === 0) {
|
|
2070
|
-
throw new
|
|
2071
|
+
throw new PenvError7(
|
|
2071
2072
|
"INIT_UNDO_NOTHING",
|
|
2072
2073
|
"There is no dotenv cutover to undo in this project",
|
|
2073
2074
|
"Run `penv init` to adopt your dotenv files; undo puts them back afterwards."
|
|
@@ -2081,7 +2082,7 @@ function runUndo(options) {
|
|
|
2081
2082
|
if (occupied2.length > 0) {
|
|
2082
2083
|
const listed = occupied2.join(", ");
|
|
2083
2084
|
const many = occupied2.length > 1;
|
|
2084
|
-
throw new
|
|
2085
|
+
throw new PenvError7(
|
|
2085
2086
|
"INIT_UNDO_OCCUPIED",
|
|
2086
2087
|
`${listed} ${many ? "exist" : "exists"} again, and restoring what penv moved aside would write over ${many ? "them" : "it"}`,
|
|
2087
2088
|
`Move ${listed} out of the way, or run \`penv cleanup\` to keep ${many ? "them" : "it"} and drop the bundle. Nothing was restored.`
|
|
@@ -2174,7 +2175,7 @@ import { defineCommand as defineCommand7 } from "citty";
|
|
|
2174
2175
|
import {
|
|
2175
2176
|
checkNameCollisions as checkNameCollisions2,
|
|
2176
2177
|
holdsProjection as holdsProjection3,
|
|
2177
|
-
PenvError as
|
|
2178
|
+
PenvError as PenvError8,
|
|
2178
2179
|
recordPath,
|
|
2179
2180
|
requireValue,
|
|
2180
2181
|
variableName as variableName4
|
|
@@ -2242,7 +2243,7 @@ async function destinationFor(project, environment, options) {
|
|
|
2242
2243
|
const declared = project.config.providers[environment];
|
|
2243
2244
|
const location = declared?.location;
|
|
2244
2245
|
if (declared === void 0 || declared.type === LOCAL_TREE_TYPE) {
|
|
2245
|
-
throw new
|
|
2246
|
+
throw new PenvError8(
|
|
2246
2247
|
"NO_DESTINATION",
|
|
2247
2248
|
`Environment ${environment}'s provider is the local records tree itself, so penv has nowhere to push`,
|
|
2248
2249
|
`Declare a provider for it in penv.config.ts \u2014 e.g. \`${environment}: { type: "@penvhq/provider-github", location: "owner/repo" }\` \u2014 or push somewhere once with \`penv push --env ${environment} --destination <package> --location <place>\`.`
|
|
@@ -2269,7 +2270,7 @@ function plan(resolutions, config, environment, allowDecrypt) {
|
|
|
2269
2270
|
let encrypted = false;
|
|
2270
2271
|
if (winner.file.encrypted) {
|
|
2271
2272
|
if (!allowDecrypt) {
|
|
2272
|
-
throw new
|
|
2273
|
+
throw new PenvError8(
|
|
2273
2274
|
"ENCRYPTED_VALUE_REFUSED",
|
|
2274
2275
|
`Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${recordPath(winner.location)}, and a push sends plaintext for the destination to re-seal`,
|
|
2275
2276
|
"Re-run with `--allow-decrypt` to decrypt it locally and push it, or push an environment whose values are plaintext. penv's encryption stops at the projection; the destination seals it under its own key."
|
|
@@ -2322,7 +2323,7 @@ async function ensureTargetApproved(provider, environment, options) {
|
|
|
2322
2323
|
return false;
|
|
2323
2324
|
}
|
|
2324
2325
|
if (provider.ensureTarget === void 0) {
|
|
2325
|
-
throw new
|
|
2326
|
+
throw new PenvError8(
|
|
2326
2327
|
"MISSING_TARGET",
|
|
2327
2328
|
`The destination has no environment \`${environment}\` to receive this push, and this provider cannot create one`,
|
|
2328
2329
|
`Create the environment on the destination side, then run \`penv push --env ${environment}\` again.`
|
|
@@ -2332,7 +2333,7 @@ async function ensureTargetApproved(provider, environment, options) {
|
|
|
2332
2333
|
`The destination has no environment \`${environment}\`. Create it?`
|
|
2333
2334
|
);
|
|
2334
2335
|
if (!approved) {
|
|
2335
|
-
throw new
|
|
2336
|
+
throw new PenvError8(
|
|
2336
2337
|
"MISSING_TARGET",
|
|
2337
2338
|
`The destination has no environment \`${environment}\` to receive this push`,
|
|
2338
2339
|
`Re-run with \`--yes\` to create it, answer \`y\` at the prompt, or create it on the destination side yourself.`
|
|
@@ -3496,7 +3497,7 @@ import {
|
|
|
3496
3497
|
formatValueFile as formatValueFile5,
|
|
3497
3498
|
isSecret as isSecret5,
|
|
3498
3499
|
openValue as openValue3,
|
|
3499
|
-
PenvError as
|
|
3500
|
+
PenvError as PenvError10,
|
|
3500
3501
|
parameterId as parameterId5,
|
|
3501
3502
|
recordPath as recordPath3,
|
|
3502
3503
|
sealValue as sealValue2
|
|
@@ -3507,7 +3508,7 @@ import { defineCommand as defineCommand9 } from "citty";
|
|
|
3507
3508
|
import {
|
|
3508
3509
|
formatValueFile as formatValueFile4,
|
|
3509
3510
|
isSecret as isSecret4,
|
|
3510
|
-
PenvError as
|
|
3511
|
+
PenvError as PenvError9,
|
|
3511
3512
|
parameterId as parameterId4,
|
|
3512
3513
|
recordPath as recordPath2,
|
|
3513
3514
|
sealValue
|
|
@@ -3531,7 +3532,7 @@ function targetScope(project, options, key) {
|
|
|
3531
3532
|
return scopeFrom(options);
|
|
3532
3533
|
}
|
|
3533
3534
|
if (environment.trim().length === 0) {
|
|
3534
|
-
throw new
|
|
3535
|
+
throw new PenvError9(
|
|
3535
3536
|
"ENVIRONMENT_FLAG_EMPTY",
|
|
3536
3537
|
`\`--env\` for parameter ${key} names no environment`,
|
|
3537
3538
|
`Pass a declared environment \u2014 ${project.config.environments.map((e) => `\`${e}\``).join(", ")} \u2014 e.g. \`--env production\`, or drop \`--env\` to write the scope that has no environment.`
|
|
@@ -3544,7 +3545,7 @@ function policyEnvironment(project, options) {
|
|
|
3544
3545
|
}
|
|
3545
3546
|
function sealFor(project, file, value, parameter, environment) {
|
|
3546
3547
|
if (environment === void 0) {
|
|
3547
|
-
throw new
|
|
3548
|
+
throw new PenvError9(
|
|
3548
3549
|
"SECRET_SCOPE_AMBIGUOUS",
|
|
3549
3550
|
`Parameter ${parameter} is a secret, and ${recordPath2(formatValueFile4(file))} names no environment`,
|
|
3550
3551
|
"Keys are declared per environment in the `keys` block of penv.config.ts, so penv cannot tell which key should seal a file that every environment reads. Write it at an environment scope \u2014 add `--env <environment>` \u2014 or drop `secret` from the parameter's meta."
|
|
@@ -3646,7 +3647,7 @@ function twins(project, key, options) {
|
|
|
3646
3647
|
}
|
|
3647
3648
|
function environmentFor(project, options, verb) {
|
|
3648
3649
|
if (options.environment === void 0) {
|
|
3649
|
-
throw new
|
|
3650
|
+
throw new PenvError10(
|
|
3650
3651
|
"SECRET_SCOPE_AMBIGUOUS",
|
|
3651
3652
|
`\`penv ${verb}\` names no environment, and keys are declared per environment`,
|
|
3652
3653
|
"Pass `--env <environment>`. penv cannot tell which environment's key applies to a file that names none, and will not pick one for you."
|
|
@@ -3665,7 +3666,7 @@ async function runEncrypt(options) {
|
|
|
3665
3666
|
const value = await readOne(project, plain);
|
|
3666
3667
|
if (value === void 0) {
|
|
3667
3668
|
const already = await readOne(project, sealed);
|
|
3668
|
-
throw new
|
|
3669
|
+
throw new PenvError10(
|
|
3669
3670
|
"PARAMETER_ABSENT",
|
|
3670
3671
|
already === void 0 ? `Parameter ${parameter} has no value file at ${recordPath3(formatValueFile5(plain))}` : `Parameter ${parameter} is already encrypted at ${recordPath3(formatValueFile5(sealed))}`,
|
|
3671
3672
|
already === void 0 ? `Write it first with \`penv set ${options.key} --env ${environment}\`, which seals it automatically when the parameter's meta declares it a secret.` : "Nothing to do."
|
|
@@ -3686,7 +3687,7 @@ async function runDecrypt(options) {
|
|
|
3686
3687
|
const [plain, sealed] = twins(project, options.key, options);
|
|
3687
3688
|
const parameter = parameterId5(plain);
|
|
3688
3689
|
if (isSecret5(await project.provider.readMeta(plain), environment)) {
|
|
3689
|
-
throw new
|
|
3690
|
+
throw new PenvError10(
|
|
3690
3691
|
"SECRET_DECRYPT_REFUSED",
|
|
3691
3692
|
`Parameter ${parameter} is declared a secret for environment ${environment}, so penv will not write it in plaintext`,
|
|
3692
3693
|
"A secret with a plaintext value file is a `penv doctor` failure. Drop `secret` from the parameter's meta if it is not one, or run `penv generate --allow-decrypt` if you need the plaintext value in a `.env` artifact."
|
|
@@ -3694,7 +3695,7 @@ async function runDecrypt(options) {
|
|
|
3694
3695
|
}
|
|
3695
3696
|
const stored = await readOne(project, sealed);
|
|
3696
3697
|
if (stored === void 0) {
|
|
3697
|
-
throw new
|
|
3698
|
+
throw new PenvError10(
|
|
3698
3699
|
"PARAMETER_ABSENT",
|
|
3699
3700
|
`Parameter ${parameter} has no encrypted value file at ${recordPath3(formatValueFile5(sealed))}`,
|
|
3700
3701
|
`Nothing to decrypt. \`penv get ${options.key} --env ${environment} --explain\` shows every file penv looked at.`
|
|
@@ -3717,7 +3718,7 @@ async function runDecrypt(options) {
|
|
|
3717
3718
|
removed: formatValueFile5(sealed)
|
|
3718
3719
|
};
|
|
3719
3720
|
}
|
|
3720
|
-
var UndecryptableAt = class extends
|
|
3721
|
+
var UndecryptableAt = class extends PenvError10 {
|
|
3721
3722
|
constructor(parameter, environment, location, detail) {
|
|
3722
3723
|
super(
|
|
3723
3724
|
"VALUE_UNDECRYPTABLE",
|
|
@@ -3772,7 +3773,7 @@ var decryptCommand = defineCommand9({
|
|
|
3772
3773
|
});
|
|
3773
3774
|
|
|
3774
3775
|
// src/commands/fill.ts
|
|
3775
|
-
import { PenvError as
|
|
3776
|
+
import { PenvError as PenvError11, recordPath as recordPath4, SCHEMA_SHAPE_FILE as SCHEMA_SHAPE_FILE2 } from "@penvhq/core";
|
|
3776
3777
|
import { defineCommand as defineCommand10 } from "citty";
|
|
3777
3778
|
var BLOCKING = /* @__PURE__ */ new Set(["config", "collision", "reserved"]);
|
|
3778
3779
|
async function runFill(options) {
|
|
@@ -3787,7 +3788,7 @@ async function runFill(options) {
|
|
|
3787
3788
|
const detail = blockers.map(
|
|
3788
3789
|
(issue) => ` - ${issue.message}${issue.remedy === void 0 ? "" : ` (${issue.remedy})`}`
|
|
3789
3790
|
).join("\n");
|
|
3790
|
-
throw new
|
|
3791
|
+
throw new PenvError11(
|
|
3791
3792
|
"FILL_BLOCKED",
|
|
3792
3793
|
`penv fill cannot run: environment ${environment} has ${blockers.length} unresolved configuration ${blockers.length === 1 ? "issue" : "issues"}:
|
|
3793
3794
|
${detail}`,
|
|
@@ -3927,7 +3928,7 @@ import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve5 }
|
|
|
3927
3928
|
import {
|
|
3928
3929
|
checkNameCollisions as checkNameCollisions3,
|
|
3929
3930
|
effectiveMeta as effectiveMeta2,
|
|
3930
|
-
PenvError as
|
|
3931
|
+
PenvError as PenvError12,
|
|
3931
3932
|
recordPath as recordPath5,
|
|
3932
3933
|
requireValue as requireValue2,
|
|
3933
3934
|
serializeDotenv,
|
|
@@ -3952,7 +3953,7 @@ function entriesFor(project, environment, allowDecrypt) {
|
|
|
3952
3953
|
const winner = resolution.winner;
|
|
3953
3954
|
if (winner?.file.encrypted === true) {
|
|
3954
3955
|
if (!allowDecrypt) {
|
|
3955
|
-
throw new
|
|
3956
|
+
throw new PenvError12(
|
|
3956
3957
|
"ENCRYPTED_VALUE_REFUSED",
|
|
3957
3958
|
`Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${recordPath5(winner.location)}, and \`penv generate\` writes plaintext`,
|
|
3958
3959
|
`Re-run with \`--allow-decrypt\` to write the decrypted value into the artifact, or generate for an environment whose values are plaintext. The artifact is gitignored; a committed plaintext secret is a \`penv doctor\` failure.`
|
|
@@ -4036,7 +4037,7 @@ var generateCommand = defineCommand11({
|
|
|
4036
4037
|
});
|
|
4037
4038
|
|
|
4038
4039
|
// src/commands/get.ts
|
|
4039
|
-
import { PenvError as
|
|
4040
|
+
import { PenvError as PenvError13, recordPath as recordPath6, requireValue as requireValue3, resolveParameter } from "@penvhq/core";
|
|
4040
4041
|
import { defineCommand as defineCommand12 } from "citty";
|
|
4041
4042
|
async function runGet(options) {
|
|
4042
4043
|
const project = openProject(options.cwd);
|
|
@@ -4046,7 +4047,7 @@ async function runGet(options) {
|
|
|
4046
4047
|
const resolution = await resolveParameter(ref, environment, project.provider, keys);
|
|
4047
4048
|
const value = requireValue3(resolution, environment);
|
|
4048
4049
|
if (value === void 0) {
|
|
4049
|
-
throw new
|
|
4050
|
+
throw new PenvError13(
|
|
4050
4051
|
"PARAMETER_ABSENT",
|
|
4051
4052
|
`Parameter ${resolution.parameter} resolves to no value for environment ${environment}`,
|
|
4052
4053
|
`Set it with \`penv set ${options.key} --env ${environment}\`, or run \`penv get ${options.key} --env ${environment} --explain\` to see every file penv looked at.`
|
|
@@ -4130,7 +4131,7 @@ import {
|
|
|
4130
4131
|
findConfigFile as findConfigFile2,
|
|
4131
4132
|
loadConfigFrom as loadConfigFrom2,
|
|
4132
4133
|
lookupEnvironment,
|
|
4133
|
-
PenvError as
|
|
4134
|
+
PenvError as PenvError16,
|
|
4134
4135
|
parseDotenv as parseDotenv2,
|
|
4135
4136
|
schemaFileOf as schemaFileOf4,
|
|
4136
4137
|
UnknownEnvironmentError
|
|
@@ -4141,7 +4142,7 @@ import { defineCommand as defineCommand14 } from "citty";
|
|
|
4141
4142
|
import {
|
|
4142
4143
|
checkNameCollisions as checkNameCollisions4,
|
|
4143
4144
|
isReservedToken as isReservedToken3,
|
|
4144
|
-
PenvError as
|
|
4145
|
+
PenvError as PenvError14,
|
|
4145
4146
|
ReservedTokenError as ReservedTokenError3,
|
|
4146
4147
|
refFromVariable as refFromVariable2,
|
|
4147
4148
|
roundTripsCleanly,
|
|
@@ -4151,7 +4152,7 @@ function assertImportable(ref, variable) {
|
|
|
4151
4152
|
if (!ref.name.includes(".")) {
|
|
4152
4153
|
return;
|
|
4153
4154
|
}
|
|
4154
|
-
throw new
|
|
4155
|
+
throw new PenvError14(
|
|
4155
4156
|
"IMPORT_UNPARSEABLE_NAME",
|
|
4156
4157
|
`The variable ${variable} becomes the parameter \`${ref.name}\`, whose \`.\` would be read as a scope`,
|
|
4157
4158
|
`Filenames are split on \`.\`. Rename ${variable} in the source file, then import it again.`
|
|
@@ -4170,7 +4171,7 @@ function assertRoundTrips(ref, variable, config) {
|
|
|
4170
4171
|
return;
|
|
4171
4172
|
}
|
|
4172
4173
|
const generated = variableName7(ref, config);
|
|
4173
|
-
throw new
|
|
4174
|
+
throw new PenvError14(
|
|
4174
4175
|
"IMPORT_LOSSY_NAME",
|
|
4175
4176
|
`The variable ${variable} becomes the parameter \`${ref.name}\`, which regenerates as ${generated}`,
|
|
4176
4177
|
`\`penv generate\` would write ${generated}, so anything reading \`process.env["${variable}"]\` would read \`undefined\`. Declare the name you want in the \`override\` block of penv.config.ts \u2014 \`override: { "${ref.name}": "${variable}" }\` \u2014 then import it again. Nothing was imported.`
|
|
@@ -4385,7 +4386,7 @@ import {
|
|
|
4385
4386
|
isLegalEnvironmentName as isLegalEnvironmentName2,
|
|
4386
4387
|
loadConfigFrom,
|
|
4387
4388
|
PENV_DIR as PENV_DIR2,
|
|
4388
|
-
PenvError as
|
|
4389
|
+
PenvError as PenvError15,
|
|
4389
4390
|
parameterId as parameterId6,
|
|
4390
4391
|
parseDotenv,
|
|
4391
4392
|
RECORDS_PATH as RECORDS_PATH3,
|
|
@@ -4666,7 +4667,7 @@ function suggestEnvironments(root) {
|
|
|
4666
4667
|
return [...found].sort();
|
|
4667
4668
|
}
|
|
4668
4669
|
function emptyFlag(flag) {
|
|
4669
|
-
return new
|
|
4670
|
+
return new PenvError15(
|
|
4670
4671
|
"INIT_FLAG_EMPTY",
|
|
4671
4672
|
`\`--${flag}\` was given without a value`,
|
|
4672
4673
|
flag === "schema" ? `Name the module that exports the schema, e.g. \`--schema src/env.ts\`, or drop the flag to use ${DEFAULT_SCHEMA_FILE2}.` : "Name the environment, e.g. `--env production`, or drop the flag to leave the whitelist empty and declare it in penv.config.ts."
|
|
@@ -4729,7 +4730,7 @@ function planInit(root, flags = {}) {
|
|
|
4729
4730
|
throw emptyFlag("alias");
|
|
4730
4731
|
}
|
|
4731
4732
|
if (!ALIAS_NAME.test(alias)) {
|
|
4732
|
-
throw new
|
|
4733
|
+
throw new PenvError15(
|
|
4733
4734
|
"INIT_ALIAS_INVALID",
|
|
4734
4735
|
`\`${alias}\` is not an alias penv can write`,
|
|
4735
4736
|
`An alias is \`@name\` \u2014 a tsconfig \`paths\` entry a bundler resolves \u2014 or \`#name\`, a package.json \`imports\` entry Node resolves itself. Those are the two things a module specifier can be that is not a package.`
|
|
@@ -5063,7 +5064,7 @@ ${objectIndent}${source.slice(close)}`;
|
|
|
5063
5064
|
${entryIndent}${member},${source.slice(open + 1)}`;
|
|
5064
5065
|
}
|
|
5065
5066
|
function shapeError(what, target, alias) {
|
|
5066
|
-
return new
|
|
5067
|
+
return new PenvError15(
|
|
5067
5068
|
"TSCONFIG_SHAPE",
|
|
5068
5069
|
`penv cannot add the \`${alias}\` path alias to tsconfig.json: ${what}`,
|
|
5069
5070
|
`Add it by hand: \`{ "compilerOptions": { "paths": { "${alias}": ["${target}"] } } }\`.`
|
|
@@ -5405,7 +5406,7 @@ function planCutover(input) {
|
|
|
5405
5406
|
assertBundleResolved(root);
|
|
5406
5407
|
const selected = [...input.selected];
|
|
5407
5408
|
if (selected.length === 0) {
|
|
5408
|
-
throw new
|
|
5409
|
+
throw new PenvError15(
|
|
5409
5410
|
"INIT_NOTHING_SELECTED",
|
|
5410
5411
|
"No dotenv file was selected, so there is nothing to migrate",
|
|
5411
5412
|
"Run `penv init` again and choose the files penv should adopt."
|
|
@@ -5417,7 +5418,7 @@ function planCutover(input) {
|
|
|
5417
5418
|
const environments = declared === void 0 ? chosen : declared.environments;
|
|
5418
5419
|
for (const environment of chosen) {
|
|
5419
5420
|
if (!environments.includes(environment)) {
|
|
5420
|
-
throw new
|
|
5421
|
+
throw new PenvError15(
|
|
5421
5422
|
"INIT_ENVIRONMENT_UNDECLARED",
|
|
5422
5423
|
`${CONFIG_FILE} declares ${describeList(environments)}, and adopting these files needs \`${environment}\` declared too`,
|
|
5423
5424
|
`Add \`${environment}\` to \`environments\` in ${CONFIG_FILE}, with a provider for it, then run \`penv init\` again. Nothing was changed.`
|
|
@@ -5504,7 +5505,7 @@ function requireEnvironment(input) {
|
|
|
5504
5505
|
if (environment.length > 0) {
|
|
5505
5506
|
return environment;
|
|
5506
5507
|
}
|
|
5507
|
-
throw new
|
|
5508
|
+
throw new PenvError15(
|
|
5508
5509
|
"INIT_ENVIRONMENT_UNNAMED",
|
|
5509
5510
|
"The selected files name no environment, and penv does not invent one",
|
|
5510
5511
|
`Run \`penv init --env ${DEVELOPMENT}\` to say which environment these values are for.`
|
|
@@ -5516,7 +5517,7 @@ function assertCascadeComplete(root, selected, environments) {
|
|
|
5516
5517
|
for (const environment of environments) {
|
|
5517
5518
|
for (const name of cascadeFor(environment)) {
|
|
5518
5519
|
if (present.has(name) && !taken.has(name)) {
|
|
5519
|
-
throw new
|
|
5520
|
+
throw new PenvError15(
|
|
5520
5521
|
"INIT_CUTOVER_INCOMPLETE",
|
|
5521
5522
|
`${name} is part of ${environment}'s cascade and was not selected, so your framework would keep reading it beside penv`,
|
|
5522
5523
|
"Run `penv init` again and take every file penv listed for that environment. Nothing was changed."
|
|
@@ -5529,7 +5530,7 @@ function assertBundleResolved(root) {
|
|
|
5529
5530
|
if (!bundleUnresolved(root)) {
|
|
5530
5531
|
return;
|
|
5531
5532
|
}
|
|
5532
|
-
throw new
|
|
5533
|
+
throw new PenvError15(
|
|
5533
5534
|
"INIT_BUNDLE_UNRESOLVED",
|
|
5534
5535
|
`The dotenv files from the last cutover are still in ${ROLLBACK_DOTENV_PATH3}/, and penv will not migrate a second time over them`,
|
|
5535
5536
|
"Run `penv init undo` to put them back, or `penv cleanup` to drop them once you are happy with the migration."
|
|
@@ -5541,7 +5542,7 @@ function selectionForYes(plan2) {
|
|
|
5541
5542
|
(file) => file.environment !== void 0 && file.environment !== DEVELOPMENT
|
|
5542
5543
|
);
|
|
5543
5544
|
if (shared !== void 0 && other !== void 0) {
|
|
5544
|
-
throw new
|
|
5545
|
+
throw new PenvError15(
|
|
5545
5546
|
"INIT_YES_SHARED_FALLBACK",
|
|
5546
5547
|
`${other.name} falls back to the shared ${shared.name} this cutover would move, so \`--yes\` will not decide what happens to ${other.environment ?? ""}`,
|
|
5547
5548
|
"Run `penv init` without `--yes` and choose every file the cutover takes. Nothing was changed."
|
|
@@ -5587,7 +5588,7 @@ function issueLines(result2) {
|
|
|
5587
5588
|
}
|
|
5588
5589
|
var SCAFFOLD_ROLLED_BACK = "penv put the project back as it found it \u2014 your dotenv files and everything else are exactly where they were.";
|
|
5589
5590
|
function invalidAfterImport(result2) {
|
|
5590
|
-
return new
|
|
5591
|
+
return new PenvError15(
|
|
5591
5592
|
"INIT_CUTOVER_INVALID",
|
|
5592
5593
|
`The imported values do not satisfy the draft schema for ${result2.environment}:
|
|
5593
5594
|
${issueLines(result2)}`,
|
|
@@ -5595,7 +5596,7 @@ ${issueLines(result2)}`,
|
|
|
5595
5596
|
);
|
|
5596
5597
|
}
|
|
5597
5598
|
function draftNotLoaded(result2) {
|
|
5598
|
-
return new
|
|
5599
|
+
return new PenvError15(
|
|
5599
5600
|
"INIT_DRAFT_NOT_LOADED",
|
|
5600
5601
|
`penv could not load the schema it drafted for ${result2.environment}, so nothing was checked against it:
|
|
5601
5602
|
${issueLines(result2)}`,
|
|
@@ -5662,7 +5663,11 @@ function renderCutover(result2) {
|
|
|
5662
5663
|
const glyph = step.action === "conflicted" ? WARN : step.action === "info" ? "\u2192" : CHECK;
|
|
5663
5664
|
return step.note === void 0 ? { glyph, text: step.text } : { glyph, text: step.text, note: step.note };
|
|
5664
5665
|
}),
|
|
5665
|
-
...plan2.install
|
|
5666
|
+
...installedPackages(plan2.install).map((entry) => ({
|
|
5667
|
+
glyph: CHECK,
|
|
5668
|
+
text: `Installed ${entry.name}`,
|
|
5669
|
+
note: entry.version
|
|
5670
|
+
})),
|
|
5666
5671
|
{
|
|
5667
5672
|
glyph: CHECK,
|
|
5668
5673
|
text: `Imported ${plan2.fields.length} parameters`,
|
|
@@ -5735,7 +5740,7 @@ async function promptForSelection(plan2, io) {
|
|
|
5735
5740
|
for (const name of names) {
|
|
5736
5741
|
const file = plan2.found.find((candidate) => candidate.name === name);
|
|
5737
5742
|
if (file === void 0) {
|
|
5738
|
-
throw new
|
|
5743
|
+
throw new PenvError15(
|
|
5739
5744
|
"INIT_SELECTION_UNKNOWN",
|
|
5740
5745
|
`\`${name}\` is not one of the dotenv files penv found`,
|
|
5741
5746
|
"Run `penv init` again and name the files exactly as they are listed, e.g. `.env.production`."
|
|
@@ -5898,7 +5903,7 @@ var initCommand = defineCommand13({
|
|
|
5898
5903
|
});
|
|
5899
5904
|
function runUndoAction(root, action) {
|
|
5900
5905
|
if (action !== "undo") {
|
|
5901
|
-
throw new
|
|
5906
|
+
throw new PenvError15(
|
|
5902
5907
|
"INIT_UNKNOWN_ACTION",
|
|
5903
5908
|
`\`penv init ${action}\` is not something init does`,
|
|
5904
5909
|
"Run `penv init undo` to put back the dotenv files of the last cutover."
|
|
@@ -6004,7 +6009,7 @@ function explicitEnvironment(options, source, config) {
|
|
|
6004
6009
|
if (value.length > 0) {
|
|
6005
6010
|
return value;
|
|
6006
6011
|
}
|
|
6007
|
-
throw new
|
|
6012
|
+
throw new PenvError16(
|
|
6008
6013
|
"IMPORT_ENV_FLAG_EMPTY",
|
|
6009
6014
|
`\`--env\` for the import of ${source} names no environment`,
|
|
6010
6015
|
`Pass a declared environment \u2014 ${config.environments.map((e) => `\`${e}\``).join(", ")} \u2014 e.g. \`--env production\`, or drop \`--env\` to import ${source} as the scope that has no environment. Nothing was imported.`
|
|
@@ -6014,7 +6019,7 @@ function assertEnvironmentAgrees(derived, explicit, source) {
|
|
|
6014
6019
|
if (derived === void 0 || explicit === void 0 || derived === explicit) {
|
|
6015
6020
|
return;
|
|
6016
6021
|
}
|
|
6017
|
-
throw new
|
|
6022
|
+
throw new PenvError16(
|
|
6018
6023
|
"IMPORT_ENV_CONFLICT",
|
|
6019
6024
|
`The file ${source} is scoped to environment ${derived}, but \`--env ${explicit}\` names ${explicit}`,
|
|
6020
6025
|
`Drop \`--env\` to import ${source} as ${derived}, pass \`--env ${derived}\` to say the same thing twice, or point \`penv import\` at the file that holds ${explicit}'s values. Nothing was imported.`
|
|
@@ -6061,7 +6066,7 @@ function importDotenv(options) {
|
|
|
6061
6066
|
const cwd = resolve7(options.cwd);
|
|
6062
6067
|
const file = isAbsolute3(options.file) ? options.file : resolve7(cwd, options.file);
|
|
6063
6068
|
if (!existsSync7(file)) {
|
|
6064
|
-
throw new
|
|
6069
|
+
throw new PenvError16(
|
|
6065
6070
|
"IMPORT_FILE_MISSING",
|
|
6066
6071
|
`There is no file at ${file} to import`,
|
|
6067
6072
|
"Point `penv import` at an existing dotenv file, e.g. `penv import .env`."
|
|
@@ -6185,19 +6190,19 @@ var importCommand = defineCommand14({
|
|
|
6185
6190
|
|
|
6186
6191
|
// src/commands/key.ts
|
|
6187
6192
|
import { randomBytes } from "crypto";
|
|
6188
|
-
import { KEY_BYTES, KEYCHAIN_SERVICE, PenvError as
|
|
6193
|
+
import { KEY_BYTES, KEYCHAIN_SERVICE, PenvError as PenvError18 } from "@penvhq/core";
|
|
6189
6194
|
import { defineCommand as defineCommand15 } from "citty";
|
|
6190
6195
|
|
|
6191
6196
|
// src/keychain.ts
|
|
6192
6197
|
import { createRequire as createRequire3 } from "module";
|
|
6193
|
-
import { PenvError as
|
|
6198
|
+
import { PenvError as PenvError17 } from "@penvhq/core";
|
|
6194
6199
|
var KEYRING_MODULE = "@napi-rs/keyring";
|
|
6195
6200
|
var nodeRequire = (id) => createRequire3(import.meta.url)(id);
|
|
6196
6201
|
function firstLine2(cause) {
|
|
6197
6202
|
return (cause instanceof Error ? cause.message : String(cause)).split("\n")[0] ?? "";
|
|
6198
6203
|
}
|
|
6199
6204
|
function keyringMissing(cause) {
|
|
6200
|
-
return new
|
|
6205
|
+
return new PenvError17(
|
|
6201
6206
|
"KEYCHAIN_BINDING_MISSING",
|
|
6202
6207
|
`penv could not load ${KEYRING_MODULE}, the native binding it reads your OS keychain through`,
|
|
6203
6208
|
`This penv engine was installed as a plain tarball, which carries no native modules. Install penv with \`npm install -g @penvhq/launcher\`, or declare \`source: "env"\` for this environment and export its key. Original error: ${firstLine2(cause)}`
|
|
@@ -6239,7 +6244,7 @@ function runKeyCreate(options) {
|
|
|
6239
6244
|
const environment = targetEnvironment(project, options.environment);
|
|
6240
6245
|
const declared = project.config.keys?.[environment];
|
|
6241
6246
|
if (declared === void 0) {
|
|
6242
|
-
throw new
|
|
6247
|
+
throw new PenvError18(
|
|
6243
6248
|
"KEY_SOURCE_UNDECLARED",
|
|
6244
6249
|
`Environment ${environment} declares no key source, so penv does not know what a key for it would be`,
|
|
6245
6250
|
`Add a \`keys\` entry to penv.config.ts \u2014 e.g. \`keys: { ${environment}: { source: "env", id: "${environment}" } }\` \u2014 then run this again.`
|
|
@@ -6253,17 +6258,17 @@ function runKeyCreate(options) {
|
|
|
6253
6258
|
try {
|
|
6254
6259
|
existing = keychain.getPassword(KEYCHAIN_SERVICE, declared.id);
|
|
6255
6260
|
} catch (cause) {
|
|
6256
|
-
if (cause instanceof
|
|
6261
|
+
if (cause instanceof PenvError18) {
|
|
6257
6262
|
throw cause;
|
|
6258
6263
|
}
|
|
6259
|
-
throw new
|
|
6264
|
+
throw new PenvError18(
|
|
6260
6265
|
"KEYCHAIN_UNAVAILABLE",
|
|
6261
6266
|
`penv could not read your OS keychain to check for an existing key \`${declared.id}\``,
|
|
6262
6267
|
`Unlock your keychain and run this again. Original error: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
6263
6268
|
);
|
|
6264
6269
|
}
|
|
6265
6270
|
if (existing !== null) {
|
|
6266
|
-
throw new
|
|
6271
|
+
throw new PenvError18(
|
|
6267
6272
|
"KEY_EXISTS",
|
|
6268
6273
|
`Environment ${environment} already has a key \`${declared.id}\` in your OS keychain`,
|
|
6269
6274
|
"Replacing it would orphan every value already sealed under it \u2014 they could never be decrypted again. Re-run with `--force` only if you are certain nothing is sealed under the current key."
|
|
@@ -6432,7 +6437,7 @@ import {
|
|
|
6432
6437
|
loadConfig as loadConfig2,
|
|
6433
6438
|
oldLayoutEntries,
|
|
6434
6439
|
PENV_DIR as PENV_DIR3,
|
|
6435
|
-
PenvError as
|
|
6440
|
+
PenvError as PenvError19,
|
|
6436
6441
|
RECORDS_PATH as RECORDS_PATH5,
|
|
6437
6442
|
recordsDir as recordsDir3,
|
|
6438
6443
|
renderStateGitignore as renderStateGitignore2,
|
|
@@ -6447,7 +6452,7 @@ function planMigrate(cwd) {
|
|
|
6447
6452
|
const tree = recordsDir3(root);
|
|
6448
6453
|
const collisions = collidingEntries(entries, tree);
|
|
6449
6454
|
if (collisions.length > 0) {
|
|
6450
|
-
throw new
|
|
6455
|
+
throw new PenvError19(
|
|
6451
6456
|
"HALF_MIGRATED",
|
|
6452
6457
|
`${describe(collisions)} in both \`${PENV_DIR3}/\` and \`${RECORDS_PATH5}/\`, and penv cannot tell which copy is current`,
|
|
6453
6458
|
`Move what is left under \`${PENV_DIR3}/\` into \`${RECORDS_PATH5}/\` yourself, keeping the copy you want, then run \`penv validate\`.`
|
|
@@ -6588,7 +6593,7 @@ import {
|
|
|
6588
6593
|
formatMetaFile,
|
|
6589
6594
|
formatValueFile as formatValueFile6,
|
|
6590
6595
|
openValue as openValue4,
|
|
6591
|
-
PenvError as
|
|
6596
|
+
PenvError as PenvError20,
|
|
6592
6597
|
parameterId as parameterId7,
|
|
6593
6598
|
recordPath as recordPath7,
|
|
6594
6599
|
sealValue as sealValue3
|
|
@@ -6608,7 +6613,7 @@ async function planFile(project, source, target, parameter) {
|
|
|
6608
6613
|
}
|
|
6609
6614
|
const environment = environmentOf2(source);
|
|
6610
6615
|
if (environment === void 0) {
|
|
6611
|
-
throw new
|
|
6616
|
+
throw new PenvError20(
|
|
6612
6617
|
"SECRET_SCOPE_AMBIGUOUS",
|
|
6613
6618
|
`${recordPath7(formatValueFile6(source))} is encrypted at a scope that names no environment, so penv cannot tell which key would re-seal it`,
|
|
6614
6619
|
"Keys are declared per environment in the `keys` block of penv.config.ts. Decrypt it with `penv decrypt`, move the parameter, then encrypt it again at its new address."
|
|
@@ -6617,7 +6622,7 @@ async function planFile(project, source, target, parameter) {
|
|
|
6617
6622
|
const keys = keySourceFor(project, environment);
|
|
6618
6623
|
const opened = openValue4(source, stored, keys);
|
|
6619
6624
|
if (opened.kind === "failed") {
|
|
6620
|
-
throw new
|
|
6625
|
+
throw new PenvError20(
|
|
6621
6626
|
"VALUE_UNDECRYPTABLE",
|
|
6622
6627
|
`${recordPath7(formatValueFile6(source))} could not be decrypted, so penv cannot re-seal it at its new address: ${opened.failure.detail}`,
|
|
6623
6628
|
"A sealed value is bound to the file it lives in, so moving it means opening it and sealing it again. Make the key available and run this again. Nothing has been moved."
|
|
@@ -6640,7 +6645,7 @@ async function runMove(options) {
|
|
|
6640
6645
|
assertWritableKey(options.to);
|
|
6641
6646
|
const to = refFromKey(options.to, project.config);
|
|
6642
6647
|
if (parameterId7(from) === parameterId7(to)) {
|
|
6643
|
-
throw new
|
|
6648
|
+
throw new PenvError20(
|
|
6644
6649
|
"PARAMETER_UNCHANGED",
|
|
6645
6650
|
`\`${options.from}\` and \`${options.to}\` are the same parameter`,
|
|
6646
6651
|
"Name a different destination, e.g. `penv mv redis-password redis/password`."
|
|
@@ -6650,7 +6655,7 @@ async function runMove(options) {
|
|
|
6650
6655
|
const sources = filesOf(all, from);
|
|
6651
6656
|
const meta = await project.provider.readMeta(from);
|
|
6652
6657
|
if (sources.length === 0 && meta === void 0) {
|
|
6653
|
-
throw new
|
|
6658
|
+
throw new PenvError20(
|
|
6654
6659
|
"PARAMETER_ABSENT",
|
|
6655
6660
|
`Parameter ${parameterId7(from)} has no value files and no meta, so there is nothing to move`,
|
|
6656
6661
|
`\`penv list\` shows every parameter penv holds.`
|
|
@@ -6658,7 +6663,7 @@ async function runMove(options) {
|
|
|
6658
6663
|
}
|
|
6659
6664
|
const occupied2 = filesOf(all, to);
|
|
6660
6665
|
if (occupied2.length > 0 || await project.provider.readMeta(to) !== void 0) {
|
|
6661
|
-
throw new
|
|
6666
|
+
throw new PenvError20(
|
|
6662
6667
|
"PARAMETER_EXISTS",
|
|
6663
6668
|
`Parameter ${parameterId7(to)} already exists, and penv will not merge two parameters into one`,
|
|
6664
6669
|
`Remove or rename ${parameterId7(to)} first. \`penv get ${options.to} --explain\` shows every file it holds.`
|
|
@@ -6817,7 +6822,7 @@ import {
|
|
|
6817
6822
|
beginRotation,
|
|
6818
6823
|
completeRotation,
|
|
6819
6824
|
holdsRecords as holdsRecords2,
|
|
6820
|
-
PenvError as
|
|
6825
|
+
PenvError as PenvError21,
|
|
6821
6826
|
retainsPrevious,
|
|
6822
6827
|
rotationOf as rotationOf2
|
|
6823
6828
|
} from "@penvhq/core";
|
|
@@ -6846,7 +6851,7 @@ async function writeRotatedValue(project, provider, ref, environment, value) {
|
|
|
6846
6851
|
}
|
|
6847
6852
|
function requireNewValue(value, phase, key) {
|
|
6848
6853
|
if (value === void 0) {
|
|
6849
|
-
throw new
|
|
6854
|
+
throw new PenvError21(
|
|
6850
6855
|
"ROTATION_NO_VALUE",
|
|
6851
6856
|
`A ${phase} rotation of ${key} writes a new value, and none was given`,
|
|
6852
6857
|
"Pass the new value as the argument \u2014 `penv rotate <key> <value>` \u2014 or pipe it in on stdin."
|
|
@@ -6856,7 +6861,7 @@ function requireNewValue(value, phase, key) {
|
|
|
6856
6861
|
}
|
|
6857
6862
|
function requireRetaining(provider, environment) {
|
|
6858
6863
|
if (!retainsPrevious(provider)) {
|
|
6859
|
-
throw new
|
|
6864
|
+
throw new PenvError21(
|
|
6860
6865
|
"ROTATION_NOT_RETAINING",
|
|
6861
6866
|
`A dual-valid rotation needs the previous value to stay readable during the grace window, and the \`${provider.type}\` provider for environment ${environment} does not retain it`,
|
|
6862
6867
|
"Point this environment at a provider that keeps prior versions (its `readPrevious` is what penv reads during the window), or, if a momentary overlap is not required, declare the parameter `atomic-cutover` in its meta and flip it in one step."
|
|
@@ -6870,7 +6875,7 @@ async function runRotate(options) {
|
|
|
6870
6875
|
const ref = refFromKey(options.key, project.config);
|
|
6871
6876
|
const source = await sourceProviderFor(project, environment);
|
|
6872
6877
|
if (!holdsRecords2(source)) {
|
|
6873
|
-
throw new
|
|
6878
|
+
throw new PenvError21(
|
|
6874
6879
|
"ROTATION_NOT_RECORDS",
|
|
6875
6880
|
`Environment ${environment} is backed by \`${source.type}\`, which holds a resolved projection penv cannot rotate in place`,
|
|
6876
6881
|
"Rotate the parameter in the environment that holds the records (the local tree, Vault, SSM), then `penv push` the result to this destination."
|
|
@@ -6881,7 +6886,7 @@ async function runRotate(options) {
|
|
|
6881
6886
|
const before = await provider.readMeta(ref);
|
|
6882
6887
|
const { mechanism } = rotationOf2(before, environment);
|
|
6883
6888
|
if (mechanism === void 0) {
|
|
6884
|
-
throw new
|
|
6889
|
+
throw new PenvError21(
|
|
6885
6890
|
"ROTATION_NO_MECHANISM",
|
|
6886
6891
|
`Parameter ${options.key} declares no rotation mechanism for environment ${environment}, so penv does not know how to rotate it`,
|
|
6887
6892
|
'Set `rotationMechanism` in the parameter\'s meta to `"dual-valid"` (a grace-window overlap) or `"atomic-cutover"` (a single flip), then run `penv rotate` again.'
|
|
@@ -6891,7 +6896,7 @@ async function runRotate(options) {
|
|
|
6891
6896
|
const complete = options.complete === true;
|
|
6892
6897
|
if (mechanism === "atomic-cutover") {
|
|
6893
6898
|
if (begin || complete) {
|
|
6894
|
-
throw new
|
|
6899
|
+
throw new PenvError21(
|
|
6895
6900
|
"ROTATION_MECHANISM_MISMATCH",
|
|
6896
6901
|
`Parameter ${options.key} is atomic-cutover, which flips in one step, so \`--begin\`/\`--complete\` do not apply`,
|
|
6897
6902
|
"Run `penv rotate <key> <value>` with no phase flag to flip it. `--begin`/`--complete` bracket a dual-valid grace window, which atomic-cutover has none of."
|
|
@@ -6905,7 +6910,7 @@ async function runRotate(options) {
|
|
|
6905
6910
|
}
|
|
6906
6911
|
const retaining = requireRetaining(provider, environment);
|
|
6907
6912
|
if (begin === complete) {
|
|
6908
|
-
throw new
|
|
6913
|
+
throw new PenvError21(
|
|
6909
6914
|
"ROTATION_PHASE_REQUIRED",
|
|
6910
6915
|
`A dual-valid rotation of ${options.key} needs exactly one of \`--begin\` or \`--complete\``,
|
|
6911
6916
|
"`--begin` writes the new value and opens the grace window; `--complete` closes it once every reader has moved to the new value. Run them in that order, one at a time."
|