@penvhq/cli 0.6.0 → 0.7.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/index.cjs +107 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +107 -28
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -2803,7 +2803,7 @@ function occupied(cwd, relative3) {
|
|
|
2803
2803
|
return (0, import_node_fs2.existsSync)(file) && !exportsSchema(file);
|
|
2804
2804
|
}
|
|
2805
2805
|
function schemaFileFor(cwd) {
|
|
2806
|
-
const dir = (
|
|
2806
|
+
const dir = srcPrefix(cwd);
|
|
2807
2807
|
const preferred = `${dir}env.ts`;
|
|
2808
2808
|
if (!occupied(cwd, preferred)) {
|
|
2809
2809
|
return { file: preferred };
|
|
@@ -2814,6 +2814,9 @@ function schemaFileFor(cwd) {
|
|
|
2814
2814
|
}
|
|
2815
2815
|
return { file: import_core14.DEFAULT_SCHEMA_FILE, displaced: preferred };
|
|
2816
2816
|
}
|
|
2817
|
+
function srcPrefix(cwd) {
|
|
2818
|
+
return (0, import_node_fs2.existsSync)((0, import_node_path5.join)(cwd, "src")) ? "src/" : "";
|
|
2819
|
+
}
|
|
2817
2820
|
function dependenciesOf(cwd) {
|
|
2818
2821
|
const manifest = manifestOf(cwd);
|
|
2819
2822
|
if (manifest === void 0) {
|
|
@@ -2951,19 +2954,25 @@ function bun({ alias }) {
|
|
|
2951
2954
|
kind: "scaffold",
|
|
2952
2955
|
file: ".penv/preload.ts",
|
|
2953
2956
|
content: `// Bun evaluates this file before your entry point, because it is listed under
|
|
2954
|
-
// \`preload\` in bunfig.toml
|
|
2955
|
-
//
|
|
2957
|
+
// \`preload\` in bunfig.toml. Running it injects your config into process.env
|
|
2958
|
+
// before any library reads it.
|
|
2956
2959
|
import "${alias}";
|
|
2957
2960
|
`,
|
|
2958
2961
|
ifPresent: `Keep .penv/preload.ts as \`import "${alias}";\`.`,
|
|
2959
|
-
notes: [
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2962
|
+
notes: [`\`${alias}\` must be a tsconfig \`paths\` alias for Bun to resolve it.`],
|
|
2963
|
+
// The preload file is inert until bunfig.toml points at it — so penv writes
|
|
2964
|
+
// that too, both for the runtime and for `bun test`. Only when there is no
|
|
2965
|
+
// bunfig to overwrite; an existing one is the user's, and penv prints instead.
|
|
2966
|
+
also: {
|
|
2967
|
+
file: "bunfig.toml",
|
|
2968
|
+
content: 'preload = ["./.penv/preload.ts"]\n\n[test]\npreload = ["./.penv/preload.ts"]\n',
|
|
2969
|
+
ifPresent: 'Add "./.penv/preload.ts" to the `preload` array in bunfig.toml \u2014 and mirror it under `[test]` so `bun test` injects too.'
|
|
2970
|
+
}
|
|
2963
2971
|
};
|
|
2964
2972
|
}
|
|
2965
|
-
function node({ alias,
|
|
2966
|
-
const
|
|
2973
|
+
function node({ alias, schemaFile }) {
|
|
2974
|
+
const builtSchema = `./${schemaFile.replace(/\.ts$/, ".js")}`;
|
|
2975
|
+
const runtimeSpecifier = alias.startsWith("#") ? alias : builtSchema;
|
|
2967
2976
|
return {
|
|
2968
2977
|
kind: "instruct",
|
|
2969
2978
|
instruction: `Plain Node / Express / Fastify have no framework hook that runs before your
|
|
@@ -2983,10 +2992,17 @@ import before it. If you have no server.ts yet, create it from TanStack's server
|
|
|
2983
2992
|
template and put that import first.`
|
|
2984
2993
|
};
|
|
2985
2994
|
}
|
|
2986
|
-
function astro(
|
|
2995
|
+
function astro({ alias }) {
|
|
2987
2996
|
return {
|
|
2988
2997
|
kind: "instruct",
|
|
2989
|
-
instruction:
|
|
2998
|
+
instruction: `Astro has no single pre-app hook. Add a small integration to astro.config that
|
|
2999
|
+
injects the import into every SSR page, then cover the routes it cannot reach:
|
|
3000
|
+
\u2022 In astro.config integrations, add:
|
|
3001
|
+
{ name: "penv", hooks: { "astro:config:setup": ({ injectScript }) =>
|
|
3002
|
+
injectScript("page-ssr", 'import "${alias}";') } }
|
|
3003
|
+
\u2022 Also add \`import "${alias}";\` as the first line of src/middleware.ts and of any
|
|
3004
|
+
endpoint route (src/pages/*.ts) that imports a library reading process.env.
|
|
3005
|
+
Injection only applies under a server (on-demand) adapter, not a static build.`
|
|
2990
3006
|
};
|
|
2991
3007
|
}
|
|
2992
3008
|
function viteSpa(_context) {
|
|
@@ -3187,17 +3203,18 @@ async function promptForDecisions(plan2, io) {
|
|
|
3187
3203
|
);
|
|
3188
3204
|
io.write("");
|
|
3189
3205
|
}
|
|
3190
|
-
const inject = seamKindFor(plan2) === "none" ? false : await askInject(io);
|
|
3191
3206
|
const proceed = (await io.ask(prompt("Proceed?", "Y/n"))).trim().toLowerCase();
|
|
3192
3207
|
if (proceed.length > 0 && proceed !== "y" && proceed !== "yes") {
|
|
3193
3208
|
return void 0;
|
|
3194
3209
|
}
|
|
3210
|
+
const inject = seamKindFor(plan2) === "none" ? false : await askInject(io);
|
|
3195
3211
|
return { ...plan2.decisions, environments, inject };
|
|
3196
3212
|
}
|
|
3197
3213
|
function seamKindFor(plan2) {
|
|
3198
3214
|
return seamFor(plan2.detected?.name, {
|
|
3199
3215
|
alias: plan2.decisions.alias,
|
|
3200
|
-
srcDir: plan2.decisions.schemaFile.startsWith("src/") ? "src/" : ""
|
|
3216
|
+
srcDir: plan2.decisions.schemaFile.startsWith("src/") ? "src/" : "",
|
|
3217
|
+
schemaFile: plan2.decisions.schemaFile
|
|
3201
3218
|
}).kind;
|
|
3202
3219
|
}
|
|
3203
3220
|
async function askInject(io) {
|
|
@@ -3592,15 +3609,48 @@ function writeGitignore(root, decisions = DEFAULT_DECISIONS) {
|
|
|
3592
3609
|
text: `${existing === void 0 ? "Created" : "Updated"} ${relative3}`
|
|
3593
3610
|
};
|
|
3594
3611
|
}
|
|
3595
|
-
|
|
3596
|
-
|
|
3612
|
+
var INJECT_MIN_VERSION = "0.6.0";
|
|
3613
|
+
function outdatedRuntimeWarning(root) {
|
|
3614
|
+
const version = installedPenvVersion(root);
|
|
3615
|
+
if (version === void 0 || !isBelow(version, INJECT_MIN_VERSION)) {
|
|
3616
|
+
return void 0;
|
|
3617
|
+
}
|
|
3618
|
+
return `Injection needs @penvhq/penv ${INJECT_MIN_VERSION}+ \u2014 this project has ${version}, whose \`load\` ignores \`{ inject: true }\`. Upgrade, or process.env stays empty.`;
|
|
3619
|
+
}
|
|
3620
|
+
function installedPenvVersion(root) {
|
|
3621
|
+
const file = (0, import_node_path6.join)(root, "node_modules", "@penvhq", "penv", "package.json");
|
|
3622
|
+
if (!(0, import_node_fs3.existsSync)(file)) {
|
|
3623
|
+
return void 0;
|
|
3624
|
+
}
|
|
3625
|
+
try {
|
|
3626
|
+
const version = JSON.parse((0, import_node_fs3.readFileSync)(file, "utf8")).version;
|
|
3627
|
+
return typeof version === "string" ? version : void 0;
|
|
3628
|
+
} catch {
|
|
3629
|
+
return void 0;
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
function releaseTriple(version) {
|
|
3633
|
+
const parts = (version.split("-")[0] ?? "").split(".");
|
|
3634
|
+
const at = (i) => Number.parseInt(parts[i] ?? "0", 10) || 0;
|
|
3635
|
+
return [at(0), at(1), at(2)];
|
|
3636
|
+
}
|
|
3637
|
+
function isBelow(a, b) {
|
|
3638
|
+
const [am, an, ap] = releaseTriple(a);
|
|
3639
|
+
const [bm, bn, bp] = releaseTriple(b);
|
|
3640
|
+
if (am !== bm) return am < bm;
|
|
3641
|
+
if (an !== bn) return an < bn;
|
|
3642
|
+
return ap < bp;
|
|
3597
3643
|
}
|
|
3598
|
-
function writeSeam(root, decisions = DEFAULT_DECISIONS) {
|
|
3644
|
+
function writeSeam(root, decisions = DEFAULT_DECISIONS, framework = detectFramework(root)?.name) {
|
|
3599
3645
|
if (!decisions.inject) {
|
|
3600
3646
|
return void 0;
|
|
3601
3647
|
}
|
|
3602
|
-
const
|
|
3603
|
-
|
|
3648
|
+
const seam = seamFor(framework, {
|
|
3649
|
+
alias: decisions.alias,
|
|
3650
|
+
srcDir: srcPrefix(root),
|
|
3651
|
+
schemaFile: decisions.schemaFile
|
|
3652
|
+
});
|
|
3653
|
+
const outdated = outdatedRuntimeWarning(root);
|
|
3604
3654
|
if (seam.kind === "none") {
|
|
3605
3655
|
return { target: "seam", action: "info", text: "No injection seam needed", note: seam.reason };
|
|
3606
3656
|
}
|
|
@@ -3609,30 +3659,51 @@ function writeSeam(root, decisions = DEFAULT_DECISIONS) {
|
|
|
3609
3659
|
target: "seam",
|
|
3610
3660
|
action: "info",
|
|
3611
3661
|
text: "Place the injection seam",
|
|
3612
|
-
note: seam.instruction
|
|
3662
|
+
note: withWarning(seam.instruction, outdated)
|
|
3613
3663
|
};
|
|
3614
3664
|
}
|
|
3665
|
+
const alsoNote = writeAlso(root, seam.also);
|
|
3615
3666
|
const file = (0, import_node_path6.join)(root, ...seam.file.split("/"));
|
|
3616
|
-
const
|
|
3617
|
-
|
|
3667
|
+
const baseNotes = [...seam.notes, ...alsoNote === void 0 ? [] : [alsoNote]];
|
|
3668
|
+
const notes = baseNotes.length === 0 ? "" : `
|
|
3669
|
+
${baseNotes.map((n) => ` ${n}`).join("\n")}`;
|
|
3618
3670
|
if ((0, import_node_fs3.existsSync)(file)) {
|
|
3619
3671
|
return {
|
|
3620
3672
|
target: "seam",
|
|
3621
3673
|
action: "info",
|
|
3622
3674
|
text: `Add the injection seam to ${seam.file}`,
|
|
3623
|
-
note: `${seam.ifPresent}${notes}
|
|
3675
|
+
note: withWarning(`${seam.ifPresent}${notes}`, outdated)
|
|
3624
3676
|
};
|
|
3625
3677
|
}
|
|
3626
3678
|
(0, import_node_fs3.mkdirSync)((0, import_node_path6.dirname)(file), { recursive: true });
|
|
3627
3679
|
(0, import_node_fs3.writeFileSync)(file, seam.content, "utf8");
|
|
3628
3680
|
return {
|
|
3629
3681
|
target: "seam",
|
|
3630
|
-
action: "created",
|
|
3682
|
+
action: outdated === void 0 ? "created" : "info",
|
|
3631
3683
|
text: `Wrote ${seam.file} (runs the injection before your app)`,
|
|
3632
|
-
...notes === "" ? {} : { note: notes.trimStart() }
|
|
3684
|
+
...notes === "" && outdated === void 0 ? {} : { note: withWarning(notes.trimStart(), outdated) }
|
|
3633
3685
|
};
|
|
3634
3686
|
}
|
|
3635
|
-
function
|
|
3687
|
+
function writeAlso(root, also) {
|
|
3688
|
+
if (also === void 0) {
|
|
3689
|
+
return void 0;
|
|
3690
|
+
}
|
|
3691
|
+
const file = (0, import_node_path6.join)(root, ...also.file.split("/"));
|
|
3692
|
+
if ((0, import_node_fs3.existsSync)(file)) {
|
|
3693
|
+
return also.ifPresent;
|
|
3694
|
+
}
|
|
3695
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path6.dirname)(file), { recursive: true });
|
|
3696
|
+
(0, import_node_fs3.writeFileSync)(file, also.content, "utf8");
|
|
3697
|
+
return `Wrote ${also.file} to register it.`;
|
|
3698
|
+
}
|
|
3699
|
+
function withWarning(note, warning) {
|
|
3700
|
+
if (warning === void 0) {
|
|
3701
|
+
return note;
|
|
3702
|
+
}
|
|
3703
|
+
return note === "" ? warning : `${note}
|
|
3704
|
+
\u26A0 ${warning}`;
|
|
3705
|
+
}
|
|
3706
|
+
function scaffold(root, fields, draft, decisions = DEFAULT_DECISIONS, framework = detectFramework(root)?.name) {
|
|
3636
3707
|
const steps = [
|
|
3637
3708
|
ensurePenvDir(root),
|
|
3638
3709
|
writeSchemaFile(root, fields, draft, decisions),
|
|
@@ -3640,13 +3711,13 @@ function scaffold(root, fields, draft, decisions = DEFAULT_DECISIONS) {
|
|
|
3640
3711
|
writeTsconfigAlias(root, decisions),
|
|
3641
3712
|
writeGitignore(root, decisions)
|
|
3642
3713
|
];
|
|
3643
|
-
const seam = writeSeam(root, decisions);
|
|
3714
|
+
const seam = writeSeam(root, decisions, framework);
|
|
3644
3715
|
return seam === void 0 ? steps : [...steps, seam];
|
|
3645
3716
|
}
|
|
3646
3717
|
function runInit(options) {
|
|
3647
3718
|
const root = (0, import_node_path6.resolve)(options.cwd);
|
|
3648
3719
|
const decisions = options.decisions ?? planInit(root).decisions;
|
|
3649
|
-
return { root, decisions, steps: scaffold(root, [], false, decisions) };
|
|
3720
|
+
return { root, decisions, steps: scaffold(root, [], false, decisions, options.framework) };
|
|
3650
3721
|
}
|
|
3651
3722
|
function renderInit(result2) {
|
|
3652
3723
|
const steps = result2.steps.map((step) => {
|
|
@@ -3713,7 +3784,15 @@ var initCommand = (0, import_citty9.defineCommand)({
|
|
|
3713
3784
|
if (!asked) {
|
|
3714
3785
|
write([...plan2.notes, ""]);
|
|
3715
3786
|
}
|
|
3716
|
-
write(
|
|
3787
|
+
write(
|
|
3788
|
+
renderInit(
|
|
3789
|
+
runInit({
|
|
3790
|
+
cwd: root,
|
|
3791
|
+
decisions,
|
|
3792
|
+
...plan2.detected && { framework: plan2.detected.name }
|
|
3793
|
+
})
|
|
3794
|
+
)
|
|
3795
|
+
);
|
|
3717
3796
|
});
|
|
3718
3797
|
}
|
|
3719
3798
|
});
|