envlock-next 0.4.0 → 0.6.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/cli/index.js +180 -14
- package/dist/index.cjs +45 -0
- package/dist/index.d.cts +10 -0
- package/dist/postinstall.cjs +64 -0
- package/package.json +15 -6
package/dist/cli/index.js
CHANGED
|
@@ -2,29 +2,162 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
5
|
+
import { realpathSync } from "fs";
|
|
5
6
|
import { Command } from "commander";
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
// ../core/dist/index.js
|
|
9
|
+
import { spawnSync } from "child_process";
|
|
10
|
+
import { execFileSync } from "child_process";
|
|
11
|
+
import { isAbsolute, relative, resolve } from "path";
|
|
12
|
+
import { createServer } from "net";
|
|
13
|
+
var verbose = false;
|
|
14
|
+
function setVerbose(flag) {
|
|
15
|
+
verbose = flag;
|
|
16
|
+
}
|
|
17
|
+
var log = {
|
|
18
|
+
debug: (msg) => {
|
|
19
|
+
if (verbose) process.stderr.write(`[envlock:debug] ${msg}
|
|
20
|
+
`);
|
|
21
|
+
},
|
|
22
|
+
info: (msg) => {
|
|
23
|
+
process.stderr.write(`[envlock] ${msg}
|
|
24
|
+
`);
|
|
25
|
+
},
|
|
26
|
+
warn: (msg) => {
|
|
27
|
+
process.stderr.write(`[envlock] Warning: ${msg}
|
|
28
|
+
`);
|
|
29
|
+
},
|
|
30
|
+
error: (msg) => {
|
|
31
|
+
process.stderr.write(`[envlock] Error: ${msg}
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var WHICH = process.platform === "win32" ? "where" : "which";
|
|
36
|
+
function hasBinary(name) {
|
|
37
|
+
try {
|
|
38
|
+
execFileSync(WHICH, [name], { stdio: "pipe" });
|
|
39
|
+
return true;
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function checkBinary(name, installHint) {
|
|
45
|
+
if (!hasBinary(name)) {
|
|
46
|
+
throw new Error(`[envlock] '${name}' not found in PATH.
|
|
47
|
+
${installHint}`);
|
|
48
|
+
}
|
|
49
|
+
log.debug(`Binary check: ${name} found`);
|
|
50
|
+
}
|
|
51
|
+
function runWithSecrets(options) {
|
|
52
|
+
const { envFile, environment, onePasswordEnvId, command, args } = options;
|
|
53
|
+
checkBinary(
|
|
54
|
+
"dotenvx",
|
|
55
|
+
"Install dotenvx: npm install -g @dotenvx/dotenvx\nOr add it as a dev dependency."
|
|
56
|
+
);
|
|
57
|
+
const privateKeyVar = `DOTENV_PRIVATE_KEY_${environment.toUpperCase()}`;
|
|
58
|
+
const keyAlreadyInjected = !!process.env[privateKeyVar];
|
|
59
|
+
let result;
|
|
60
|
+
if (keyAlreadyInjected) {
|
|
61
|
+
log.debug(`Spawning: dotenvx run -f ${envFile} -- ${command} ${args.join(" ")}`);
|
|
62
|
+
result = spawnSync(
|
|
63
|
+
"dotenvx",
|
|
64
|
+
["run", "-f", envFile, "--", command, ...args],
|
|
65
|
+
{ stdio: "inherit" }
|
|
66
|
+
);
|
|
67
|
+
if (result.error) {
|
|
68
|
+
throw new Error(`[envlock] Failed to spawn 'dotenvx': ${result.error.message}`);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
checkBinary(
|
|
72
|
+
"op",
|
|
73
|
+
"Install 1Password CLI: brew install --cask 1password-cli@beta\nThen sign in: op signin"
|
|
74
|
+
);
|
|
75
|
+
log.debug(`Spawning: op run --environment ${onePasswordEnvId} -- dotenvx run -f ${envFile} -- ${command} ${args.join(" ")}`);
|
|
76
|
+
result = spawnSync(
|
|
77
|
+
"op",
|
|
78
|
+
[
|
|
79
|
+
"run",
|
|
80
|
+
"--environment",
|
|
81
|
+
onePasswordEnvId,
|
|
82
|
+
"--",
|
|
83
|
+
"dotenvx",
|
|
84
|
+
"run",
|
|
85
|
+
"-f",
|
|
86
|
+
envFile,
|
|
87
|
+
"--",
|
|
88
|
+
command,
|
|
89
|
+
...args
|
|
90
|
+
],
|
|
91
|
+
{ stdio: "inherit" }
|
|
92
|
+
);
|
|
93
|
+
if (result.error) {
|
|
94
|
+
throw new Error(`[envlock] Failed to spawn 'op': ${result.error.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
process.exit(result.status ?? 1);
|
|
98
|
+
}
|
|
99
|
+
var OP_ENV_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
100
|
+
function validateOnePasswordEnvId(id) {
|
|
101
|
+
if (!id || !OP_ENV_ID_PATTERN.test(id)) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`[envlock] Invalid onePasswordEnvId: "${id}". Must be a lowercase alphanumeric string (hyphens allowed), e.g. 'ca6uypwvab5mevel44gqdc2zae'.`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function validateEnvFilePath(envFile, cwd) {
|
|
108
|
+
if (envFile.includes("\0")) {
|
|
109
|
+
throw new Error(`[envlock] Invalid env file path: null bytes are not allowed.`);
|
|
110
|
+
}
|
|
111
|
+
const resolved = resolve(cwd, envFile);
|
|
112
|
+
const base = resolve(cwd);
|
|
113
|
+
const rel = relative(base, resolved);
|
|
114
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`[envlock] Invalid env file path: "${envFile}" resolves outside the project directory.`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
var ENVIRONMENTS = {
|
|
121
|
+
development: "development",
|
|
122
|
+
staging: "staging",
|
|
123
|
+
production: "production"
|
|
124
|
+
};
|
|
125
|
+
function isPortFree(port) {
|
|
126
|
+
return new Promise((resolve22) => {
|
|
127
|
+
const server = createServer();
|
|
128
|
+
server.once("error", () => resolve22(false));
|
|
129
|
+
server.once("listening", () => server.close(() => resolve22(true)));
|
|
130
|
+
server.listen(port, "127.0.0.1");
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async function findFreePort(preferred) {
|
|
134
|
+
for (let port = preferred; port <= preferred + 10; port++) {
|
|
135
|
+
if (await isPortFree(port)) return port;
|
|
136
|
+
}
|
|
137
|
+
throw new Error(
|
|
138
|
+
`[envlock] No free port found in range ${preferred}\u2013${preferred + 10}.`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
7
141
|
|
|
8
142
|
// src/cli/resolve-config.ts
|
|
9
143
|
import { existsSync } from "fs";
|
|
10
|
-
import { resolve } from "path";
|
|
144
|
+
import { resolve as resolve2 } from "path";
|
|
11
145
|
import { pathToFileURL } from "url";
|
|
12
|
-
|
|
13
|
-
var CONFIG_CANDIDATES = ["next.config.js", "next.config.mjs"];
|
|
146
|
+
var CONFIG_CANDIDATES = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
14
147
|
async function resolveConfig(cwd) {
|
|
15
148
|
for (const candidate of CONFIG_CANDIDATES) {
|
|
16
|
-
const fullPath =
|
|
149
|
+
const fullPath = resolve2(cwd, candidate);
|
|
17
150
|
if (!existsSync(fullPath)) continue;
|
|
18
151
|
try {
|
|
19
152
|
const mod = await import(pathToFileURL(fullPath).href);
|
|
20
153
|
const config = mod.default ?? mod;
|
|
21
154
|
if (config && typeof config === "object" && "__envlock" in config && config.__envlock && typeof config.__envlock === "object" && "onePasswordEnvId" in config.__envlock) {
|
|
155
|
+
log.debug(`Config loaded from ${candidate}`);
|
|
22
156
|
return config.__envlock;
|
|
23
157
|
}
|
|
24
158
|
} catch (err) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
159
|
+
log.warn(`Failed to load ${candidate}: ${err instanceof Error ? err.message : String(err)}`);
|
|
160
|
+
log.debug(`Stack: ${err instanceof Error ? err.stack ?? "" : ""}`);
|
|
28
161
|
}
|
|
29
162
|
}
|
|
30
163
|
if (process.env["ENVLOCK_OP_ENV_ID"]) {
|
|
@@ -61,12 +194,30 @@ async function runNextCommand(subcommand, environment, passthroughArgs) {
|
|
|
61
194
|
const config = await resolveConfig(process.cwd());
|
|
62
195
|
const envFile = config.envFiles?.[environment] ?? DEFAULT_ENV_FILES[environment];
|
|
63
196
|
validateEnvFilePath(envFile, process.cwd());
|
|
197
|
+
let finalArgs = [...passthroughArgs];
|
|
198
|
+
if (subcommand === "dev") {
|
|
199
|
+
const portFlagIndex = finalArgs.findIndex(
|
|
200
|
+
(a) => a === "--port" || a === "-p"
|
|
201
|
+
);
|
|
202
|
+
const requestedPort = portFlagIndex !== -1 ? parseInt(finalArgs[portFlagIndex + 1] ?? "3000", 10) : 3e3;
|
|
203
|
+
const freePort = await findFreePort(requestedPort);
|
|
204
|
+
if (freePort !== requestedPort) {
|
|
205
|
+
log.warn(`Port ${requestedPort} in use, switching to ${freePort}`);
|
|
206
|
+
}
|
|
207
|
+
if (portFlagIndex !== -1) {
|
|
208
|
+
finalArgs.splice(portFlagIndex, 2);
|
|
209
|
+
}
|
|
210
|
+
finalArgs = ["-p", String(freePort), ...finalArgs];
|
|
211
|
+
}
|
|
212
|
+
log.debug(`Environment: ${environment}`);
|
|
213
|
+
log.debug(`Env file: ${envFile}`);
|
|
214
|
+
log.debug(`Command: next ${subcommand} ${finalArgs.join(" ")}`);
|
|
64
215
|
runWithSecrets({
|
|
65
216
|
envFile,
|
|
66
217
|
environment,
|
|
67
218
|
onePasswordEnvId: config.onePasswordEnvId,
|
|
68
219
|
command: "next",
|
|
69
|
-
args: [subcommand, ...
|
|
220
|
+
args: [subcommand, ...finalArgs]
|
|
70
221
|
});
|
|
71
222
|
}
|
|
72
223
|
function addEnvFlags(cmd) {
|
|
@@ -91,9 +242,12 @@ async function handleRunCommand(cmd, cmdArgs, opts) {
|
|
|
91
242
|
"[envlock] No onePasswordEnvId found. Set it in envlock.config.js or via ENVLOCK_OP_ENV_ID env var."
|
|
92
243
|
);
|
|
93
244
|
}
|
|
94
|
-
|
|
245
|
+
validateOnePasswordEnvId(onePasswordEnvId);
|
|
95
246
|
const envFile = config.envFiles?.[environment] ?? DEFAULT_ENV_FILES[environment];
|
|
96
247
|
validateEnvFilePath(envFile, process.cwd());
|
|
248
|
+
log.debug(`Environment: ${environment}`);
|
|
249
|
+
log.debug(`Env file: ${envFile}`);
|
|
250
|
+
log.debug(`Command: ${cmd} ${cmdArgs.join(" ")}`);
|
|
97
251
|
runWithSecrets({
|
|
98
252
|
envFile,
|
|
99
253
|
environment,
|
|
@@ -103,7 +257,7 @@ async function handleRunCommand(cmd, cmdArgs, opts) {
|
|
|
103
257
|
});
|
|
104
258
|
}
|
|
105
259
|
var program = new Command("envlock");
|
|
106
|
-
program.name("envlock").description("Run Next.js commands with 1Password + dotenvx secret injection").version("0.3.0").enablePositionalOptions();
|
|
260
|
+
program.name("envlock").description("Run Next.js commands with 1Password + dotenvx secret injection").version("0.3.0").enablePositionalOptions().option("-d, --debug", "enable debug output");
|
|
107
261
|
for (const [subcommand, defaultEnv] of Object.entries(
|
|
108
262
|
SUPPORTED_SUBCOMMANDS
|
|
109
263
|
)) {
|
|
@@ -122,15 +276,27 @@ addEnvFlags(runCmd).action(
|
|
|
122
276
|
try {
|
|
123
277
|
await handleRunCommand(cmd, cmdArgs, opts);
|
|
124
278
|
} catch (err) {
|
|
125
|
-
|
|
279
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
126
280
|
process.exit(1);
|
|
127
281
|
}
|
|
128
282
|
}
|
|
129
283
|
);
|
|
130
284
|
program.addCommand(runCmd);
|
|
131
|
-
|
|
285
|
+
var _resolvedArgv1Next = (() => {
|
|
286
|
+
try {
|
|
287
|
+
return realpathSync(process.argv[1] ?? "");
|
|
288
|
+
} catch {
|
|
289
|
+
return process.argv[1] ?? "";
|
|
290
|
+
}
|
|
291
|
+
})();
|
|
292
|
+
if (import.meta.url === pathToFileURL2(_resolvedArgv1Next).href) {
|
|
293
|
+
if (process.argv.includes("--debug") || process.argv.includes("-d")) {
|
|
294
|
+
setVerbose(true);
|
|
295
|
+
}
|
|
296
|
+
log.debug(`Resolved argv[1]: ${_resolvedArgv1Next}`);
|
|
132
297
|
program.parse(process.argv);
|
|
133
298
|
}
|
|
134
299
|
export {
|
|
135
|
-
handleRunCommand
|
|
300
|
+
handleRunCommand,
|
|
301
|
+
runNextCommand
|
|
136
302
|
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
withEnvlock: () => withEnvlock
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(src_exports);
|
|
26
|
+
|
|
27
|
+
// src/plugin.ts
|
|
28
|
+
var import_envlock_core = require("envlock-core");
|
|
29
|
+
function withEnvlock(nextConfig, options) {
|
|
30
|
+
if (!options?.onePasswordEnvId) {
|
|
31
|
+
console.warn(
|
|
32
|
+
"[envlock] No onePasswordEnvId provided to withEnvlock(). Set it to your 1Password Environment ID for automatic secret injection. Alternatively, set ENVLOCK_OP_ENV_ID in your environment."
|
|
33
|
+
);
|
|
34
|
+
} else {
|
|
35
|
+
(0, import_envlock_core.validateOnePasswordEnvId)(options.onePasswordEnvId);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
...nextConfig,
|
|
39
|
+
__envlock: options ?? { onePasswordEnvId: "" }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
withEnvlock
|
|
45
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NextConfig } from 'next';
|
|
2
|
+
import { EnvlockOptions } from 'envlock-core';
|
|
3
|
+
export { EnvlockOptions } from 'envlock-core';
|
|
4
|
+
|
|
5
|
+
type EnvlockNextConfig = NextConfig & {
|
|
6
|
+
__envlock: EnvlockOptions;
|
|
7
|
+
};
|
|
8
|
+
declare function withEnvlock(nextConfig: NextConfig, options?: EnvlockOptions): EnvlockNextConfig;
|
|
9
|
+
|
|
10
|
+
export { type EnvlockNextConfig, withEnvlock };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/postinstall.ts
|
|
21
|
+
var postinstall_exports = {};
|
|
22
|
+
__export(postinstall_exports, {
|
|
23
|
+
rewriteScripts: () => rewriteScripts
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(postinstall_exports);
|
|
26
|
+
var import_node_fs = require("fs");
|
|
27
|
+
var import_node_path = require("path");
|
|
28
|
+
var REWRITES = [
|
|
29
|
+
{ from: /(?<![envlock\s])next dev/, to: "envlock dev", cmd: "dev" },
|
|
30
|
+
{ from: /(?<![envlock\s])next build/, to: "envlock build", cmd: "build" },
|
|
31
|
+
{ from: /(?<![envlock\s])next start/, to: "envlock start", cmd: "start" }
|
|
32
|
+
];
|
|
33
|
+
function rewriteScripts(projectRoot2) {
|
|
34
|
+
const pkgPath = (0, import_node_path.join)(projectRoot2, "package.json");
|
|
35
|
+
if (!(0, import_node_fs.existsSync)(pkgPath)) return;
|
|
36
|
+
let pkg;
|
|
37
|
+
try {
|
|
38
|
+
pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf8"));
|
|
39
|
+
} catch {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!pkg.scripts) return;
|
|
43
|
+
let changed = false;
|
|
44
|
+
for (const { from, to, cmd } of REWRITES) {
|
|
45
|
+
const script = pkg.scripts[cmd];
|
|
46
|
+
if (!script) continue;
|
|
47
|
+
if (script.includes("envlock")) continue;
|
|
48
|
+
if (!from.test(script)) continue;
|
|
49
|
+
pkg.scripts[cmd] = script.replace(from, to);
|
|
50
|
+
console.log(`[envlock] Updated scripts.${cmd}: "${script}" \u2192 "${pkg.scripts[cmd]}"`);
|
|
51
|
+
changed = true;
|
|
52
|
+
}
|
|
53
|
+
if (changed) {
|
|
54
|
+
(0, import_node_fs.writeFileSync)(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
var projectRoot = process.env["INIT_CWD"];
|
|
58
|
+
if (projectRoot) {
|
|
59
|
+
rewriteScripts(projectRoot);
|
|
60
|
+
}
|
|
61
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
62
|
+
0 && (module.exports = {
|
|
63
|
+
rewriteScripts
|
|
64
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envlock-next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Next.js plugin and CLI for envlock",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,24 +22,33 @@
|
|
|
22
22
|
},
|
|
23
23
|
"exports": {
|
|
24
24
|
".": {
|
|
25
|
-
"
|
|
26
|
-
"
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"require": "./dist/index.cjs",
|
|
27
|
+
"import": "./dist/index.js"
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
|
-
"
|
|
30
|
+
"main": "./dist/index.cjs",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
30
34
|
"scripts": {
|
|
31
35
|
"build": "tsup",
|
|
32
36
|
"dev": "tsup --watch",
|
|
33
37
|
"test": "vitest run",
|
|
34
|
-
"test:watch": "vitest"
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"postinstall": "node ./dist/postinstall.cjs"
|
|
35
40
|
},
|
|
36
41
|
"dependencies": {
|
|
37
|
-
"envlock-core": "
|
|
42
|
+
"envlock-core": "^0.6.0",
|
|
38
43
|
"commander": "^12.0.0"
|
|
39
44
|
},
|
|
40
45
|
"peerDependencies": {
|
|
46
|
+
"@dotenvx/dotenvx": ">=1.0.0",
|
|
41
47
|
"next": ">=14.0.0"
|
|
42
48
|
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@dotenvx/dotenvx": { "optional": false }
|
|
51
|
+
},
|
|
43
52
|
"devDependencies": {
|
|
44
53
|
"envlock-core": "workspace:*",
|
|
45
54
|
"@types/node": "^20.14.10",
|