@penvhq/cli 0.2.0 → 0.3.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/dist/index.cjs +286 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -1
- package/dist/index.d.ts +71 -1
- package/dist/index.js +208 -61
- package/dist/index.js.map +1 -1
- package/package.json +10 -7
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
insertEnvAlias: () => insertEnvAlias,
|
|
27
27
|
main: () => main,
|
|
28
28
|
renderDoctor: () => renderDoctor,
|
|
29
|
+
renderFill: () => renderFill,
|
|
29
30
|
renderMove: () => renderMove,
|
|
30
31
|
renderPull: () => renderPull,
|
|
31
32
|
renderPush: () => renderPush,
|
|
@@ -35,6 +36,7 @@ __export(index_exports, {
|
|
|
35
36
|
runDoctor: () => runDoctor,
|
|
36
37
|
runEncrypt: () => runEncrypt,
|
|
37
38
|
runExplain: () => runExplain,
|
|
39
|
+
runFill: () => runFill,
|
|
38
40
|
runGenerate: () => runGenerate,
|
|
39
41
|
runGet: () => runGet,
|
|
40
42
|
runInit: () => runInit,
|
|
@@ -50,8 +52,8 @@ __export(index_exports, {
|
|
|
50
52
|
runWatch: () => runWatch
|
|
51
53
|
});
|
|
52
54
|
module.exports = __toCommonJS(index_exports);
|
|
53
|
-
var
|
|
54
|
-
var
|
|
55
|
+
var import_core22 = require("@penvhq/core");
|
|
56
|
+
var import_citty18 = require("citty");
|
|
55
57
|
|
|
56
58
|
// src/commands/doctor.ts
|
|
57
59
|
var import_core7 = require("@penvhq/core");
|
|
@@ -69,13 +71,20 @@ var import_node_path = require("path");
|
|
|
69
71
|
var import_node_url = require("url");
|
|
70
72
|
var import_core = require("@penvhq/core");
|
|
71
73
|
var import_provider_filesystem = require("@penvhq/provider-filesystem");
|
|
74
|
+
var import_provider_kubernetes = require("@penvhq/provider-kubernetes");
|
|
72
75
|
var import_provider_mock = require("@penvhq/provider-mock");
|
|
76
|
+
var import_provider_ssm = require("@penvhq/provider-ssm");
|
|
73
77
|
var import_provider_vault = require("@penvhq/provider-vault");
|
|
74
78
|
var PLUGIN_FACTORY_EXPORT = "penvProviderFactory";
|
|
75
79
|
var LOCAL_TREE_TYPE = "filesystem";
|
|
76
80
|
var REGISTRY = /* @__PURE__ */ new Map([
|
|
77
81
|
[LOCAL_TREE_TYPE, ({ root, config }) => (0, import_provider_filesystem.createFilesystemProvider)({ root, config })],
|
|
78
82
|
["vault", ({ providerConfig }) => (0, import_provider_vault.createVaultProvider)({ path: providerConfig?.path ?? "penv" })],
|
|
83
|
+
["ssm", ({ providerConfig }) => (0, import_provider_ssm.createSsmProvider)({ path: providerConfig?.path ?? "penv" })],
|
|
84
|
+
[
|
|
85
|
+
"kubernetes",
|
|
86
|
+
({ providerConfig }) => (0, import_provider_kubernetes.createKubernetesProvider)(kubernetesOptions(providerConfig))
|
|
87
|
+
],
|
|
79
88
|
["mock", ({ root }) => (0, import_provider_mock.createMockProvider)({ storePath: (0, import_node_path.resolve)(root, ".penv-mock.json") })]
|
|
80
89
|
]);
|
|
81
90
|
var CONTRACT_METHODS = [
|
|
@@ -178,6 +187,14 @@ function assertSatisfiesContract(provider, specifier) {
|
|
|
178
187
|
}
|
|
179
188
|
}
|
|
180
189
|
}
|
|
190
|
+
function kubernetesOptions(providerConfig) {
|
|
191
|
+
const path = providerConfig?.path ?? "penv";
|
|
192
|
+
const slash = path.indexOf("/");
|
|
193
|
+
if (slash === -1) return { secretName: path };
|
|
194
|
+
const namespace = path.slice(0, slash);
|
|
195
|
+
const secretName = path.slice(slash + 1) || "penv";
|
|
196
|
+
return namespace === "" ? { secretName } : { namespace, secretName };
|
|
197
|
+
}
|
|
181
198
|
function unknownProvider(type, environment, specifier) {
|
|
182
199
|
const known = [...REGISTRY.keys()].map((name) => `\`${name}\``).join(", ");
|
|
183
200
|
const where = environment === void 0 ? "" : ` for environment ${environment}`;
|
|
@@ -246,6 +263,26 @@ function refFromKey(key, config) {
|
|
|
246
263
|
}
|
|
247
264
|
return { namespace: segments.slice(0, -1), name };
|
|
248
265
|
}
|
|
266
|
+
function assertWritableKey(key) {
|
|
267
|
+
const segments = key.split(KEY_SEPARATOR).filter((s) => s.length > 0);
|
|
268
|
+
if (segments.length === 0 || segments.every((s) => (0, import_core2.isCanonicalSegment)(s))) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const ref = (0, import_core2.refFromAccessPath)(segments);
|
|
272
|
+
if (ref !== void 0) {
|
|
273
|
+
const suggestion = [...ref.namespace, ref.name].join("/");
|
|
274
|
+
throw new import_core2.PenvError(
|
|
275
|
+
"PARAMETER_KEY_CASING",
|
|
276
|
+
`\`${key}\` is not a canonical parameter name`,
|
|
277
|
+
`Parameter files are lower-case and hyphenated. Did you mean \`${suggestion}\`? That is the file that backs the \`${key}\` key in your schema.`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
throw new import_core2.PenvError(
|
|
281
|
+
"PARAMETER_KEY_UNREACHABLE",
|
|
282
|
+
`No value file can be named that reaches \`${key}\``,
|
|
283
|
+
"Parameter files are lower-case and hyphenated, and this key maps to no such file \u2014 a run of capitals like `apiURL` cannot be reached (use `api-url`, which the schema reads as `apiUrl`). Run `penv validate` or `penv fill` to see the names penv expects."
|
|
284
|
+
);
|
|
285
|
+
}
|
|
249
286
|
function keySourceFor(project, environment) {
|
|
250
287
|
return (0, import_core2.resolveKeySource)(project.config, environment);
|
|
251
288
|
}
|
|
@@ -665,7 +702,6 @@ var import_node_path3 = require("path");
|
|
|
665
702
|
var import_node_url2 = require("url");
|
|
666
703
|
var import_core6 = require("@penvhq/core");
|
|
667
704
|
var import_citty2 = require("citty");
|
|
668
|
-
var import_jiti = require("jiti");
|
|
669
705
|
var SCHEMA_EXPORT = "schema";
|
|
670
706
|
var LABELS = {
|
|
671
707
|
config: "Config",
|
|
@@ -744,7 +780,7 @@ function loadSchema(project, environment) {
|
|
|
744
780
|
return exclusively(() => loadSchemaExclusively(file, schemaPath, environment));
|
|
745
781
|
}
|
|
746
782
|
async function loadSchemaExclusively(file, schemaPath, environment) {
|
|
747
|
-
const jiti = (0,
|
|
783
|
+
const jiti = (0, import_core6.jitiFor)(file);
|
|
748
784
|
const previous = process.env.PENV_ENV;
|
|
749
785
|
process.env.PENV_ENV = environment;
|
|
750
786
|
let loaded;
|
|
@@ -1739,6 +1775,7 @@ async function sealAwareWrite(options) {
|
|
|
1739
1775
|
}
|
|
1740
1776
|
async function runSet(options) {
|
|
1741
1777
|
const project = openProject(options.cwd);
|
|
1778
|
+
assertWritableKey(options.key);
|
|
1742
1779
|
const ref = refFromKey(options.key, project.config);
|
|
1743
1780
|
const scope = targetScope(project, options, options.key);
|
|
1744
1781
|
const environment = policyEnvironment(project, options);
|
|
@@ -1941,17 +1978,122 @@ var decryptCommand = (0, import_citty5.defineCommand)({
|
|
|
1941
1978
|
}
|
|
1942
1979
|
});
|
|
1943
1980
|
|
|
1981
|
+
// src/commands/fill.ts
|
|
1982
|
+
var import_promises = require("readline/promises");
|
|
1983
|
+
var import_core10 = require("@penvhq/core");
|
|
1984
|
+
var import_citty6 = require("citty");
|
|
1985
|
+
var BLOCKING = /* @__PURE__ */ new Set(["config", "collision", "reserved"]);
|
|
1986
|
+
async function runFill(options) {
|
|
1987
|
+
const validation = await runValidate({
|
|
1988
|
+
cwd: options.cwd,
|
|
1989
|
+
...options.environment === void 0 ? {} : { environment: options.environment }
|
|
1990
|
+
});
|
|
1991
|
+
const environment = validation.environment;
|
|
1992
|
+
const blockers = validation.issues.filter((issue) => BLOCKING.has(issue.kind));
|
|
1993
|
+
if (blockers.length > 0) {
|
|
1994
|
+
const detail = blockers.map(
|
|
1995
|
+
(issue) => ` - ${issue.message}${issue.remedy === void 0 ? "" : ` (${issue.remedy})`}`
|
|
1996
|
+
).join("\n");
|
|
1997
|
+
throw new import_core10.PenvError(
|
|
1998
|
+
"FILL_BLOCKED",
|
|
1999
|
+
`penv fill cannot run: environment ${environment} has ${blockers.length} unresolved configuration ${blockers.length === 1 ? "issue" : "issues"}:
|
|
2000
|
+
${detail}`,
|
|
2001
|
+
`Fix these \u2014 \`penv validate\` reports them \u2014 then run \`penv fill\`. If you have not written a schema yet, declare the required parameters in ${PENV_DIR}/env.ts.`
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
const written = [];
|
|
2005
|
+
const skipped2 = [];
|
|
2006
|
+
const unreachable = [];
|
|
2007
|
+
for (const drift of validation.drift.declared) {
|
|
2008
|
+
if (drift.ref === void 0) {
|
|
2009
|
+
unreachable.push({ subject: drift.subject, remedy: drift.remedy });
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
const ref = drift.ref;
|
|
2013
|
+
const key = [...ref.namespace, ref.name].join("/");
|
|
2014
|
+
const value = await options.ask({ parameter: key, environment, secret: false });
|
|
2015
|
+
if (value === void 0 || value === "") {
|
|
2016
|
+
skipped2.push(drift.subject);
|
|
2017
|
+
continue;
|
|
2018
|
+
}
|
|
2019
|
+
const result2 = await runSet({ cwd: options.cwd, key, value, environment });
|
|
2020
|
+
written.push({
|
|
2021
|
+
parameter: drift.subject,
|
|
2022
|
+
location: result2.location,
|
|
2023
|
+
encrypted: result2.encrypted
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
return { environment, written, skipped: skipped2, unreachable };
|
|
2027
|
+
}
|
|
2028
|
+
function summaryLine(result2) {
|
|
2029
|
+
const filled = result2.written.length;
|
|
2030
|
+
if (filled === 0 && result2.skipped.length === 0 && result2.unreachable.length === 0) {
|
|
2031
|
+
return `Nothing to fill for environment ${result2.environment}: every declared parameter has a value`;
|
|
2032
|
+
}
|
|
2033
|
+
const parts = [`${filled} written`];
|
|
2034
|
+
if (result2.skipped.length > 0) {
|
|
2035
|
+
parts.push(`${result2.skipped.length} skipped`);
|
|
2036
|
+
}
|
|
2037
|
+
if (result2.unreachable.length > 0) {
|
|
2038
|
+
parts.push(`${result2.unreachable.length} unreachable`);
|
|
2039
|
+
}
|
|
2040
|
+
return `${parts.join(", ")} for environment ${result2.environment}`;
|
|
2041
|
+
}
|
|
2042
|
+
function renderFill(result2) {
|
|
2043
|
+
const rows = result2.written.map((entry) => ({
|
|
2044
|
+
glyph: CHECK,
|
|
2045
|
+
label: "Wrote",
|
|
2046
|
+
subject: `${PENV_DIR}/${entry.location}`,
|
|
2047
|
+
// Meta decided the seal, not the answer, so the line says so — as `set` does.
|
|
2048
|
+
...entry.encrypted ? { detail: "encrypted, per the parameter's meta policy" } : {}
|
|
2049
|
+
}));
|
|
2050
|
+
for (const entry of result2.unreachable) {
|
|
2051
|
+
rows.push({ glyph: WARN, label: "Unreachable", subject: entry.subject, detail: entry.remedy });
|
|
2052
|
+
}
|
|
2053
|
+
const lines = formatRows(rows);
|
|
2054
|
+
lines.push(summaryLine(result2));
|
|
2055
|
+
return lines;
|
|
2056
|
+
}
|
|
2057
|
+
var fillCommand = (0, import_citty6.defineCommand)({
|
|
2058
|
+
meta: {
|
|
2059
|
+
name: "fill",
|
|
2060
|
+
description: "Prompt for each declared parameter the tree has no value for"
|
|
2061
|
+
},
|
|
2062
|
+
args: {
|
|
2063
|
+
env: { type: "string", description: "The environment to fill" }
|
|
2064
|
+
},
|
|
2065
|
+
run({ args }) {
|
|
2066
|
+
return guard(async () => {
|
|
2067
|
+
const rl = (0, import_promises.createInterface)({ input: process.stdin, output: process.stdout });
|
|
2068
|
+
const ask = (prompt) => rl.question(`${prompt.parameter} (${prompt.environment}): `);
|
|
2069
|
+
try {
|
|
2070
|
+
write(
|
|
2071
|
+
renderFill(
|
|
2072
|
+
await runFill({
|
|
2073
|
+
cwd: process.cwd(),
|
|
2074
|
+
...args.env === void 0 ? {} : { environment: args.env },
|
|
2075
|
+
ask
|
|
2076
|
+
})
|
|
2077
|
+
)
|
|
2078
|
+
);
|
|
2079
|
+
} finally {
|
|
2080
|
+
rl.close();
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
});
|
|
2085
|
+
|
|
1944
2086
|
// src/commands/generate.ts
|
|
1945
2087
|
var import_node_fs = require("fs");
|
|
1946
2088
|
var import_node_path4 = require("path");
|
|
1947
|
-
var
|
|
1948
|
-
var
|
|
2089
|
+
var import_core11 = require("@penvhq/core");
|
|
2090
|
+
var import_citty7 = require("citty");
|
|
1949
2091
|
var DEFAULT_OUTPUT = ".env";
|
|
1950
2092
|
function entriesFor(project, environment, allowDecrypt) {
|
|
1951
2093
|
const keys = keySourceFor(project, environment);
|
|
1952
2094
|
const tree = localTree(project);
|
|
1953
2095
|
const resolutions = resolveAllSync(tree, environment, keys);
|
|
1954
|
-
const collision = (0,
|
|
2096
|
+
const collision = (0, import_core11.checkNameCollisions)(
|
|
1955
2097
|
refsFrom(resolutions.map((resolution) => resolution.ref)),
|
|
1956
2098
|
project.config
|
|
1957
2099
|
)[0];
|
|
@@ -1964,21 +2106,21 @@ function entriesFor(project, environment, allowDecrypt) {
|
|
|
1964
2106
|
const winner = resolution.winner;
|
|
1965
2107
|
if (winner?.file.encrypted === true) {
|
|
1966
2108
|
if (!allowDecrypt) {
|
|
1967
|
-
throw new
|
|
2109
|
+
throw new import_core11.PenvError(
|
|
1968
2110
|
"ENCRYPTED_VALUE_REFUSED",
|
|
1969
2111
|
`Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${PENV_DIR}/${winner.location}, and \`penv generate\` writes plaintext`,
|
|
1970
2112
|
`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.`
|
|
1971
2113
|
);
|
|
1972
2114
|
}
|
|
1973
|
-
(0,
|
|
2115
|
+
(0, import_core11.requireValue)(resolution, environment);
|
|
1974
2116
|
decrypted += 1;
|
|
1975
2117
|
}
|
|
1976
2118
|
if (resolution.value === void 0) {
|
|
1977
2119
|
continue;
|
|
1978
2120
|
}
|
|
1979
|
-
const description = (0,
|
|
2121
|
+
const description = (0, import_core11.effectiveMeta)(tree.readMetaSync(resolution.ref), environment).description;
|
|
1980
2122
|
entries.push({
|
|
1981
|
-
key: (0,
|
|
2123
|
+
key: (0, import_core11.variableName)(resolution.ref, project.config),
|
|
1982
2124
|
value: resolution.value,
|
|
1983
2125
|
...typeof description === "string" ? { description } : {}
|
|
1984
2126
|
});
|
|
@@ -1989,14 +2131,14 @@ function entriesFor(project, environment, allowDecrypt) {
|
|
|
1989
2131
|
function generateDotenv(options) {
|
|
1990
2132
|
const project = openProject(options.cwd);
|
|
1991
2133
|
const environment = targetEnvironment(project, options.environment);
|
|
1992
|
-
return (0,
|
|
2134
|
+
return (0, import_core11.serializeDotenv)(entriesFor(project, environment, options.allowDecrypt === true).entries);
|
|
1993
2135
|
}
|
|
1994
2136
|
function runGenerate(options) {
|
|
1995
2137
|
const project = openProject(options.cwd);
|
|
1996
2138
|
const environment = targetEnvironment(project, options.environment);
|
|
1997
2139
|
const { entries, decrypted } = entriesFor(project, environment, options.allowDecrypt === true);
|
|
1998
2140
|
const file = options.out === void 0 ? (0, import_node_path4.resolve)(project.root, DEFAULT_OUTPUT) : (0, import_node_path4.isAbsolute)(options.out) ? options.out : (0, import_node_path4.resolve)(options.cwd, options.out);
|
|
1999
|
-
(0, import_node_fs.writeFileSync)(file, (0,
|
|
2141
|
+
(0, import_node_fs.writeFileSync)(file, (0, import_core11.serializeDotenv)(entries), "utf8");
|
|
2000
2142
|
return { file, environment, entries: entries.length, decrypted };
|
|
2001
2143
|
}
|
|
2002
2144
|
function displayPath(cwd, file) {
|
|
@@ -2022,7 +2164,7 @@ function renderGenerate(result2, cwd) {
|
|
|
2022
2164
|
}
|
|
2023
2165
|
return formatRows(rows);
|
|
2024
2166
|
}
|
|
2025
|
-
var generateCommand = (0,
|
|
2167
|
+
var generateCommand = (0, import_citty7.defineCommand)({
|
|
2026
2168
|
meta: { name: "generate", description: "Write a standard .env artifact for deploy targets" },
|
|
2027
2169
|
args: {
|
|
2028
2170
|
env: { type: "string", description: "The environment to generate for" },
|
|
@@ -2047,17 +2189,17 @@ var generateCommand = (0, import_citty6.defineCommand)({
|
|
|
2047
2189
|
});
|
|
2048
2190
|
|
|
2049
2191
|
// src/commands/get.ts
|
|
2050
|
-
var
|
|
2051
|
-
var
|
|
2192
|
+
var import_core12 = require("@penvhq/core");
|
|
2193
|
+
var import_citty8 = require("citty");
|
|
2052
2194
|
async function runGet(options) {
|
|
2053
2195
|
const project = openProject(options.cwd);
|
|
2054
2196
|
const environment = targetEnvironment(project, options.environment);
|
|
2055
2197
|
const ref = refFromKey(options.key);
|
|
2056
2198
|
const keys = keySourceFor(project, environment);
|
|
2057
|
-
const resolution = await (0,
|
|
2058
|
-
const value = (0,
|
|
2199
|
+
const resolution = await (0, import_core12.resolveParameter)(ref, environment, project.provider, keys);
|
|
2200
|
+
const value = (0, import_core12.requireValue)(resolution, environment);
|
|
2059
2201
|
if (value === void 0) {
|
|
2060
|
-
throw new
|
|
2202
|
+
throw new import_core12.PenvError(
|
|
2061
2203
|
"PARAMETER_ABSENT",
|
|
2062
2204
|
`Parameter ${resolution.parameter} resolves to no value for environment ${environment}`,
|
|
2063
2205
|
`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.`
|
|
@@ -2079,7 +2221,7 @@ async function runExplain(options) {
|
|
|
2079
2221
|
const environment = targetEnvironment(project, options.environment);
|
|
2080
2222
|
const ref = refFromKey(options.key);
|
|
2081
2223
|
const keys = keySourceFor(project, environment);
|
|
2082
|
-
const resolution = await (0,
|
|
2224
|
+
const resolution = await (0, import_core12.resolveParameter)(ref, environment, project.provider, keys);
|
|
2083
2225
|
const winner = resolution.winner;
|
|
2084
2226
|
return {
|
|
2085
2227
|
parameter: resolution.parameter,
|
|
@@ -2107,7 +2249,7 @@ function renderExplain(explanation) {
|
|
|
2107
2249
|
...columns(rows).map((line) => ` ${line}`)
|
|
2108
2250
|
];
|
|
2109
2251
|
}
|
|
2110
|
-
var getCommand = (0,
|
|
2252
|
+
var getCommand = (0, import_citty8.defineCommand)({
|
|
2111
2253
|
meta: { name: "get", description: "Read a parameter" },
|
|
2112
2254
|
args: {
|
|
2113
2255
|
key: { type: "positional", required: true, description: "The parameter, e.g. redis/password" },
|
|
@@ -2133,13 +2275,13 @@ var getCommand = (0, import_citty7.defineCommand)({
|
|
|
2133
2275
|
// src/commands/import.ts
|
|
2134
2276
|
var import_node_fs4 = require("fs");
|
|
2135
2277
|
var import_node_path7 = require("path");
|
|
2136
|
-
var
|
|
2137
|
-
var
|
|
2278
|
+
var import_core15 = require("@penvhq/core");
|
|
2279
|
+
var import_citty10 = require("citty");
|
|
2138
2280
|
|
|
2139
2281
|
// src/detect.ts
|
|
2140
2282
|
var import_node_fs2 = require("fs");
|
|
2141
2283
|
var import_node_path5 = require("path");
|
|
2142
|
-
var
|
|
2284
|
+
var import_core13 = require("@penvhq/core");
|
|
2143
2285
|
var SIGNATURES = [
|
|
2144
2286
|
{ name: "Next.js", packages: ["next"], publicPrefixes: ["NEXT_PUBLIC_"] },
|
|
2145
2287
|
{
|
|
@@ -2177,7 +2319,7 @@ function schemaFileFor(cwd) {
|
|
|
2177
2319
|
if (!occupied(cwd, beside)) {
|
|
2178
2320
|
return { file: beside, displaced: preferred };
|
|
2179
2321
|
}
|
|
2180
|
-
return { file:
|
|
2322
|
+
return { file: import_core13.DEFAULT_SCHEMA_FILE, displaced: preferred };
|
|
2181
2323
|
}
|
|
2182
2324
|
function dependenciesOf(cwd) {
|
|
2183
2325
|
const manifest = manifestOf(cwd);
|
|
@@ -2240,9 +2382,9 @@ function hasImportsBlock(cwd) {
|
|
|
2240
2382
|
// src/commands/init.ts
|
|
2241
2383
|
var import_node_fs3 = require("fs");
|
|
2242
2384
|
var import_node_path6 = require("path");
|
|
2243
|
-
var
|
|
2244
|
-
var
|
|
2245
|
-
var
|
|
2385
|
+
var import_promises2 = require("readline/promises");
|
|
2386
|
+
var import_core14 = require("@penvhq/core");
|
|
2387
|
+
var import_citty9 = require("citty");
|
|
2246
2388
|
var CONFIG_FILE = "penv.config.ts";
|
|
2247
2389
|
var TSCONFIG_FILE = "tsconfig.json";
|
|
2248
2390
|
var GITIGNORE_FILE = ".gitignore";
|
|
@@ -2252,11 +2394,11 @@ var IMPORTS_PREFIX = "#";
|
|
|
2252
2394
|
var PACKAGE_FILE = "package.json";
|
|
2253
2395
|
var DEFAULT_DECISIONS = {
|
|
2254
2396
|
environments: [],
|
|
2255
|
-
schemaFile:
|
|
2397
|
+
schemaFile: import_core14.DEFAULT_SCHEMA_FILE,
|
|
2256
2398
|
publicPrefixes: [],
|
|
2257
2399
|
alias: DEFAULT_ALIAS
|
|
2258
2400
|
};
|
|
2259
|
-
var NOT_ENVIRONMENTS = [...
|
|
2401
|
+
var NOT_ENVIRONMENTS = [...import_core14.RESERVED_TOKENS, "example", "sample", "template"];
|
|
2260
2402
|
function suggestEnvironments(root) {
|
|
2261
2403
|
let entries;
|
|
2262
2404
|
try {
|
|
@@ -2272,7 +2414,7 @@ function suggestEnvironments(root) {
|
|
|
2272
2414
|
const segments = entry.slice(".env.".length).split(".");
|
|
2273
2415
|
const withoutLocal = segments.at(-1) === "local" ? segments.slice(0, -1) : segments;
|
|
2274
2416
|
const name = withoutLocal.length === 1 ? withoutLocal[0] : void 0;
|
|
2275
|
-
if (name === void 0 || !(0,
|
|
2417
|
+
if (name === void 0 || !(0, import_core14.isLegalEnvironmentName)(name) || NOT_ENVIRONMENTS.includes(name)) {
|
|
2276
2418
|
continue;
|
|
2277
2419
|
}
|
|
2278
2420
|
found.add(name);
|
|
@@ -2280,10 +2422,10 @@ function suggestEnvironments(root) {
|
|
|
2280
2422
|
return [...found].sort();
|
|
2281
2423
|
}
|
|
2282
2424
|
function emptyFlag(flag) {
|
|
2283
|
-
return new
|
|
2425
|
+
return new import_core14.PenvError(
|
|
2284
2426
|
"INIT_FLAG_EMPTY",
|
|
2285
2427
|
`\`--${flag}\` was given without a value`,
|
|
2286
|
-
flag === "schema" ? `Name the module that exports the schema, e.g. \`--schema src/env.ts\`, or drop the flag to use ${
|
|
2428
|
+
flag === "schema" ? `Name the module that exports the schema, e.g. \`--schema src/env.ts\`, or drop the flag to use ${import_core14.DEFAULT_SCHEMA_FILE}.` : "Name the environment, e.g. `--env production`, or drop the flag to leave the whitelist empty and declare it in penv.config.ts."
|
|
2287
2429
|
);
|
|
2288
2430
|
}
|
|
2289
2431
|
function splitEnvironments(value) {
|
|
@@ -2308,7 +2450,7 @@ function declaredIn(root) {
|
|
|
2308
2450
|
if (!(0, import_node_fs3.existsSync)(file)) {
|
|
2309
2451
|
return void 0;
|
|
2310
2452
|
}
|
|
2311
|
-
return (0,
|
|
2453
|
+
return (0, import_core14.loadConfigFrom)(file);
|
|
2312
2454
|
}
|
|
2313
2455
|
function planInit(root, flags = {}) {
|
|
2314
2456
|
const declared = declaredIn(root);
|
|
@@ -2318,7 +2460,7 @@ function planInit(root, flags = {}) {
|
|
|
2318
2460
|
notes.push(`${CONFIG_FILE} already exists \u2014 init keeps every decision it records.`);
|
|
2319
2461
|
} else if (detected === void 0) {
|
|
2320
2462
|
notes.push(
|
|
2321
|
-
`No framework detected in package.json \u2014 the schema goes to ${
|
|
2463
|
+
`No framework detected in package.json \u2014 the schema goes to ${import_core14.DEFAULT_SCHEMA_FILE}.`
|
|
2322
2464
|
);
|
|
2323
2465
|
} else {
|
|
2324
2466
|
notes.push(`Detected ${detected.name}.`);
|
|
@@ -2328,12 +2470,12 @@ function planInit(root, flags = {}) {
|
|
|
2328
2470
|
);
|
|
2329
2471
|
}
|
|
2330
2472
|
}
|
|
2331
|
-
const schemaFile = flags.schema === void 0 ? declared !== void 0 ? (0,
|
|
2473
|
+
const schemaFile = flags.schema === void 0 ? declared !== void 0 ? (0, import_core14.schemaFileOf)(declared) : detected?.schemaFile ?? import_core14.DEFAULT_SCHEMA_FILE : flags.schema.trim();
|
|
2332
2474
|
if (flags.schema !== void 0) {
|
|
2333
2475
|
if (schemaFile.length === 0) {
|
|
2334
2476
|
throw emptyFlag("schema");
|
|
2335
2477
|
}
|
|
2336
|
-
const error = (0,
|
|
2478
|
+
const error = (0, import_core14.validateSchemaFile)({ environments: [], providers: {}, schemaFile })[0];
|
|
2337
2479
|
if (error !== void 0) {
|
|
2338
2480
|
throw error;
|
|
2339
2481
|
}
|
|
@@ -2343,7 +2485,7 @@ function planInit(root, flags = {}) {
|
|
|
2343
2485
|
throw emptyFlag("alias");
|
|
2344
2486
|
}
|
|
2345
2487
|
if (!ALIAS_NAME.test(alias)) {
|
|
2346
|
-
throw new
|
|
2488
|
+
throw new import_core14.PenvError(
|
|
2347
2489
|
"INIT_ALIAS_INVALID",
|
|
2348
2490
|
`\`${alias}\` is not an alias penv can write`,
|
|
2349
2491
|
`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.`
|
|
@@ -2388,7 +2530,7 @@ function renderPlan(plan2) {
|
|
|
2388
2530
|
rows.push([
|
|
2389
2531
|
" schemaFile",
|
|
2390
2532
|
plan2.decisions.schemaFile,
|
|
2391
|
-
plan2.decisions.schemaFile ===
|
|
2533
|
+
plan2.decisions.schemaFile === import_core14.DEFAULT_SCHEMA_FILE ? "" : `(default: ${import_core14.DEFAULT_SCHEMA_FILE})`
|
|
2392
2534
|
]);
|
|
2393
2535
|
for (const prefix of plan2.decisions.publicPrefixes) {
|
|
2394
2536
|
rows.push([" publicPrefix", prefix, ""]);
|
|
@@ -2462,7 +2604,7 @@ ${providers} },
|
|
|
2462
2604
|
}
|
|
2463
2605
|
function renderConfigModule(decisions) {
|
|
2464
2606
|
let body = renderEnvironments(decisions);
|
|
2465
|
-
if (decisions.schemaFile !==
|
|
2607
|
+
if (decisions.schemaFile !== import_core14.DEFAULT_SCHEMA_FILE) {
|
|
2466
2608
|
body += `
|
|
2467
2609
|
// The module that exports the schema. It is yours \u2014 penv scaffolds it once
|
|
2468
2610
|
// and never regenerates it \u2014 so this says where you keep it.
|
|
@@ -2485,7 +2627,7 @@ ${body}});
|
|
|
2485
2627
|
`;
|
|
2486
2628
|
}
|
|
2487
2629
|
function renderGitignore(decisions) {
|
|
2488
|
-
const inside = (0,
|
|
2630
|
+
const inside = (0, import_core14.schemaInsideTree)(configOf(decisions));
|
|
2489
2631
|
const listed = inside === void 0 ? "" : `${inside}, `;
|
|
2490
2632
|
return `# Written by penv. Value files hold configuration values and are never
|
|
2491
2633
|
# committed; only the structure, ${listed}meta, and config are.
|
|
@@ -2630,13 +2772,13 @@ ${objectIndent}${source.slice(close)}`;
|
|
|
2630
2772
|
${entryIndent}${member},${source.slice(open + 1)}`;
|
|
2631
2773
|
}
|
|
2632
2774
|
function shapeError(what, target, alias) {
|
|
2633
|
-
return new
|
|
2775
|
+
return new import_core14.PenvError(
|
|
2634
2776
|
"TSCONFIG_SHAPE",
|
|
2635
2777
|
`penv cannot add the \`${alias}\` path alias to tsconfig.json: ${what}`,
|
|
2636
2778
|
`Add it by hand: \`{ "compilerOptions": { "paths": { "${alias}": ["${target}"] } } }\`.`
|
|
2637
2779
|
);
|
|
2638
2780
|
}
|
|
2639
|
-
function insertEnvAlias(source, target =
|
|
2781
|
+
function insertEnvAlias(source, target = import_core14.DEFAULT_SCHEMA_FILE, name = DEFAULT_ALIAS) {
|
|
2640
2782
|
const alias = `"${name}": ["${target}"]`;
|
|
2641
2783
|
const root = skipTrivia(source, 0);
|
|
2642
2784
|
if (source.charAt(root) !== "{") {
|
|
@@ -2824,7 +2966,7 @@ function renderInit(result2) {
|
|
|
2824
2966
|
];
|
|
2825
2967
|
}
|
|
2826
2968
|
async function askOnTty(plan2) {
|
|
2827
|
-
const rl = (0,
|
|
2969
|
+
const rl = (0, import_promises2.createInterface)({ input: process.stdin, output: process.stdout });
|
|
2828
2970
|
try {
|
|
2829
2971
|
return await promptForDecisions(plan2, {
|
|
2830
2972
|
ask: (question) => rl.question(question),
|
|
@@ -2835,7 +2977,7 @@ async function askOnTty(plan2) {
|
|
|
2835
2977
|
rl.close();
|
|
2836
2978
|
}
|
|
2837
2979
|
}
|
|
2838
|
-
var initCommand = (0,
|
|
2980
|
+
var initCommand = (0, import_citty9.defineCommand)({
|
|
2839
2981
|
meta: { name: "init", description: "Initialize a project (.penv/, env.ts, config, @env alias)" },
|
|
2840
2982
|
args: {
|
|
2841
2983
|
yes: {
|
|
@@ -2844,7 +2986,7 @@ var initCommand = (0, import_citty8.defineCommand)({
|
|
|
2844
2986
|
},
|
|
2845
2987
|
schema: {
|
|
2846
2988
|
type: "string",
|
|
2847
|
-
description: `Where the schema module goes, e.g. src/env.ts (default: ${
|
|
2989
|
+
description: `Where the schema module goes, e.g. src/env.ts (default: ${import_core14.DEFAULT_SCHEMA_FILE})`
|
|
2848
2990
|
},
|
|
2849
2991
|
alias: {
|
|
2850
2992
|
type: "string",
|
|
@@ -2898,7 +3040,7 @@ function inferType(value) {
|
|
|
2898
3040
|
}
|
|
2899
3041
|
function draftFields(entries) {
|
|
2900
3042
|
return entries.map((entry) => {
|
|
2901
|
-
const key = (0,
|
|
3043
|
+
const key = (0, import_core15.accessPath)((0, import_core15.refFromVariable)(entry.key)).join(".");
|
|
2902
3044
|
return {
|
|
2903
3045
|
key: IDENTIFIER.test(key) ? key : JSON.stringify(key),
|
|
2904
3046
|
type: inferType(entry.value)
|
|
@@ -2909,33 +3051,33 @@ function assertImportable(ref, variable) {
|
|
|
2909
3051
|
if (!ref.name.includes(".")) {
|
|
2910
3052
|
return;
|
|
2911
3053
|
}
|
|
2912
|
-
throw new
|
|
3054
|
+
throw new import_core15.PenvError(
|
|
2913
3055
|
"IMPORT_UNPARSEABLE_NAME",
|
|
2914
3056
|
`The variable ${variable} becomes the parameter \`${ref.name}\`, whose \`.\` would be read as a scope`,
|
|
2915
3057
|
`Filenames are split on \`.\`. Rename ${variable} in the source file, then import it again.`
|
|
2916
3058
|
);
|
|
2917
3059
|
}
|
|
2918
3060
|
function assertNotReserved(ref, variable, where, config) {
|
|
2919
|
-
if ((0,
|
|
2920
|
-
throw new
|
|
3061
|
+
if ((0, import_core15.isReservedToken)(ref.name, config)) {
|
|
3062
|
+
throw new import_core15.ReservedTokenError("parameter", variable, where);
|
|
2921
3063
|
}
|
|
2922
3064
|
}
|
|
2923
3065
|
function assertRoundTrips(ref, variable, config) {
|
|
2924
|
-
if ((0,
|
|
3066
|
+
if ((0, import_core15.roundTripsCleanly)(variable)) {
|
|
2925
3067
|
return;
|
|
2926
3068
|
}
|
|
2927
|
-
if ((0,
|
|
3069
|
+
if ((0, import_core15.variableName)(ref, config) === variable) {
|
|
2928
3070
|
return;
|
|
2929
3071
|
}
|
|
2930
|
-
const generated = (0,
|
|
2931
|
-
throw new
|
|
3072
|
+
const generated = (0, import_core15.variableName)(ref, config);
|
|
3073
|
+
throw new import_core15.PenvError(
|
|
2932
3074
|
"IMPORT_LOSSY_NAME",
|
|
2933
3075
|
`The variable ${variable} becomes the parameter \`${ref.name}\`, which regenerates as ${generated}`,
|
|
2934
3076
|
`\`penv generate\` would write ${generated}, so anything reading \`process.env["${variable}"]\` would read \`undefined\`. Declare the name you want in the \`names\` block of penv.config.ts \u2014 \`names: { "${ref.name}": "${variable}" }\` \u2014 then import it again. Nothing was imported.`
|
|
2935
3077
|
);
|
|
2936
3078
|
}
|
|
2937
3079
|
function collisionsIn(refs, config) {
|
|
2938
|
-
const errors = (0,
|
|
3080
|
+
const errors = (0, import_core15.checkNameCollisions)(refs, config);
|
|
2939
3081
|
const first = errors[0];
|
|
2940
3082
|
if (first !== void 0) {
|
|
2941
3083
|
throw first;
|
|
@@ -2945,7 +3087,7 @@ function assertDeclared(segment, config) {
|
|
|
2945
3087
|
if (config.environments.includes(segment)) {
|
|
2946
3088
|
return segment;
|
|
2947
3089
|
}
|
|
2948
|
-
throw new
|
|
3090
|
+
throw new import_core15.UnknownEnvironmentError(segment, config.environments);
|
|
2949
3091
|
}
|
|
2950
3092
|
function scopeFromFilename(file, config) {
|
|
2951
3093
|
const name = (0, import_node_path7.basename)(file);
|
|
@@ -2970,13 +3112,13 @@ function scopeFromFilename(file, config) {
|
|
|
2970
3112
|
return { kind: "environment-local", environment: assertDeclared(first, config) };
|
|
2971
3113
|
}
|
|
2972
3114
|
if (first === LOCAL && rest.length === 2) {
|
|
2973
|
-
throw new
|
|
3115
|
+
throw new import_core15.FilenameGrammarError(
|
|
2974
3116
|
name,
|
|
2975
3117
|
"`local` precedes the environment segment",
|
|
2976
3118
|
`The environment segment always precedes \`local\` \u2014 \`.env.${second}.${LOCAL}\` is the file Next.js and Vite read, and \`.env.${LOCAL}.${second}\` is not a synonym for it. Rename it to \`.env.${second}.${LOCAL}\`, then import it again. Nothing was imported.`
|
|
2977
3119
|
);
|
|
2978
3120
|
}
|
|
2979
|
-
throw new
|
|
3121
|
+
throw new import_core15.FilenameGrammarError(
|
|
2980
3122
|
name,
|
|
2981
3123
|
`\`${rest.join("` and `")}\` are ${rest.length} scope segments`,
|
|
2982
3124
|
"A dotenv file carries exactly one scope: `.env`, `.env.<environment>`, `.env.local`, or `.env.<environment>.local`. Point `penv import` at one of those. Nothing was imported."
|
|
@@ -2991,7 +3133,7 @@ function environmentOf(scope) {
|
|
|
2991
3133
|
case "local":
|
|
2992
3134
|
return void 0;
|
|
2993
3135
|
default:
|
|
2994
|
-
return (0,
|
|
3136
|
+
return (0, import_core15.assertNever)(scope, "scope");
|
|
2995
3137
|
}
|
|
2996
3138
|
}
|
|
2997
3139
|
function scopeWithEnvironment(scope, environment) {
|
|
@@ -3004,7 +3146,7 @@ function scopeWithEnvironment(scope, environment) {
|
|
|
3004
3146
|
case "environment-local":
|
|
3005
3147
|
return scope;
|
|
3006
3148
|
default:
|
|
3007
|
-
return (0,
|
|
3149
|
+
return (0, import_core15.assertNever)(scope, "scope");
|
|
3008
3150
|
}
|
|
3009
3151
|
}
|
|
3010
3152
|
function explicitEnvironment(options, source, config) {
|
|
@@ -3012,7 +3154,7 @@ function explicitEnvironment(options, source, config) {
|
|
|
3012
3154
|
if (value.length > 0) {
|
|
3013
3155
|
return value;
|
|
3014
3156
|
}
|
|
3015
|
-
throw new
|
|
3157
|
+
throw new import_core15.PenvError(
|
|
3016
3158
|
"IMPORT_ENV_FLAG_EMPTY",
|
|
3017
3159
|
`\`--env\` for the import of ${source} names no environment`,
|
|
3018
3160
|
`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.`
|
|
@@ -3022,7 +3164,7 @@ function assertEnvironmentAgrees(derived, explicit, source) {
|
|
|
3022
3164
|
if (derived === void 0 || explicit === void 0 || derived === explicit) {
|
|
3023
3165
|
return;
|
|
3024
3166
|
}
|
|
3025
|
-
throw new
|
|
3167
|
+
throw new import_core15.PenvError(
|
|
3026
3168
|
"IMPORT_ENV_CONFLICT",
|
|
3027
3169
|
`The file ${source} is scoped to environment ${derived}, but \`--env ${explicit}\` names ${explicit}`,
|
|
3028
3170
|
`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.`
|
|
@@ -3043,15 +3185,15 @@ function environmentNamed(file, explicit) {
|
|
|
3043
3185
|
function decisionsOf(config, cwd) {
|
|
3044
3186
|
return {
|
|
3045
3187
|
environments: config.environments,
|
|
3046
|
-
schemaFile: (0,
|
|
3188
|
+
schemaFile: (0, import_core15.schemaFileOf)(config),
|
|
3047
3189
|
publicPrefixes: config.publicPrefixes ?? [],
|
|
3048
3190
|
alias: detectAlias(cwd)
|
|
3049
3191
|
};
|
|
3050
3192
|
}
|
|
3051
3193
|
function configInEffect(cwd, environment) {
|
|
3052
|
-
const existing = (0,
|
|
3194
|
+
const existing = (0, import_core15.findConfigFile)(cwd);
|
|
3053
3195
|
if (existing !== void 0) {
|
|
3054
|
-
const config = (0,
|
|
3196
|
+
const config = (0, import_core15.loadConfigFrom)(existing);
|
|
3055
3197
|
return { config, decisions: decisionsOf(config, cwd) };
|
|
3056
3198
|
}
|
|
3057
3199
|
const planned = planInit(cwd).decisions;
|
|
@@ -3066,13 +3208,13 @@ function importDotenv(options) {
|
|
|
3066
3208
|
const cwd = (0, import_node_path7.resolve)(options.cwd);
|
|
3067
3209
|
const file = (0, import_node_path7.isAbsolute)(options.file) ? options.file : (0, import_node_path7.resolve)(cwd, options.file);
|
|
3068
3210
|
if (!(0, import_node_fs4.existsSync)(file)) {
|
|
3069
|
-
throw new
|
|
3211
|
+
throw new import_core15.PenvError(
|
|
3070
3212
|
"IMPORT_FILE_MISSING",
|
|
3071
3213
|
`There is no file at ${file} to import`,
|
|
3072
3214
|
"Point `penv import` at an existing dotenv file, e.g. `penv import .env`."
|
|
3073
3215
|
);
|
|
3074
3216
|
}
|
|
3075
|
-
const parsed = (0,
|
|
3217
|
+
const parsed = (0, import_core15.parseDotenv)((0, import_node_fs4.readFileSync)(file, "utf8"));
|
|
3076
3218
|
const { config, decisions } = configInEffect(cwd, environmentNamed(file, options.environment));
|
|
3077
3219
|
const source = displayPath2(cwd, file);
|
|
3078
3220
|
const named = scopeFromFilename(file, config);
|
|
@@ -3080,10 +3222,10 @@ function importDotenv(options) {
|
|
|
3080
3222
|
const explicit = options.environment === void 0 ? void 0 : explicitEnvironment(options, source, config);
|
|
3081
3223
|
assertEnvironmentAgrees(derived, explicit, source);
|
|
3082
3224
|
const scope = explicit === void 0 ? named : scopeWithEnvironment(named, assertDeclared(explicit, config));
|
|
3083
|
-
const environment = (0,
|
|
3225
|
+
const environment = (0, import_core15.lookupEnvironment)(config, explicit ?? derived);
|
|
3084
3226
|
const refs = [];
|
|
3085
3227
|
for (const entry of parsed.entries) {
|
|
3086
|
-
const ref = (0,
|
|
3228
|
+
const ref = (0, import_core15.refFromVariable)(entry.key);
|
|
3087
3229
|
assertImportable(ref, entry.key);
|
|
3088
3230
|
assertNotReserved(ref, entry.key, source, config);
|
|
3089
3231
|
assertRoundTrips(ref, entry.key, config);
|
|
@@ -3179,7 +3321,7 @@ function renderImport(result2, validation) {
|
|
|
3179
3321
|
lines.push("", "Done. .penv/ is now your source of truth.");
|
|
3180
3322
|
return lines;
|
|
3181
3323
|
}
|
|
3182
|
-
var importCommand = (0,
|
|
3324
|
+
var importCommand = (0, import_citty10.defineCommand)({
|
|
3183
3325
|
meta: {
|
|
3184
3326
|
name: "import",
|
|
3185
3327
|
description: "Import an existing dotenv file; it becomes the source of truth"
|
|
@@ -3211,8 +3353,8 @@ var importCommand = (0, import_citty9.defineCommand)({
|
|
|
3211
3353
|
|
|
3212
3354
|
// src/commands/key.ts
|
|
3213
3355
|
var import_node_crypto = require("crypto");
|
|
3214
|
-
var
|
|
3215
|
-
var
|
|
3356
|
+
var import_core16 = require("@penvhq/core");
|
|
3357
|
+
var import_citty11 = require("citty");
|
|
3216
3358
|
|
|
3217
3359
|
// src/keychain.ts
|
|
3218
3360
|
var import_node_module2 = require("module");
|
|
@@ -3245,35 +3387,35 @@ function runKeyCreate(options) {
|
|
|
3245
3387
|
const environment = targetEnvironment(project, options.environment);
|
|
3246
3388
|
const declared = project.config.keys?.[environment];
|
|
3247
3389
|
if (declared === void 0) {
|
|
3248
|
-
throw new
|
|
3390
|
+
throw new import_core16.PenvError(
|
|
3249
3391
|
"KEY_SOURCE_UNDECLARED",
|
|
3250
3392
|
`Environment ${environment} declares no key source, so penv does not know what a key for it would be`,
|
|
3251
3393
|
`Add a \`keys\` entry to penv.config.ts \u2014 e.g. \`keys: { ${environment}: { source: "env", id: "${environment}" } }\` \u2014 then run this again.`
|
|
3252
3394
|
);
|
|
3253
3395
|
}
|
|
3254
|
-
const key = (0, import_node_crypto.randomBytes)(
|
|
3396
|
+
const key = (0, import_node_crypto.randomBytes)(import_core16.KEY_BYTES).toString("base64");
|
|
3255
3397
|
if (declared.source === "keychain") {
|
|
3256
3398
|
const keychain = options.keychain ?? defaultKeychain;
|
|
3257
3399
|
if (options.force !== true) {
|
|
3258
3400
|
let existing;
|
|
3259
3401
|
try {
|
|
3260
|
-
existing = keychain.getPassword(
|
|
3402
|
+
existing = keychain.getPassword(import_core16.KEYCHAIN_SERVICE, declared.id);
|
|
3261
3403
|
} catch (cause) {
|
|
3262
|
-
throw new
|
|
3404
|
+
throw new import_core16.PenvError(
|
|
3263
3405
|
"KEYCHAIN_UNAVAILABLE",
|
|
3264
3406
|
`penv could not read your OS keychain to check for an existing key \`${declared.id}\``,
|
|
3265
3407
|
`Unlock your keychain and run this again. Original error: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
3266
3408
|
);
|
|
3267
3409
|
}
|
|
3268
3410
|
if (existing !== null) {
|
|
3269
|
-
throw new
|
|
3411
|
+
throw new import_core16.PenvError(
|
|
3270
3412
|
"KEY_EXISTS",
|
|
3271
3413
|
`Environment ${environment} already has a key \`${declared.id}\` in your OS keychain`,
|
|
3272
3414
|
"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."
|
|
3273
3415
|
);
|
|
3274
3416
|
}
|
|
3275
3417
|
}
|
|
3276
|
-
keychain.setPassword(
|
|
3418
|
+
keychain.setPassword(import_core16.KEYCHAIN_SERVICE, declared.id, key);
|
|
3277
3419
|
return { source: "keychain", environment, id: declared.id };
|
|
3278
3420
|
}
|
|
3279
3421
|
return {
|
|
@@ -3303,10 +3445,10 @@ function renderKeyCreate(result2) {
|
|
|
3303
3445
|
"without it, and penv keeps no copy to fall back on."
|
|
3304
3446
|
];
|
|
3305
3447
|
}
|
|
3306
|
-
var keyCommand = (0,
|
|
3448
|
+
var keyCommand = (0, import_citty11.defineCommand)({
|
|
3307
3449
|
meta: { name: "key", description: "Work with encryption keys" },
|
|
3308
3450
|
subCommands: {
|
|
3309
|
-
create: (0,
|
|
3451
|
+
create: (0, import_citty11.defineCommand)({
|
|
3310
3452
|
meta: { name: "create", description: "Generate a key for an environment" },
|
|
3311
3453
|
args: {
|
|
3312
3454
|
env: { type: "string", description: "The environment the key is for" },
|
|
@@ -3333,8 +3475,8 @@ var keyCommand = (0, import_citty10.defineCommand)({
|
|
|
3333
3475
|
});
|
|
3334
3476
|
|
|
3335
3477
|
// src/commands/list.ts
|
|
3336
|
-
var
|
|
3337
|
-
var
|
|
3478
|
+
var import_core17 = require("@penvhq/core");
|
|
3479
|
+
var import_citty12 = require("citty");
|
|
3338
3480
|
function scopeLabel2(scope) {
|
|
3339
3481
|
switch (scope.kind) {
|
|
3340
3482
|
case "environment":
|
|
@@ -3346,7 +3488,7 @@ function scopeLabel2(scope) {
|
|
|
3346
3488
|
case "unscoped":
|
|
3347
3489
|
return "default";
|
|
3348
3490
|
default:
|
|
3349
|
-
return (0,
|
|
3491
|
+
return (0, import_core17.assertNever)(scope, "scope");
|
|
3350
3492
|
}
|
|
3351
3493
|
}
|
|
3352
3494
|
async function runList(options) {
|
|
@@ -3354,12 +3496,12 @@ async function runList(options) {
|
|
|
3354
3496
|
const environment = targetEnvironment(project, options.environment);
|
|
3355
3497
|
const keys = keySourceFor(project, environment);
|
|
3356
3498
|
const parameters = [];
|
|
3357
|
-
for (const resolution of await (0,
|
|
3499
|
+
for (const resolution of await (0, import_core17.resolveAll)(environment, project.provider, keys)) {
|
|
3358
3500
|
const winner = resolution.winner;
|
|
3359
3501
|
const scope = winner?.file.scope;
|
|
3360
3502
|
parameters.push({
|
|
3361
3503
|
parameter: resolution.parameter,
|
|
3362
|
-
variable: (0,
|
|
3504
|
+
variable: (0, import_core17.variableName)(resolution.ref, project.config),
|
|
3363
3505
|
scope: scope === void 0 ? "absent" : scopeLabel2(scope),
|
|
3364
3506
|
location: winner?.location,
|
|
3365
3507
|
encrypted: winner?.file.encrypted === true,
|
|
@@ -3374,7 +3516,7 @@ function renderList(result2) {
|
|
|
3374
3516
|
}
|
|
3375
3517
|
return columns(result2.parameters.map((entry) => [entry.parameter, entry.scope, entry.variable]));
|
|
3376
3518
|
}
|
|
3377
|
-
var listCommand = (0,
|
|
3519
|
+
var listCommand = (0, import_citty12.defineCommand)({
|
|
3378
3520
|
meta: { name: "list", description: "List parameters" },
|
|
3379
3521
|
args: {
|
|
3380
3522
|
env: { type: "string", description: "The environment to resolve against" },
|
|
@@ -3392,8 +3534,8 @@ var listCommand = (0, import_citty11.defineCommand)({
|
|
|
3392
3534
|
});
|
|
3393
3535
|
|
|
3394
3536
|
// src/commands/mv.ts
|
|
3395
|
-
var
|
|
3396
|
-
var
|
|
3537
|
+
var import_core18 = require("@penvhq/core");
|
|
3538
|
+
var import_citty13 = require("citty");
|
|
3397
3539
|
function environmentOf2(file) {
|
|
3398
3540
|
const scope = file.scope;
|
|
3399
3541
|
return scope.kind === "environment" || scope.kind === "environment-local" ? scope.environment : void 0;
|
|
@@ -3408,38 +3550,39 @@ async function planFile(project, source, target, parameter) {
|
|
|
3408
3550
|
}
|
|
3409
3551
|
const environment = environmentOf2(source);
|
|
3410
3552
|
if (environment === void 0) {
|
|
3411
|
-
throw new
|
|
3553
|
+
throw new import_core18.PenvError(
|
|
3412
3554
|
"SECRET_SCOPE_AMBIGUOUS",
|
|
3413
|
-
`${PENV_DIR}/${(0,
|
|
3555
|
+
`${PENV_DIR}/${(0, import_core18.formatValueFile)(source)} is encrypted at a scope that names no environment, so penv cannot tell which key would re-seal it`,
|
|
3414
3556
|
"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."
|
|
3415
3557
|
);
|
|
3416
3558
|
}
|
|
3417
3559
|
const keys = keySourceFor(project, environment);
|
|
3418
|
-
const opened = (0,
|
|
3560
|
+
const opened = (0, import_core18.openValue)(source, stored, keys);
|
|
3419
3561
|
if (opened.kind === "failed") {
|
|
3420
|
-
throw new
|
|
3562
|
+
throw new import_core18.PenvError(
|
|
3421
3563
|
"VALUE_UNDECRYPTABLE",
|
|
3422
|
-
`${PENV_DIR}/${(0,
|
|
3564
|
+
`${PENV_DIR}/${(0, import_core18.formatValueFile)(source)} could not be decrypted, so penv cannot re-seal it at its new address: ${opened.failure.detail}`,
|
|
3423
3565
|
"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."
|
|
3424
3566
|
);
|
|
3425
3567
|
}
|
|
3426
3568
|
return {
|
|
3427
3569
|
source,
|
|
3428
3570
|
target,
|
|
3429
|
-
contents: (0,
|
|
3571
|
+
contents: (0, import_core18.sealValue)(target, opened.value, keys, parameter, environment),
|
|
3430
3572
|
resealed: true
|
|
3431
3573
|
};
|
|
3432
3574
|
}
|
|
3433
3575
|
function filesOf(all, ref) {
|
|
3434
|
-
const id = (0,
|
|
3435
|
-
return all.filter((file) => (0,
|
|
3576
|
+
const id = (0, import_core18.parameterId)(ref);
|
|
3577
|
+
return all.filter((file) => (0, import_core18.parameterId)(file) === id);
|
|
3436
3578
|
}
|
|
3437
3579
|
async function runMove(options) {
|
|
3438
3580
|
const project = openProject(options.cwd);
|
|
3439
3581
|
const from = refFromKey(options.from, project.config);
|
|
3582
|
+
assertWritableKey(options.to);
|
|
3440
3583
|
const to = refFromKey(options.to, project.config);
|
|
3441
|
-
if ((0,
|
|
3442
|
-
throw new
|
|
3584
|
+
if ((0, import_core18.parameterId)(from) === (0, import_core18.parameterId)(to)) {
|
|
3585
|
+
throw new import_core18.PenvError(
|
|
3443
3586
|
"PARAMETER_UNCHANGED",
|
|
3444
3587
|
`\`${options.from}\` and \`${options.to}\` are the same parameter`,
|
|
3445
3588
|
"Name a different destination, e.g. `penv mv redis-password redis/password`."
|
|
@@ -3449,24 +3592,24 @@ async function runMove(options) {
|
|
|
3449
3592
|
const sources = filesOf(all, from);
|
|
3450
3593
|
const meta = await project.provider.readMeta(from);
|
|
3451
3594
|
if (sources.length === 0 && meta === void 0) {
|
|
3452
|
-
throw new
|
|
3595
|
+
throw new import_core18.PenvError(
|
|
3453
3596
|
"PARAMETER_ABSENT",
|
|
3454
|
-
`Parameter ${(0,
|
|
3597
|
+
`Parameter ${(0, import_core18.parameterId)(from)} has no value files and no meta, so there is nothing to move`,
|
|
3455
3598
|
`\`penv list\` shows every parameter penv holds.`
|
|
3456
3599
|
);
|
|
3457
3600
|
}
|
|
3458
3601
|
const occupied2 = filesOf(all, to);
|
|
3459
3602
|
if (occupied2.length > 0 || await project.provider.readMeta(to) !== void 0) {
|
|
3460
|
-
throw new
|
|
3603
|
+
throw new import_core18.PenvError(
|
|
3461
3604
|
"PARAMETER_EXISTS",
|
|
3462
|
-
`Parameter ${(0,
|
|
3463
|
-
`Remove or rename ${(0,
|
|
3605
|
+
`Parameter ${(0, import_core18.parameterId)(to)} already exists, and penv will not merge two parameters into one`,
|
|
3606
|
+
`Remove or rename ${(0, import_core18.parameterId)(to)} first. \`penv get ${options.to} --explain\` shows every file it holds.`
|
|
3464
3607
|
);
|
|
3465
3608
|
}
|
|
3466
3609
|
const planned = [];
|
|
3467
3610
|
for (const source of sources) {
|
|
3468
3611
|
const target = { ...source, namespace: to.namespace, name: to.name };
|
|
3469
|
-
const one = await planFile(project, source, target, (0,
|
|
3612
|
+
const one = await planFile(project, source, target, (0, import_core18.parameterId)(to));
|
|
3470
3613
|
if (one !== void 0) {
|
|
3471
3614
|
planned.push(one);
|
|
3472
3615
|
}
|
|
@@ -3484,18 +3627,18 @@ async function runMove(options) {
|
|
|
3484
3627
|
await project.provider.removeMeta(from);
|
|
3485
3628
|
}
|
|
3486
3629
|
return {
|
|
3487
|
-
from: (0,
|
|
3488
|
-
to: (0,
|
|
3630
|
+
from: (0, import_core18.parameterId)(from),
|
|
3631
|
+
to: (0, import_core18.parameterId)(to),
|
|
3489
3632
|
files: planned.map((file) => ({
|
|
3490
|
-
from: (0,
|
|
3491
|
-
to: (0,
|
|
3633
|
+
from: (0, import_core18.formatValueFile)(file.source),
|
|
3634
|
+
to: (0, import_core18.formatValueFile)(file.target),
|
|
3492
3635
|
resealed: file.resealed
|
|
3493
3636
|
})),
|
|
3494
3637
|
// The meta's path, not the parameter's dotted id: `redis.password` is what
|
|
3495
3638
|
// the schema calls it and `redis/password.json` is the file, and a report
|
|
3496
3639
|
// that printed the first while moving the second names no file on disk.
|
|
3497
|
-
meta: meta === void 0 ? void 0 : (0,
|
|
3498
|
-
schema: { was: (0,
|
|
3640
|
+
meta: meta === void 0 ? void 0 : (0, import_core18.formatMetaFile)({ ...to, format: "json" }),
|
|
3641
|
+
schema: { was: (0, import_core18.accessPath)(from).join("."), now: (0, import_core18.accessPath)(to).join(".") }
|
|
3499
3642
|
};
|
|
3500
3643
|
}
|
|
3501
3644
|
function renderMove(result2) {
|
|
@@ -3516,7 +3659,7 @@ function renderMove(result2) {
|
|
|
3516
3659
|
);
|
|
3517
3660
|
return lines;
|
|
3518
3661
|
}
|
|
3519
|
-
var mvCommand = (0,
|
|
3662
|
+
var mvCommand = (0, import_citty13.defineCommand)({
|
|
3520
3663
|
meta: { name: "mv", description: "Rename a parameter, every scope and its meta at once" },
|
|
3521
3664
|
args: {
|
|
3522
3665
|
from: {
|
|
@@ -3538,7 +3681,7 @@ var mvCommand = (0, import_citty12.defineCommand)({
|
|
|
3538
3681
|
});
|
|
3539
3682
|
|
|
3540
3683
|
// src/commands/pull.ts
|
|
3541
|
-
var
|
|
3684
|
+
var import_citty14 = require("citty");
|
|
3542
3685
|
async function runPull(options) {
|
|
3543
3686
|
const project = openProject(options.cwd);
|
|
3544
3687
|
const environment = targetEnvironment(project, options.environment);
|
|
@@ -3595,7 +3738,7 @@ function renderPull(result2) {
|
|
|
3595
3738
|
}
|
|
3596
3739
|
]);
|
|
3597
3740
|
}
|
|
3598
|
-
var pullCommand = (0,
|
|
3741
|
+
var pullCommand = (0, import_citty14.defineCommand)({
|
|
3599
3742
|
meta: {
|
|
3600
3743
|
name: "pull",
|
|
3601
3744
|
description: "Materialise the local .penv tree from an environment's source-of-truth provider"
|
|
@@ -3615,8 +3758,8 @@ var pullCommand = (0, import_citty13.defineCommand)({
|
|
|
3615
3758
|
});
|
|
3616
3759
|
|
|
3617
3760
|
// src/commands/remove.ts
|
|
3618
|
-
var
|
|
3619
|
-
var
|
|
3761
|
+
var import_core19 = require("@penvhq/core");
|
|
3762
|
+
var import_citty15 = require("citty");
|
|
3620
3763
|
async function runRemove(options) {
|
|
3621
3764
|
const project = openProject(options.cwd);
|
|
3622
3765
|
const ref = refFromKey(options.key);
|
|
@@ -3633,12 +3776,12 @@ async function runRemove(options) {
|
|
|
3633
3776
|
continue;
|
|
3634
3777
|
}
|
|
3635
3778
|
await project.provider.remove(file);
|
|
3636
|
-
removed.push((0,
|
|
3779
|
+
removed.push((0, import_core19.formatValueFile)(file));
|
|
3637
3780
|
}
|
|
3638
3781
|
return {
|
|
3639
3782
|
parameter: options.key,
|
|
3640
3783
|
removed,
|
|
3641
|
-
considered: files.map((file) => (0,
|
|
3784
|
+
considered: files.map((file) => (0, import_core19.formatValueFile)(file))
|
|
3642
3785
|
};
|
|
3643
3786
|
}
|
|
3644
3787
|
function renderRemove(result2) {
|
|
@@ -3660,7 +3803,7 @@ function renderRemove(result2) {
|
|
|
3660
3803
|
}));
|
|
3661
3804
|
return formatRows(rows);
|
|
3662
3805
|
}
|
|
3663
|
-
var removeCommand = (0,
|
|
3806
|
+
var removeCommand = (0, import_citty15.defineCommand)({
|
|
3664
3807
|
meta: { name: "remove", description: "Delete a parameter" },
|
|
3665
3808
|
args: {
|
|
3666
3809
|
key: { type: "positional", required: true, description: "The parameter, e.g. redis/password" },
|
|
@@ -3687,8 +3830,8 @@ var removeCommand = (0, import_citty14.defineCommand)({
|
|
|
3687
3830
|
});
|
|
3688
3831
|
|
|
3689
3832
|
// src/commands/rotate.ts
|
|
3690
|
-
var
|
|
3691
|
-
var
|
|
3833
|
+
var import_core20 = require("@penvhq/core");
|
|
3834
|
+
var import_citty16 = require("citty");
|
|
3692
3835
|
function rotatingFile(ref, environment) {
|
|
3693
3836
|
return {
|
|
3694
3837
|
namespace: ref.namespace,
|
|
@@ -3713,7 +3856,7 @@ async function writeRotatedValue(project, provider, ref, environment, value) {
|
|
|
3713
3856
|
}
|
|
3714
3857
|
function requireNewValue(value, phase, key) {
|
|
3715
3858
|
if (value === void 0) {
|
|
3716
|
-
throw new
|
|
3859
|
+
throw new import_core20.PenvError(
|
|
3717
3860
|
"ROTATION_NO_VALUE",
|
|
3718
3861
|
`A ${phase} rotation of ${key} writes a new value, and none was given`,
|
|
3719
3862
|
"Pass the new value as the argument \u2014 `penv rotate <key> <value>` \u2014 or pipe it in on stdin."
|
|
@@ -3722,8 +3865,8 @@ function requireNewValue(value, phase, key) {
|
|
|
3722
3865
|
return value;
|
|
3723
3866
|
}
|
|
3724
3867
|
function requireRetaining(provider, environment) {
|
|
3725
|
-
if (!(0,
|
|
3726
|
-
throw new
|
|
3868
|
+
if (!(0, import_core20.retainsPrevious)(provider)) {
|
|
3869
|
+
throw new import_core20.PenvError(
|
|
3727
3870
|
"ROTATION_NOT_RETAINING",
|
|
3728
3871
|
`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`,
|
|
3729
3872
|
"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."
|
|
@@ -3738,9 +3881,9 @@ async function runRotate(options) {
|
|
|
3738
3881
|
const provider = await sourceProviderFor(project, environment);
|
|
3739
3882
|
const nowIso = options.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3740
3883
|
const before = await provider.readMeta(ref);
|
|
3741
|
-
const { mechanism } = (0,
|
|
3884
|
+
const { mechanism } = (0, import_core20.rotationOf)(before, environment);
|
|
3742
3885
|
if (mechanism === void 0) {
|
|
3743
|
-
throw new
|
|
3886
|
+
throw new import_core20.PenvError(
|
|
3744
3887
|
"ROTATION_NO_MECHANISM",
|
|
3745
3888
|
`Parameter ${options.key} declares no rotation mechanism for environment ${environment}, so penv does not know how to rotate it`,
|
|
3746
3889
|
'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.'
|
|
@@ -3750,7 +3893,7 @@ async function runRotate(options) {
|
|
|
3750
3893
|
const complete = options.complete === true;
|
|
3751
3894
|
if (mechanism === "atomic-cutover") {
|
|
3752
3895
|
if (begin || complete) {
|
|
3753
|
-
throw new
|
|
3896
|
+
throw new import_core20.PenvError(
|
|
3754
3897
|
"ROTATION_MECHANISM_MISMATCH",
|
|
3755
3898
|
`Parameter ${options.key} is atomic-cutover, which flips in one step, so \`--begin\`/\`--complete\` do not apply`,
|
|
3756
3899
|
"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."
|
|
@@ -3758,13 +3901,13 @@ async function runRotate(options) {
|
|
|
3758
3901
|
}
|
|
3759
3902
|
const value = requireNewValue(options.value, "cutover", options.key);
|
|
3760
3903
|
await writeRotatedValue(project, provider, ref, environment, value);
|
|
3761
|
-
const after2 = (0,
|
|
3904
|
+
const after2 = (0, import_core20.completeRotation)(before, environment, nowIso);
|
|
3762
3905
|
await provider.writeMeta(ref, after2);
|
|
3763
3906
|
return result(ref, environment, mechanism, "cutover", provider.type, true, after2);
|
|
3764
3907
|
}
|
|
3765
3908
|
const retaining = requireRetaining(provider, environment);
|
|
3766
3909
|
if (begin === complete) {
|
|
3767
|
-
throw new
|
|
3910
|
+
throw new import_core20.PenvError(
|
|
3768
3911
|
"ROTATION_PHASE_REQUIRED",
|
|
3769
3912
|
`A dual-valid rotation of ${options.key} needs exactly one of \`--begin\` or \`--complete\``,
|
|
3770
3913
|
"`--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."
|
|
@@ -3773,16 +3916,16 @@ async function runRotate(options) {
|
|
|
3773
3916
|
if (begin) {
|
|
3774
3917
|
const value = requireNewValue(options.value, "begin", options.key);
|
|
3775
3918
|
await writeRotatedValue(project, retaining, ref, environment, value);
|
|
3776
|
-
const after2 = (0,
|
|
3919
|
+
const after2 = (0, import_core20.beginRotation)(before, environment, nowIso);
|
|
3777
3920
|
await retaining.writeMeta(ref, after2);
|
|
3778
3921
|
return result(ref, environment, mechanism, "begin", retaining.type, true, after2);
|
|
3779
3922
|
}
|
|
3780
|
-
const after = (0,
|
|
3923
|
+
const after = (0, import_core20.completeRotation)(before, environment, nowIso);
|
|
3781
3924
|
await retaining.writeMeta(ref, after);
|
|
3782
3925
|
return result(ref, environment, mechanism, "complete", retaining.type, false, after);
|
|
3783
3926
|
}
|
|
3784
3927
|
function result(ref, environment, mechanism, phase, source, wroteValue, after) {
|
|
3785
|
-
const { state, rotatingSince, lastRotated } = (0,
|
|
3928
|
+
const { state, rotatingSince, lastRotated } = (0, import_core20.rotationOf)(after, environment);
|
|
3786
3929
|
return {
|
|
3787
3930
|
parameter: [...ref.namespace, ref.name].join("/"),
|
|
3788
3931
|
environment,
|
|
@@ -3831,7 +3974,7 @@ function renderRotate(result2) {
|
|
|
3831
3974
|
}
|
|
3832
3975
|
]);
|
|
3833
3976
|
}
|
|
3834
|
-
var rotateCommand = (0,
|
|
3977
|
+
var rotateCommand = (0, import_citty16.defineCommand)({
|
|
3835
3978
|
meta: {
|
|
3836
3979
|
name: "rotate",
|
|
3837
3980
|
description: "Rotate a parameter's value by the mechanism its meta declares"
|
|
@@ -3869,8 +4012,8 @@ var rotateCommand = (0, import_citty15.defineCommand)({
|
|
|
3869
4012
|
// src/commands/watch.ts
|
|
3870
4013
|
var import_node_fs5 = require("fs");
|
|
3871
4014
|
var import_node_path8 = require("path");
|
|
3872
|
-
var
|
|
3873
|
-
var
|
|
4015
|
+
var import_core21 = require("@penvhq/core");
|
|
4016
|
+
var import_citty17 = require("citty");
|
|
3874
4017
|
var DEBOUNCE_MS = 100;
|
|
3875
4018
|
function runWatch(options) {
|
|
3876
4019
|
const project = openProject(options.cwd);
|
|
@@ -4002,8 +4145,8 @@ function runWatch(options) {
|
|
|
4002
4145
|
}
|
|
4003
4146
|
addWatcher(project.penvDir, true);
|
|
4004
4147
|
addWatcher((0, import_node_path8.dirname)(project.configFile), false, configFile);
|
|
4005
|
-
if ((0,
|
|
4006
|
-
const schemaFile = (0, import_node_path8.resolve)(project.root, (0,
|
|
4148
|
+
if ((0, import_core21.schemaInsideTree)(project.config) === void 0) {
|
|
4149
|
+
const schemaFile = (0, import_node_path8.resolve)(project.root, (0, import_core21.schemaFileOf)(project.config));
|
|
4007
4150
|
addWatcher((0, import_node_path8.dirname)(schemaFile), false, (0, import_node_path8.basename)(schemaFile));
|
|
4008
4151
|
}
|
|
4009
4152
|
void validate();
|
|
@@ -4047,7 +4190,7 @@ function renderDrift(drift, environment) {
|
|
|
4047
4190
|
}
|
|
4048
4191
|
return lines;
|
|
4049
4192
|
}
|
|
4050
|
-
var watchCommand = (0,
|
|
4193
|
+
var watchCommand = (0, import_citty17.defineCommand)({
|
|
4051
4194
|
meta: {
|
|
4052
4195
|
name: "watch",
|
|
4053
4196
|
description: "Re-validate whenever .penv/ or penv.config.ts changes"
|
|
@@ -4086,7 +4229,7 @@ var watchCommand = (0, import_citty16.defineCommand)({
|
|
|
4086
4229
|
});
|
|
4087
4230
|
|
|
4088
4231
|
// src/index.ts
|
|
4089
|
-
var main = (0,
|
|
4232
|
+
var main = (0, import_citty18.defineCommand)({
|
|
4090
4233
|
meta: {
|
|
4091
4234
|
name: "penv",
|
|
4092
4235
|
description: "Configuration that shares a data model with your production secret manager"
|
|
@@ -4097,6 +4240,7 @@ var main = (0, import_citty17.defineCommand)({
|
|
|
4097
4240
|
generate: generateCommand,
|
|
4098
4241
|
get: getCommand,
|
|
4099
4242
|
set: setCommand,
|
|
4243
|
+
fill: fillCommand,
|
|
4100
4244
|
mv: mvCommand,
|
|
4101
4245
|
pull: pullCommand,
|
|
4102
4246
|
push: pushCommand,
|
|
@@ -4112,8 +4256,8 @@ var main = (0, import_citty17.defineCommand)({
|
|
|
4112
4256
|
}
|
|
4113
4257
|
});
|
|
4114
4258
|
function runMain() {
|
|
4115
|
-
(0,
|
|
4116
|
-
return (0,
|
|
4259
|
+
(0, import_core22.setKeychain)(defaultKeychain);
|
|
4260
|
+
return (0, import_citty18.runMain)(main);
|
|
4117
4261
|
}
|
|
4118
4262
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4119
4263
|
0 && (module.exports = {
|
|
@@ -4123,6 +4267,7 @@ function runMain() {
|
|
|
4123
4267
|
insertEnvAlias,
|
|
4124
4268
|
main,
|
|
4125
4269
|
renderDoctor,
|
|
4270
|
+
renderFill,
|
|
4126
4271
|
renderMove,
|
|
4127
4272
|
renderPull,
|
|
4128
4273
|
renderPush,
|
|
@@ -4132,6 +4277,7 @@ function runMain() {
|
|
|
4132
4277
|
runDoctor,
|
|
4133
4278
|
runEncrypt,
|
|
4134
4279
|
runExplain,
|
|
4280
|
+
runFill,
|
|
4135
4281
|
runGenerate,
|
|
4136
4282
|
runGet,
|
|
4137
4283
|
runInit,
|