vercel 59.11.2 → 59.11.7
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/chunks/{add-BKSHWTPX.js → add-KSJQYR5C.js} +23 -18
- package/dist/chunks/{add-RBW7QITR.js → add-PERLOALD.js} +37 -23
- package/dist/chunks/{add-HPLJZFM2.js → add-WU2QYHYL.js} +23 -18
- package/dist/chunks/{build-V4ZLAJWB.js → build-F3J6FLPD.js} +23 -18
- package/dist/chunks/{chunk-NGGLYKNU.js → chunk-26CU4Q3C.js} +3 -115
- package/dist/chunks/{chunk-QFAS4OVW.js → chunk-2JIX6UMI.js} +3 -84
- package/dist/chunks/chunk-2TSBB22D.js +14059 -0
- package/dist/chunks/chunk-332LMJLZ.js +16014 -0
- package/dist/chunks/{chunk-AYLY3ZVL.js → chunk-3VM7HWF6.js} +2 -2
- package/dist/chunks/chunk-4IALDGB7.js +22 -0
- package/dist/chunks/chunk-4IVSM24H.js +522 -0
- package/dist/chunks/{chunk-5XECIWME.js → chunk-5NF5HOBJ.js} +5 -3
- package/dist/chunks/chunk-6E6KPBXY.js +43 -0
- package/dist/chunks/chunk-7KROIXQM.js +59 -0
- package/dist/chunks/{chunk-ASBP32T6.js → chunk-7MRDIPJY.js} +1 -1
- package/dist/chunks/chunk-A5JZS6ZN.js +92 -0
- package/dist/chunks/{chunk-7ST552E3.js → chunk-AKLTIZCU.js} +1 -1
- package/dist/chunks/{chunk-26XDDLXM.js → chunk-ARU7VBKR.js} +2 -2
- package/dist/chunks/chunk-B5XLQKHI.js +849 -0
- package/dist/chunks/chunk-C762AAVU.js +137 -0
- package/dist/chunks/{chunk-WA2SJE5S.js → chunk-CEDN47PH.js} +4 -4
- package/dist/chunks/{chunk-ONRLTUP2.js → chunk-CNDPIHY5.js} +24 -22
- package/dist/chunks/{chunk-BMKU5KEL.js → chunk-CV5YC2EN.js} +1 -1
- package/dist/chunks/chunk-DBYHS3CK.js +257 -0
- package/dist/chunks/{chunk-HDBQPBL6.js → chunk-DSTNNQVV.js} +12 -8
- package/dist/chunks/{chunk-QAT3CW4G.js → chunk-EFYMIIER.js} +2 -2
- package/dist/chunks/{chunk-NBW3BWOJ.js → chunk-EPOLDWRA.js} +2 -2
- package/dist/chunks/{chunk-B4TXCKXE.js → chunk-EZQDYIVB.js} +10 -8
- package/dist/chunks/{chunk-2EAIC3SH.js → chunk-FL4JLNT2.js} +8 -8
- package/dist/chunks/chunk-FRVG4OW3.js +7438 -0
- package/dist/chunks/{chunk-FKDO3CM4.js → chunk-FVNJTRCE.js} +17 -13
- package/dist/chunks/chunk-FVT74RZ5.js +1536 -0
- package/dist/chunks/chunk-G3PXSXIB.js +18188 -0
- package/dist/chunks/chunk-G5FBSUL4.js +822 -0
- package/dist/chunks/{chunk-FRAXI2WT.js → chunk-GCVXKRR5.js} +3 -3
- package/dist/chunks/chunk-GHKJAK5V.js +1288 -0
- package/dist/chunks/{chunk-Q5K5DEOK.js → chunk-GUU4Z2AQ.js} +42 -28
- package/dist/chunks/{chunk-OQ3C5VXZ.js → chunk-GVNCVKCI.js} +4 -2
- package/dist/chunks/chunk-HB4UKFDO.js +1295 -0
- package/dist/chunks/chunk-HRXRELD3.js +338 -0
- package/dist/chunks/{chunk-IJ4X426J.js → chunk-IIMSID24.js} +1 -1
- package/dist/chunks/{chunk-O75LSD3C.js → chunk-JSD4EZL3.js} +1 -1
- package/dist/chunks/{chunk-7AEEQOD4.js → chunk-K3RED3VO.js} +1 -1
- package/dist/chunks/{chunk-RSEAADCE.js → chunk-KEKR7OCB.js} +6 -4
- package/dist/chunks/{chunk-3T7WSWZH.js → chunk-KFWQ3EFH.js} +1 -1
- package/dist/chunks/{chunk-L3UXB2CW.js → chunk-KW7BS25T.js} +1 -1
- package/dist/chunks/{chunk-RO44KX6Y.js → chunk-N4QHMXOO.js} +11 -7
- package/dist/chunks/{chunk-XRWOTCDO.js → chunk-ND5CF2H3.js} +1 -1
- package/dist/chunks/{chunk-RSJBU3ON.js → chunk-NSOYO6JQ.js} +35 -27
- package/dist/chunks/{chunk-RKDCNQ4S.js → chunk-NW34PW6V.js} +3 -105
- package/dist/chunks/{chunk-C5HKWXRR.js → chunk-OAMU5QO6.js} +1 -1
- package/dist/chunks/{chunk-MTWHQEXI.js → chunk-OIH6FP5Y.js} +5 -3
- package/dist/chunks/chunk-P7VSBDR4.js +827 -0
- package/dist/chunks/chunk-PEC3CQSK.js +90 -0
- package/dist/chunks/{chunk-QDV5LZ4Q.js → chunk-PFM75KY3.js} +12 -8
- package/dist/chunks/chunk-PJXMXMCO.js +81 -0
- package/dist/chunks/chunk-PNGVSHR3.js +40 -0
- package/dist/chunks/{chunk-TPATD2MM.js → chunk-QHS645AZ.js} +14 -6
- package/dist/chunks/{chunk-OTXE7MHI.js → chunk-QKX7WKIN.js} +8 -6
- package/dist/chunks/chunk-QOPTXV4G.js +417 -0
- package/dist/chunks/chunk-RN6V5ODW.js +114 -0
- package/dist/chunks/chunk-RVBZ64EQ.js +52 -0
- package/dist/chunks/chunk-SHFNEZVI.js +49 -0
- package/dist/chunks/{chunk-OO3OF6MK.js → chunk-TGNEG57M.js} +44 -15
- package/dist/chunks/{chunk-WNAKOXGK.js → chunk-TO7QZGYK.js} +1 -1
- package/dist/chunks/chunk-UARGTFCT.js +875 -0
- package/dist/chunks/{chunk-FWKSJYDV.js → chunk-UG2WOB5L.js} +1 -1
- package/dist/chunks/chunk-V4RMJKQP.js +36 -0
- package/dist/chunks/chunk-VT3Z7HF6.js +233 -0
- package/dist/chunks/chunk-VUS2JQB2.js +121 -0
- package/dist/chunks/{chunk-6CZZ3SH3.js → chunk-VYC45Q4Z.js} +2 -2
- package/dist/chunks/{chunk-4KVJ2M4J.js → chunk-WL6QYSGD.js} +78 -17
- package/dist/chunks/{chunk-FZRBF25Y.js → chunk-X7DBBZQD.js} +4 -4
- package/dist/chunks/{chunk-2NJJ2K5S.js → chunk-XD4DCYMX.js} +6 -6
- package/dist/chunks/{chunk-ZSFEACZU.js → chunk-XFF5TGRA.js} +1 -1
- package/dist/chunks/{chunk-6TBDHUXK.js → chunk-XIFATBH5.js} +21 -15
- package/dist/chunks/chunk-XNIZGCN5.js +58 -0
- package/dist/chunks/chunk-XPJLPUKO.js +117 -0
- package/dist/chunks/{chunk-FXD67VN5.js → chunk-XUAWTW4W.js} +1 -1
- package/dist/chunks/{chunk-I526H4AS.js → chunk-YS76T533.js} +2 -2
- package/dist/chunks/chunk-Z7JWYFOY.js +58 -0
- package/dist/chunks/{chunk-6JPVTPTU.js → chunk-ZBEECGFD.js} +3 -3
- package/dist/chunks/{chunk-52QYYTM5.js → chunk-ZDU2NODC.js} +3 -127
- package/dist/chunks/chunk-ZW6HETRE.js +97 -0
- package/dist/chunks/{clear-IYGWCNXT.js → clear-XUQO4ZTK.js} +23 -18
- package/dist/chunks/{compile-vercel-config-NEEBZRUJ.js → compile-vercel-config-D3ARNHTN.js} +8 -11
- package/dist/chunks/{config-6DS6BBR2.js → config-37OAE7QJ.js} +22 -17
- package/dist/chunks/{config-NTB5EMV4.js → config-MEDLXUVM.js} +23 -18
- package/dist/chunks/{delete-LLC2OGHA.js → delete-3N3YZZOF.js} +16 -12
- package/dist/chunks/{delete-LSGID5FV.js → delete-VSWDZ2SW.js} +19 -14
- package/dist/chunks/detect-projects-ODNU4PK2.js +18 -0
- package/dist/chunks/detect-services-TESZCQWG.js +40 -0
- package/dist/chunks/{disable-H4EXEQK7.js → disable-A4FLFMC7.js} +17 -13
- package/dist/chunks/{discard-FG6VKHWN.js → discard-CHGFULBZ.js} +17 -13
- package/dist/chunks/{edit-YE7D3CPJ.js → edit-JZ63AJYQ.js} +17 -13
- package/dist/chunks/{edit-BZJSGUHT.js → edit-MHSYAPDR.js} +19 -15
- package/dist/chunks/{enable-6ESD4QTE.js → enable-KD46SEC5.js} +17 -13
- package/dist/chunks/{exec-XH4K34JM.js → exec-4IPHZ55G.js} +9 -5
- package/dist/chunks/{export-QWSJROLG.js → export-42QZLBSN.js} +16 -13
- package/dist/chunks/{image-LTHQMKFG.js → image-GP4H73A2.js} +11 -8
- package/dist/chunks/{import-builders-6O7ILGQJ.js → import-builders-6TBLMPL2.js} +18 -13
- package/dist/chunks/{inspect-2C4ZSNYC.js → inspect-5FMWMY3C.js} +22 -18
- package/dist/chunks/{inspect-N6SMHV3Z.js → inspect-MUVK6MMT.js} +18 -14
- package/dist/chunks/{inspect-F7KCTHIL.js → inspect-Q3DWW7MC.js} +22 -18
- package/dist/chunks/{inspect-TWDPMXZ5.js → inspect-QFXAOUL4.js} +18 -14
- package/dist/chunks/{inspect-ICKNCDMT.js → inspect-RNTSYM6O.js} +18 -14
- package/dist/chunks/{list-NWTIJF3L.js → list-IHHIPXEC.js} +20 -16
- package/dist/chunks/{list-IPGQVBJO.js → list-JRNWLSO5.js} +16 -14
- package/dist/chunks/{list-DS7ZOUXA.js → list-XHD5DLEX.js} +23 -19
- package/dist/chunks/{login-F7A7ONKC.js → login-PCT6KFWY.js} +23 -18
- package/dist/chunks/{ls-NBDX3MKN.js → ls-GPEHEFCF.js} +24 -18
- package/dist/chunks/{ls-RNGO257R.js → ls-PF7F4PP4.js} +27 -23
- package/dist/chunks/{ls-XINES6PL.js → ls-PQZ2RIDX.js} +24 -18
- package/dist/chunks/{ls-D4TUDBIH.js → ls-SVOHC3XW.js} +24 -18
- package/dist/chunks/{ls-2QW3ZSM6.js → ls-TGHCCARZ.js} +24 -18
- package/dist/chunks/{ls-LSJEUPFX.js → ls-VRIH5WA3.js} +22 -15
- package/dist/chunks/{open-VRQDWZAW.js → open-E7DEKYDU.js} +18 -13
- package/dist/chunks/{permissions-6C5C7TEV.js → permissions-JKOONWVL.js} +14 -11
- package/dist/chunks/{publish-GVIZPNLN.js → publish-EDDELDE5.js} +17 -13
- package/dist/chunks/pull-646WEVDE.js +45 -0
- package/dist/chunks/{push-EFZ5P5Z6.js → push-LTNW5OVD.js} +23 -18
- package/dist/chunks/{query-GBS2PIT4.js → query-LU4N6KPO.js} +22 -19
- package/dist/chunks/{reorder-TN65IFRL.js → reorder-22PKJMZP.js} +17 -13
- package/dist/chunks/{reply-DYVEV3PY.js → reply-SF2EZMVZ.js} +17 -13
- package/dist/chunks/{resolve-JAWFBPUM.js → resolve-ZCZGXTOT.js} +16 -12
- package/dist/chunks/resolve-deployment-framework-preset-NPE6RLV3.js +36 -0
- package/dist/chunks/{restore-TJVMHUBQ.js → restore-VJAWZXB4.js} +17 -13
- package/dist/chunks/{rm-7XACNZ2U.js → rm-KN2QFCKO.js} +23 -18
- package/dist/chunks/{rm-REJVXALW.js → rm-KVEAJPRE.js} +23 -18
- package/dist/chunks/{rm-CBPNMSRP.js → rm-OSZ5FZUM.js} +23 -16
- package/dist/chunks/{rm-5B5VHWWN.js → rm-W722Q2AO.js} +21 -18
- package/dist/chunks/{rm-HQ5CYNJA.js → rm-WNPGTUBH.js} +23 -18
- package/dist/chunks/{routes-2OLIBRYX.js → routes-QVMBXOSX.js} +7 -3
- package/dist/chunks/{rule-inspect-ZSTDDFID.js → rule-inspect-25Z6SNX3.js} +28 -24
- package/dist/chunks/{rules-VGV4M4KY.js → rules-65LKAQ35.js} +15 -12
- package/dist/chunks/{schema-45SJNY5L.js → schema-7D6IGJEJ.js} +9 -7
- package/dist/chunks/{schema-GMTQOQCV.js → schema-NXCW4M75.js} +19 -17
- package/dist/chunks/{set-Z5FO2FCC.js → set-FYJVKMPV.js} +20 -13
- package/dist/chunks/setup-and-link-KXPZE32P.js +65 -0
- package/dist/chunks/{tags-SDRXWJ63.js → tags-ANIRP5E3.js} +10 -7
- package/dist/chunks/{types-JGANJ5EQ.js → types-4GAJ7XQQ.js} +9 -7
- package/dist/chunks/{update-JBQBC3IV.js → update-UT6CTKVG.js} +32 -19
- package/dist/commands/build/index.js +86 -49
- package/dist/commands/deploy/index.js +75 -66
- package/dist/commands/dev/index.js +98 -52
- package/dist/commands/env/index.js +67 -43
- package/dist/commands/link/index.js +48 -27
- package/dist/commands/list/index.js +33 -22
- package/dist/commands-bulk.js +1659 -1287
- package/dist/index.js +62 -40
- package/dist/version.mjs +1 -1
- package/package.json +46 -46
- package/dist/chunks/chunk-WYU64FLP.js +0 -62123
- package/dist/chunks/chunk-XNFHNTS2.js +0 -2939
|
@@ -0,0 +1,1288 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module';
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname as __dirname_ } from 'node:path';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __dirname_(__filename);
|
|
7
|
+
import {
|
|
8
|
+
resolveProjectContext
|
|
9
|
+
} from "./chunk-7KROIXQM.js";
|
|
10
|
+
import {
|
|
11
|
+
require_frameworks
|
|
12
|
+
} from "./chunk-FRVG4OW3.js";
|
|
13
|
+
import {
|
|
14
|
+
require_json_parse_better_errors
|
|
15
|
+
} from "./chunk-6E6KPBXY.js";
|
|
16
|
+
import {
|
|
17
|
+
ensureLink,
|
|
18
|
+
parseEnv
|
|
19
|
+
} from "./chunk-C762AAVU.js";
|
|
20
|
+
import {
|
|
21
|
+
pullSubcommand
|
|
22
|
+
} from "./chunk-XUAWTW4W.js";
|
|
23
|
+
import {
|
|
24
|
+
performDeviceCodeFlow
|
|
25
|
+
} from "./chunk-DBYHS3CK.js";
|
|
26
|
+
import {
|
|
27
|
+
STANDARD_ENVIRONMENTS,
|
|
28
|
+
formatProject
|
|
29
|
+
} from "./chunk-PNGVSHR3.js";
|
|
30
|
+
import {
|
|
31
|
+
getDeployment,
|
|
32
|
+
parseTarget
|
|
33
|
+
} from "./chunk-RN6V5ODW.js";
|
|
34
|
+
import {
|
|
35
|
+
TelemetryClient
|
|
36
|
+
} from "./chunk-HB4UKFDO.js";
|
|
37
|
+
import {
|
|
38
|
+
printError
|
|
39
|
+
} from "./chunk-3VM7HWF6.js";
|
|
40
|
+
import {
|
|
41
|
+
parseArguments
|
|
42
|
+
} from "./chunk-57RHXXXG.js";
|
|
43
|
+
import {
|
|
44
|
+
addToGitIgnore,
|
|
45
|
+
param,
|
|
46
|
+
printAlignedLabel,
|
|
47
|
+
require_lib
|
|
48
|
+
} from "./chunk-2TSBB22D.js";
|
|
49
|
+
import {
|
|
50
|
+
buildCommandWithYes,
|
|
51
|
+
getPreservedArgsForEnvPull,
|
|
52
|
+
outputActionRequired,
|
|
53
|
+
outputAgentError
|
|
54
|
+
} from "./chunk-26CU4Q3C.js";
|
|
55
|
+
import {
|
|
56
|
+
isAPIError
|
|
57
|
+
} from "./chunk-CV5YC2EN.js";
|
|
58
|
+
import {
|
|
59
|
+
getCommandName,
|
|
60
|
+
getCommandNamePlain,
|
|
61
|
+
getFlagsSpecification
|
|
62
|
+
} from "./chunk-Q2DGFCO7.js";
|
|
63
|
+
import {
|
|
64
|
+
output_manager_default
|
|
65
|
+
} from "./chunk-2JIX6UMI.js";
|
|
66
|
+
import {
|
|
67
|
+
require_dist
|
|
68
|
+
} from "./chunk-ZW6HETRE.js";
|
|
69
|
+
import {
|
|
70
|
+
require_source
|
|
71
|
+
} from "./chunk-S7KYDPEM.js";
|
|
72
|
+
import {
|
|
73
|
+
__toESM
|
|
74
|
+
} from "./chunk-TZ2YI2VH.js";
|
|
75
|
+
|
|
76
|
+
// src/commands/env/pull.ts
|
|
77
|
+
var import_chalk2 = __toESM(require_source(), 1);
|
|
78
|
+
var import_fs_extra2 = __toESM(require_lib(), 1);
|
|
79
|
+
import { closeSync, openSync, readSync } from "fs";
|
|
80
|
+
import { resolve } from "path";
|
|
81
|
+
|
|
82
|
+
// src/util/env/get-env-records.ts
|
|
83
|
+
import { URLSearchParams } from "url";
|
|
84
|
+
|
|
85
|
+
// src/util/env/challenge-recovery.ts
|
|
86
|
+
var RECOVERABLE_CHALLENGE_CODES = /* @__PURE__ */ new Set([
|
|
87
|
+
"challenge_required",
|
|
88
|
+
"challenge_required_email_otp",
|
|
89
|
+
"user_auth_required"
|
|
90
|
+
]);
|
|
91
|
+
async function withEnvChallengeRecovery(client, fn) {
|
|
92
|
+
const hadStoredSession = Boolean(
|
|
93
|
+
client.authConfig.token || client.authConfig.refreshToken
|
|
94
|
+
);
|
|
95
|
+
try {
|
|
96
|
+
return await fn();
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (!isAPIError(error)) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
const isRecoverableChallenge = RECOVERABLE_CHALLENGE_CODES.has(error.code);
|
|
102
|
+
const isRejectedStoredSession = hadStoredSession && error.invalidToken === true;
|
|
103
|
+
if (!isRecoverableChallenge && !isRejectedStoredSession) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
if (client.authConfig.tokenSource || !client.stdin.isTTY || client.nonInteractive) {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
output_manager_default.stopSpinner();
|
|
110
|
+
output_manager_default.log("Sensitive Environment Variables require fresh authentication.");
|
|
111
|
+
const refreshToken = client.authConfig.refreshToken;
|
|
112
|
+
const acrValues = getAcrValuesFromWWWAuthenticate(error.wwwAuthenticate);
|
|
113
|
+
const tokens = isRecoverableChallenge && refreshToken && acrValues ? await performDeviceCodeFlow(client, {
|
|
114
|
+
refreshToken,
|
|
115
|
+
acrValues,
|
|
116
|
+
fallbackToLoginOnStepUpFailure: true
|
|
117
|
+
}) : await performDeviceCodeFlow(client);
|
|
118
|
+
if (!tokens) {
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
client.updateAuthConfig({
|
|
122
|
+
token: tokens.access_token,
|
|
123
|
+
userId: void 0,
|
|
124
|
+
expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in,
|
|
125
|
+
refreshToken: tokens.refresh_token
|
|
126
|
+
});
|
|
127
|
+
client.persistAuthConfig();
|
|
128
|
+
return await fn();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function getAcrValuesFromWWWAuthenticate(header) {
|
|
132
|
+
if (!header) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const bearerIndex = header.toLowerCase().indexOf("bearer");
|
|
136
|
+
if (bearerIndex === -1) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const bearerChallenge = header.slice(bearerIndex + "bearer".length);
|
|
140
|
+
const match = bearerChallenge.match(
|
|
141
|
+
/(?:^|[,\s])acr_values=(?:"((?:\\.|[^"\\])*)"|([^,\s]+))/i
|
|
142
|
+
);
|
|
143
|
+
return match?.[1]?.replace(/\\(.)/g, "$1") ?? match?.[2];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/util/env/get-env-records.ts
|
|
147
|
+
async function getEnvRecords(client, projectId, source, {
|
|
148
|
+
target,
|
|
149
|
+
gitBranch,
|
|
150
|
+
decrypt
|
|
151
|
+
} = {}) {
|
|
152
|
+
output_manager_default.debug(
|
|
153
|
+
`Fetching Environment Variables of project ${projectId} and target ${target}`
|
|
154
|
+
);
|
|
155
|
+
const query = new URLSearchParams();
|
|
156
|
+
if (target) {
|
|
157
|
+
let targetParam = "target";
|
|
158
|
+
if (target !== "production" && target !== "preview" && target !== "development") {
|
|
159
|
+
targetParam = "customEnvironmentId";
|
|
160
|
+
}
|
|
161
|
+
query.set(targetParam, target);
|
|
162
|
+
}
|
|
163
|
+
if (gitBranch) {
|
|
164
|
+
query.set("gitBranch", gitBranch);
|
|
165
|
+
}
|
|
166
|
+
if (decrypt) {
|
|
167
|
+
query.set("decrypt", decrypt.toString());
|
|
168
|
+
}
|
|
169
|
+
if (source) {
|
|
170
|
+
query.set("source", source);
|
|
171
|
+
}
|
|
172
|
+
const url = `/v10/projects/${projectId}/env?${query}`;
|
|
173
|
+
return withEnvChallengeRecovery(
|
|
174
|
+
client,
|
|
175
|
+
() => client.fetch(url)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
async function pullEnvRecords(client, projectIdOrDeploymentId, source, { target, gitBranch } = {}) {
|
|
179
|
+
output_manager_default.debug(
|
|
180
|
+
`Fetching Environment Variables of ${projectIdOrDeploymentId} and target ${target}`
|
|
181
|
+
);
|
|
182
|
+
const query = new URLSearchParams();
|
|
183
|
+
let url = `/v3/env/pull/${projectIdOrDeploymentId}`;
|
|
184
|
+
if (!projectIdOrDeploymentId.startsWith("dpl_")) {
|
|
185
|
+
if (target) {
|
|
186
|
+
url += `/${encodeURIComponent(target)}`;
|
|
187
|
+
if (gitBranch) {
|
|
188
|
+
url += `/${encodeURIComponent(gitBranch)}`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (source) {
|
|
193
|
+
query.set("source", source);
|
|
194
|
+
}
|
|
195
|
+
if (Array.from(query).length > 0) {
|
|
196
|
+
url += `?${query}`;
|
|
197
|
+
}
|
|
198
|
+
return withEnvChallengeRecovery(
|
|
199
|
+
client,
|
|
200
|
+
() => client.fetch(url)
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/util/env/diff-env-files.ts
|
|
205
|
+
var import_fs_extra = __toESM(require_lib(), 1);
|
|
206
|
+
var import_chalk = __toESM(require_source(), 1);
|
|
207
|
+
async function createEnvObject(envPath) {
|
|
208
|
+
const envArr = (await (0, import_fs_extra.readFile)(envPath, "utf-8")).replace(/"/g, "").split(/\r?\n|\r/).filter((line) => /^[^#]/.test(line)).filter((line) => /=/i.test(line));
|
|
209
|
+
const parsedEnv = parseEnv(envArr);
|
|
210
|
+
if (Object.keys(parsedEnv).length === 0) {
|
|
211
|
+
output_manager_default.debug("Failed to parse env file.");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
return parsedEnv;
|
|
215
|
+
}
|
|
216
|
+
function findChanges(oldEnv, newEnv) {
|
|
217
|
+
const added = [];
|
|
218
|
+
const changed = [];
|
|
219
|
+
for (const key of Object.keys(newEnv)) {
|
|
220
|
+
if (oldEnv[key] === void 0) {
|
|
221
|
+
added.push(key);
|
|
222
|
+
} else if (oldEnv[key] !== newEnv[key]) {
|
|
223
|
+
changed.push(key);
|
|
224
|
+
}
|
|
225
|
+
delete oldEnv[key];
|
|
226
|
+
}
|
|
227
|
+
const removed = Object.keys(oldEnv);
|
|
228
|
+
return {
|
|
229
|
+
added,
|
|
230
|
+
changed,
|
|
231
|
+
removed
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function buildDeltaString(oldEnv, newEnv) {
|
|
235
|
+
const { added, changed, removed } = findChanges(oldEnv, newEnv);
|
|
236
|
+
let deltaString = "";
|
|
237
|
+
deltaString += import_chalk.default.green(addDeltaSection("+", changed, true));
|
|
238
|
+
deltaString += import_chalk.default.green(addDeltaSection("+", added));
|
|
239
|
+
deltaString += import_chalk.default.red(addDeltaSection("-", removed));
|
|
240
|
+
return deltaString ? import_chalk.default.gray(" Changes:\n") + deltaString + "\n" : deltaString;
|
|
241
|
+
}
|
|
242
|
+
function addDeltaSection(prefix, arr, changed = false) {
|
|
243
|
+
if (arr.length === 0)
|
|
244
|
+
return "";
|
|
245
|
+
return arr.sort().map((item) => ` ${prefix} ${item}${changed ? " (Updated)" : ""}`).join("\n") + "\n";
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/util/env/constants.ts
|
|
249
|
+
var VERCEL_OIDC_TOKEN = "VERCEL_OIDC_TOKEN";
|
|
250
|
+
var SENSITIVE_ENV_VALUE_PLACEHOLDER = "[SENSITIVE]";
|
|
251
|
+
|
|
252
|
+
// src/util/env/validate-env.ts
|
|
253
|
+
var import_frameworks = __toESM(require_frameworks(), 1);
|
|
254
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
255
|
+
import { join } from "path";
|
|
256
|
+
|
|
257
|
+
// src/util/env/secret-detection.ts
|
|
258
|
+
var SERVER_ONLY_KEY_PATTERNS = [
|
|
259
|
+
"access_token",
|
|
260
|
+
"refresh_token",
|
|
261
|
+
"client_secret",
|
|
262
|
+
"webhook_secret",
|
|
263
|
+
"api_key",
|
|
264
|
+
"private_key",
|
|
265
|
+
"service_account",
|
|
266
|
+
"service_role",
|
|
267
|
+
"database_url",
|
|
268
|
+
"database_uri",
|
|
269
|
+
"db_url",
|
|
270
|
+
"postgres_url",
|
|
271
|
+
"postgres_uri",
|
|
272
|
+
"mysql_url",
|
|
273
|
+
"mongo_url",
|
|
274
|
+
"mongo_uri",
|
|
275
|
+
"redis_url",
|
|
276
|
+
"redis_uri",
|
|
277
|
+
"amqp_url",
|
|
278
|
+
"kafka_url",
|
|
279
|
+
"elasticsearch_url",
|
|
280
|
+
"password",
|
|
281
|
+
"passwd",
|
|
282
|
+
"pwd",
|
|
283
|
+
"secret",
|
|
284
|
+
"private",
|
|
285
|
+
"key",
|
|
286
|
+
"apikey",
|
|
287
|
+
"auth",
|
|
288
|
+
"token",
|
|
289
|
+
"jwt",
|
|
290
|
+
"signature",
|
|
291
|
+
"cert",
|
|
292
|
+
"pem",
|
|
293
|
+
"salt",
|
|
294
|
+
"bearer",
|
|
295
|
+
"credential",
|
|
296
|
+
"credentials",
|
|
297
|
+
"creds"
|
|
298
|
+
];
|
|
299
|
+
var SAFE_KEY_HINT_TOKENS = ["public", "publishable", "anon"];
|
|
300
|
+
var WELL_KNOWN_SECRET_NAMES = /* @__PURE__ */ new Set([
|
|
301
|
+
"DATABASE_URL",
|
|
302
|
+
"DATABASE_URL_UNPOOLED",
|
|
303
|
+
"POSTGRES_URL",
|
|
304
|
+
"POSTGRES_URL_NON_POOLING",
|
|
305
|
+
"POSTGRES_URL_NO_SSL",
|
|
306
|
+
"POSTGRES_URL_UNPOOLED",
|
|
307
|
+
"POSTGRES_PRISMA_URL",
|
|
308
|
+
"MONGODB_URI",
|
|
309
|
+
"MONGODB_URL",
|
|
310
|
+
"MONGO_URI",
|
|
311
|
+
"MONGO_URL",
|
|
312
|
+
"MYSQL_URL",
|
|
313
|
+
"MYSQL_URI",
|
|
314
|
+
"REDIS_URL",
|
|
315
|
+
"REDIS_TLS_URL",
|
|
316
|
+
"KV_URL",
|
|
317
|
+
"KV_REST_API_URL",
|
|
318
|
+
"UPSTASH_REDIS_REST_URL",
|
|
319
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
320
|
+
"AWS_ACCESS_KEY_ID"
|
|
321
|
+
]);
|
|
322
|
+
var SECRET_SEGMENT_PATTERN = /(?:^|[_-])(SECRET|PASSWORD|PASSWD|PASSPHRASE|PWD|PGPASSWORD|TOKEN|CREDENTIAL|JWT|DSN|APIKEY|PRIVATEKEY|SALT|PEPPER|MNEMONIC|PEM|CIPHER)S?(?:[_-]|$)/i;
|
|
323
|
+
var EXPLICIT_SECRET_TOKEN_PATTERN = /(?:^|[_-])(SECRET|PASSWORD|PASSWD|PASSPHRASE|PWD|PGPASSWORD|TOKEN|CREDENTIAL|MNEMONIC|PRIVATEKEY|APIKEY)S?(?:[_-]|$)/i;
|
|
324
|
+
var SECRET_COMPOUND_PATTERNS = [
|
|
325
|
+
/(?:^|[_-])(?:API|PRIVATE|SIGNING|ENCRYPTION|SESSION|COOKIE|CSRF|HMAC|ACCESS|APP|WRITE)[_-]?(?:KEY|SECRET)S?(?:[_-]|$)/i,
|
|
326
|
+
/(?:^|[_-])(?:ACCESS|REFRESH|BEARER|AUTH)[_-]?TOKENS?(?:[_-]|$)/i,
|
|
327
|
+
/(?:^|[_-])(?:WEBHOOK|SIGNING)[_-]?SECRETS?(?:[_-]|$)/i,
|
|
328
|
+
/(?:^|[_-])SERVICE[_-]?(?:ROLE(?:[_-]?KEYS?)?|ACCOUNTS?)(?:[_-]|$)/i
|
|
329
|
+
];
|
|
330
|
+
var NON_CREDENTIAL_KEY_TOKENS = /* @__PURE__ */ new Set([
|
|
331
|
+
"PUBLIC",
|
|
332
|
+
"PUBLISHABLE",
|
|
333
|
+
"ANON",
|
|
334
|
+
"PRIMARY",
|
|
335
|
+
"PARTITION",
|
|
336
|
+
"FOREIGN",
|
|
337
|
+
"SORT",
|
|
338
|
+
"HASH",
|
|
339
|
+
"COMPOSITE",
|
|
340
|
+
"INDEX",
|
|
341
|
+
"UNIQUE",
|
|
342
|
+
"NATURAL",
|
|
343
|
+
"SURROGATE",
|
|
344
|
+
"CACHE",
|
|
345
|
+
"IDEMPOTENCY",
|
|
346
|
+
"LOOKUP",
|
|
347
|
+
"ROW",
|
|
348
|
+
"SHARD",
|
|
349
|
+
"CLUSTER",
|
|
350
|
+
"LICENSE",
|
|
351
|
+
"LICENCE",
|
|
352
|
+
"PRODUCT",
|
|
353
|
+
"TRANSLATION",
|
|
354
|
+
"TRANSLATIONS",
|
|
355
|
+
"I18N",
|
|
356
|
+
"LOCALE",
|
|
357
|
+
"RBAC",
|
|
358
|
+
"ACL",
|
|
359
|
+
"ROLE",
|
|
360
|
+
"ROLES",
|
|
361
|
+
"PERMISSION",
|
|
362
|
+
"PERMISSIONS",
|
|
363
|
+
"SCOPE",
|
|
364
|
+
"SCOPES",
|
|
365
|
+
"POLICY",
|
|
366
|
+
"POLICIES"
|
|
367
|
+
]);
|
|
368
|
+
var GENERIC_KEY_SUFFIX_PATTERN = /(?:^|[_-])([A-Z0-9]+)[_-]KEYS?$/i;
|
|
369
|
+
var GENERIC_KEY_PREFIX_PATTERN = /^KEYS?[_-]([A-Z0-9]+)(?:[_-]|$)/i;
|
|
370
|
+
var DB_URL_PATTERN = /(?:^|_)(?:DATABASE|POSTGRES|MONGO|MONGODB|MYSQL|REDIS|NEON|PLANETSCALE|TURSO|RDS)(?:_[A-Z0-9_]*)?_(?:URL|URI)(?:_[A-Z0-9_]+)?$/i;
|
|
371
|
+
var SECRET_VALUE_PATTERNS = [
|
|
372
|
+
/gh[opsru]_[A-Za-z0-9_]{20,}/,
|
|
373
|
+
/github_pat_[A-Za-z0-9_]{20,}/,
|
|
374
|
+
/glpat-[A-Za-z0-9_-]{20,}/,
|
|
375
|
+
/(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{20,}/,
|
|
376
|
+
/whsec_[A-Za-z0-9]{20,}/,
|
|
377
|
+
/xox[abprs]-[A-Za-z0-9-]{20,}/,
|
|
378
|
+
/xapp-[A-Za-z0-9-]{20,}/,
|
|
379
|
+
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
|
|
380
|
+
/\bAIza[A-Za-z0-9_-]{30,}/,
|
|
381
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/,
|
|
382
|
+
/sk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,}/,
|
|
383
|
+
/\bsk-[A-Za-z0-9]{32,}\b/,
|
|
384
|
+
/shp(?:at|ss|ca)_[a-fA-F0-9]{32}/,
|
|
385
|
+
/npm_[A-Za-z0-9]{30,}/,
|
|
386
|
+
/\bhf_[A-Za-z0-9_]{30,}/,
|
|
387
|
+
/nvapi-[A-Za-z0-9_-]{40,}/,
|
|
388
|
+
/SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/,
|
|
389
|
+
/key-[a-f0-9]{32}/,
|
|
390
|
+
/glsa_[A-Za-z0-9_]{32}_[a-f0-9]{8}/,
|
|
391
|
+
/pscale_pw_[A-Za-z0-9_-]{20,}/,
|
|
392
|
+
/\bre_[A-Za-z0-9_]{30,}/,
|
|
393
|
+
/dop_v1_[a-f0-9]{64}/,
|
|
394
|
+
/sntrys_[A-Za-z0-9_-]{30,}/,
|
|
395
|
+
/FlyV1 [A-Za-z0-9_-]{20,}/,
|
|
396
|
+
/AccountKey=[A-Za-z0-9+/]{40,}=*/,
|
|
397
|
+
/-----BEGIN [A-Z0-9 ]*PRIVATE KEY[A-Z0-9 ]*-----/,
|
|
398
|
+
/-----BEGIN PGP MESSAGE-----/,
|
|
399
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{8,}\b/,
|
|
400
|
+
/[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[A-Za-z0-9_.%-]*:[^@\s/]+(?<!\.\.)@/,
|
|
401
|
+
/\bBearer\s+[A-Za-z0-9_+=/.-]{20,}/i,
|
|
402
|
+
/(?:password|passwd|pwd|secret|token|api[_-]?key|access[_-]?token|refresh[_-]?token|private[_-]?key|auth)\s*[=:]\s*["']?[A-Za-z0-9_+=/.-]{12,}/i
|
|
403
|
+
];
|
|
404
|
+
function tokenize(key) {
|
|
405
|
+
return new Set(
|
|
406
|
+
key.split(/(?<=[a-z])(?=[A-Z])/).flatMap((part) => part.split(/[_\-.]+/)).map((token) => token.toLowerCase()).filter(Boolean)
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
function hasSafeKeyHint(key) {
|
|
410
|
+
const tokens = tokenize(key);
|
|
411
|
+
return SAFE_KEY_HINT_TOKENS.some((token) => tokens.has(token));
|
|
412
|
+
}
|
|
413
|
+
function hasGenericKeySuffix(key) {
|
|
414
|
+
const precedingToken = GENERIC_KEY_SUFFIX_PATTERN.exec(key)?.[1]?.toUpperCase();
|
|
415
|
+
return Boolean(
|
|
416
|
+
precedingToken && !NON_CREDENTIAL_KEY_TOKENS.has(precedingToken)
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
function hasGenericKeyPrefix(key) {
|
|
420
|
+
const followingToken = GENERIC_KEY_PREFIX_PATTERN.exec(key)?.[1]?.toUpperCase();
|
|
421
|
+
return Boolean(
|
|
422
|
+
followingToken && !NON_CREDENTIAL_KEY_TOKENS.has(followingToken)
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
function getMatchingServerOnlyKey(key) {
|
|
426
|
+
const normalized = key.replace(/(?<=[a-z])(?=[A-Z])/g, "_").toLowerCase().replace(/[-.]+/g, "_");
|
|
427
|
+
for (const pattern of SERVER_ONLY_KEY_PATTERNS) {
|
|
428
|
+
if (pattern.includes("_") && normalized.includes(pattern))
|
|
429
|
+
return pattern;
|
|
430
|
+
}
|
|
431
|
+
const tokens = tokenize(key);
|
|
432
|
+
return SERVER_ONLY_KEY_PATTERNS.find(
|
|
433
|
+
(pattern) => !pattern.includes("_") && tokens.has(pattern)
|
|
434
|
+
) ?? null;
|
|
435
|
+
}
|
|
436
|
+
function looksLikeSecret(key) {
|
|
437
|
+
if (!key || hasSafeKeyHint(key))
|
|
438
|
+
return false;
|
|
439
|
+
if (WELL_KNOWN_SECRET_NAMES.has(key.toUpperCase()))
|
|
440
|
+
return true;
|
|
441
|
+
if (SECRET_SEGMENT_PATTERN.test(key))
|
|
442
|
+
return true;
|
|
443
|
+
if (SECRET_COMPOUND_PATTERNS.some((pattern) => pattern.test(key)))
|
|
444
|
+
return true;
|
|
445
|
+
if (DB_URL_PATTERN.test(key))
|
|
446
|
+
return true;
|
|
447
|
+
return hasGenericKeySuffix(key) || hasGenericKeyPrefix(key);
|
|
448
|
+
}
|
|
449
|
+
function looksLikeSecretValue(value) {
|
|
450
|
+
const trimmed = value.trim();
|
|
451
|
+
return Boolean(
|
|
452
|
+
trimmed && SECRET_VALUE_PATTERNS.some((pattern) => pattern.test(trimmed))
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
function shouldConfirmRotationBeforeDelete(env) {
|
|
456
|
+
if (env.type === "system")
|
|
457
|
+
return false;
|
|
458
|
+
if (EXPLICIT_SECRET_TOKEN_PATTERN.test(env.key))
|
|
459
|
+
return true;
|
|
460
|
+
if (env.hasPublicPrefix || hasSafeKeyHint(env.key))
|
|
461
|
+
return false;
|
|
462
|
+
return looksLikeSecret(env.key);
|
|
463
|
+
}
|
|
464
|
+
function isFlagsSecretNeedingSplit(env) {
|
|
465
|
+
if (env.key !== "FLAGS_SECRET")
|
|
466
|
+
return false;
|
|
467
|
+
if (env.type !== "plain" && env.type !== "encrypted")
|
|
468
|
+
return false;
|
|
469
|
+
return env.targets.length + (env.customEnvironmentIds?.length ?? 0) > 1;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// src/util/env/validate-env.ts
|
|
473
|
+
function getEnvValueWarnings(value) {
|
|
474
|
+
const warnings = [];
|
|
475
|
+
const normalized = value.replace(/\n$/, "");
|
|
476
|
+
if (/^[ \t]+/.test(normalized)) {
|
|
477
|
+
warnings.push({
|
|
478
|
+
message: "starts with whitespace",
|
|
479
|
+
requiresConfirmation: false
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
if (/[ \t]+$/.test(normalized)) {
|
|
483
|
+
warnings.push({
|
|
484
|
+
message: "ends with whitespace",
|
|
485
|
+
requiresConfirmation: false
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
if (normalized.includes("\r") || normalized.includes("\n")) {
|
|
489
|
+
warnings.push({
|
|
490
|
+
message: "contains newlines",
|
|
491
|
+
requiresConfirmation: false
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
if (value.includes("\0")) {
|
|
495
|
+
warnings.push({
|
|
496
|
+
message: "contains null characters",
|
|
497
|
+
requiresConfirmation: false
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
if (value === "") {
|
|
501
|
+
warnings.push({
|
|
502
|
+
message: "is empty",
|
|
503
|
+
requiresConfirmation: true
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
if (value.length > 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
507
|
+
warnings.push({
|
|
508
|
+
message: "includes surrounding quotes (these will be stored literally)",
|
|
509
|
+
requiresConfirmation: false
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
return warnings;
|
|
513
|
+
}
|
|
514
|
+
function formatWarnings(warnings) {
|
|
515
|
+
if (warnings.length === 0)
|
|
516
|
+
return null;
|
|
517
|
+
const messages = warnings.map((w) => w.message);
|
|
518
|
+
const startsIdx = messages.indexOf("starts with whitespace");
|
|
519
|
+
const endsIdx = messages.indexOf("ends with whitespace");
|
|
520
|
+
if (startsIdx !== -1 && endsIdx !== -1) {
|
|
521
|
+
messages.splice(Math.max(startsIdx, endsIdx), 1);
|
|
522
|
+
messages[Math.min(startsIdx, endsIdx)] = "starts and ends with whitespace";
|
|
523
|
+
}
|
|
524
|
+
if (messages.length === 1) {
|
|
525
|
+
return `Value ${messages[0]}`;
|
|
526
|
+
}
|
|
527
|
+
if (messages.length === 2) {
|
|
528
|
+
return `Value ${messages[0]} and ${messages[1]}`;
|
|
529
|
+
}
|
|
530
|
+
const last = messages.pop();
|
|
531
|
+
return `Value ${messages.join(", ")}, and ${last}`;
|
|
532
|
+
}
|
|
533
|
+
var API_PUBLIC_PREFIXES = [
|
|
534
|
+
"NEXT_PUBLIC_",
|
|
535
|
+
"VUE_APP_",
|
|
536
|
+
"REACT_APP_",
|
|
537
|
+
"GATSBY_",
|
|
538
|
+
"GRIDSOME_",
|
|
539
|
+
"NUXT_PUBLIC_",
|
|
540
|
+
"STORYBOOK_",
|
|
541
|
+
"VITE_",
|
|
542
|
+
"PUBLIC_",
|
|
543
|
+
"EXPO_PUBLIC_",
|
|
544
|
+
"NG_APP_",
|
|
545
|
+
"REDWOOD_ENV_"
|
|
546
|
+
];
|
|
547
|
+
var PUBLIC_PREFIXES = [
|
|
548
|
+
.../* @__PURE__ */ new Set([
|
|
549
|
+
...API_PUBLIC_PREFIXES,
|
|
550
|
+
...import_frameworks.frameworkList.map((f) => f.envPrefix).filter((prefix) => !!prefix)
|
|
551
|
+
])
|
|
552
|
+
];
|
|
553
|
+
function hasOnlyWhitespaceWarnings(warnings) {
|
|
554
|
+
return warnings.length > 0 && warnings.every(
|
|
555
|
+
(w) => w.message === "starts with whitespace" || w.message === "ends with whitespace"
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
function trimValue(value) {
|
|
559
|
+
return value.replace(/\n$/, "").trim();
|
|
560
|
+
}
|
|
561
|
+
function normalizeStdinEnvValue(value) {
|
|
562
|
+
let valueWithoutTrailingNewline = value;
|
|
563
|
+
if (value.endsWith("\r\n")) {
|
|
564
|
+
valueWithoutTrailingNewline = value.slice(0, -2);
|
|
565
|
+
} else if (value.endsWith("\n")) {
|
|
566
|
+
valueWithoutTrailingNewline = value.slice(0, -1);
|
|
567
|
+
} else {
|
|
568
|
+
return {
|
|
569
|
+
value,
|
|
570
|
+
strippedTrailingNewline: false
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
if (valueWithoutTrailingNewline.includes("\n") || valueWithoutTrailingNewline.includes("\r")) {
|
|
574
|
+
return {
|
|
575
|
+
value,
|
|
576
|
+
strippedTrailingNewline: false
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
value: valueWithoutTrailingNewline,
|
|
581
|
+
strippedTrailingNewline: true
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function getPublicPrefix(key) {
|
|
585
|
+
const upperKey = key.toUpperCase();
|
|
586
|
+
return PUBLIC_PREFIXES.find((p) => upperKey.startsWith(p)) || null;
|
|
587
|
+
}
|
|
588
|
+
function getFrameworkPublicPrefix(frameworkSlug, key) {
|
|
589
|
+
const prefix = import_frameworks.frameworkList.find(
|
|
590
|
+
(framework) => framework.slug === frameworkSlug
|
|
591
|
+
)?.envPrefix;
|
|
592
|
+
return prefix && key.toUpperCase().startsWith(prefix.toUpperCase()) ? prefix : null;
|
|
593
|
+
}
|
|
594
|
+
function getApiPublicPrefix(key) {
|
|
595
|
+
const upperKey = key.toUpperCase();
|
|
596
|
+
return API_PUBLIC_PREFIXES.find((prefix) => upperKey.startsWith(prefix)) ?? null;
|
|
597
|
+
}
|
|
598
|
+
function parseSvelteKitPublicEnvVarPrefix(config) {
|
|
599
|
+
if (!config.includes("publicPrefix")) {
|
|
600
|
+
return { status: "ready", prefix: null };
|
|
601
|
+
}
|
|
602
|
+
const match = /publicPrefix:\s*(?:'(?<single>[^']*)'|"(?<double>[^"]*)"|`(?<template>[^`$]*)`)/.exec(
|
|
603
|
+
config
|
|
604
|
+
);
|
|
605
|
+
const prefix = match?.groups?.single ?? match?.groups?.double ?? match?.groups?.template;
|
|
606
|
+
return prefix === void 0 ? { status: "unavailable" } : { status: "ready", prefix };
|
|
607
|
+
}
|
|
608
|
+
async function getLocalSvelteKitPublicPrefixes(cwd, rootDirectory) {
|
|
609
|
+
const projectRoot = rootDirectory ? join(cwd, rootDirectory) : cwd;
|
|
610
|
+
let config;
|
|
611
|
+
try {
|
|
612
|
+
config = await readFile2(join(projectRoot, "svelte.config.js"), "utf8");
|
|
613
|
+
} catch {
|
|
614
|
+
return void 0;
|
|
615
|
+
}
|
|
616
|
+
const parsed = parseSvelteKitPublicEnvVarPrefix(config);
|
|
617
|
+
if (parsed.status === "unavailable")
|
|
618
|
+
return void 0;
|
|
619
|
+
return [parsed.prefix ?? "PUBLIC_", "VITE_"];
|
|
620
|
+
}
|
|
621
|
+
function removePublicPrefix(key) {
|
|
622
|
+
const prefix = getPublicPrefix(key);
|
|
623
|
+
if (!prefix)
|
|
624
|
+
return key;
|
|
625
|
+
return key.slice(prefix.length);
|
|
626
|
+
}
|
|
627
|
+
async function validateEnvValue(opts) {
|
|
628
|
+
let finalValue = opts.initialValue;
|
|
629
|
+
let alreadyConfirmed = false;
|
|
630
|
+
if (!opts.skipConfirm) {
|
|
631
|
+
let valueAccepted = false;
|
|
632
|
+
while (!valueAccepted) {
|
|
633
|
+
const valueWarnings = getEnvValueWarnings(finalValue);
|
|
634
|
+
const warningMessage = formatWarnings(valueWarnings);
|
|
635
|
+
if (!warningMessage) {
|
|
636
|
+
valueAccepted = true;
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
opts.showWarning(warningMessage);
|
|
640
|
+
const canTrim = hasOnlyWhitespaceWarnings(valueWarnings);
|
|
641
|
+
const choices = canTrim ? [
|
|
642
|
+
{ name: "Leave as is", value: "c" },
|
|
643
|
+
{ name: "Re-enter", value: "r" },
|
|
644
|
+
{ name: "Trim whitespace", value: "t" }
|
|
645
|
+
] : [
|
|
646
|
+
{ name: "Leave as is", value: "c" },
|
|
647
|
+
{ name: "Re-enter", value: "r" }
|
|
648
|
+
];
|
|
649
|
+
const action = await opts.selectAction(choices);
|
|
650
|
+
if (action === "c") {
|
|
651
|
+
valueAccepted = true;
|
|
652
|
+
if (valueWarnings.some((w) => w.requiresConfirmation)) {
|
|
653
|
+
alreadyConfirmed = true;
|
|
654
|
+
}
|
|
655
|
+
} else if (action === "t") {
|
|
656
|
+
finalValue = trimValue(finalValue);
|
|
657
|
+
opts.showLog("Trimmed whitespace");
|
|
658
|
+
} else {
|
|
659
|
+
finalValue = await opts.promptForValue();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
} else {
|
|
663
|
+
const valueWarnings = getEnvValueWarnings(finalValue);
|
|
664
|
+
const warningMessage = formatWarnings(valueWarnings);
|
|
665
|
+
if (warningMessage) {
|
|
666
|
+
opts.showWarning(warningMessage);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return { finalValue, alreadyConfirmed };
|
|
670
|
+
}
|
|
671
|
+
function getEnvKeyWarnings(key) {
|
|
672
|
+
const warnings = [];
|
|
673
|
+
const matchingPrefix = getPublicPrefix(key);
|
|
674
|
+
if (matchingPrefix) {
|
|
675
|
+
const nameWithoutPrefix = key.slice(matchingPrefix.length);
|
|
676
|
+
const sensitiveMatch = looksLikeSecret(nameWithoutPrefix) && getMatchingServerOnlyKey(nameWithoutPrefix);
|
|
677
|
+
if (sensitiveMatch) {
|
|
678
|
+
warnings.push({
|
|
679
|
+
message: `\`${matchingPrefix}\` exposes \`${key}\` to anyone visiting your site`,
|
|
680
|
+
requiresConfirmation: true
|
|
681
|
+
});
|
|
682
|
+
} else {
|
|
683
|
+
warnings.push({
|
|
684
|
+
message: `\`${matchingPrefix}\` exposes this value to anyone visiting your site`,
|
|
685
|
+
requiresConfirmation: false
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return warnings;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// src/util/env/env-var-config-secret-ui.ts
|
|
693
|
+
var ENV_VISIBILITY_DEPRECATION_MESSAGE = "`--visibility` is deprecated. Use `--type` instead.";
|
|
694
|
+
function invalidTypeOptionError(optionName, value) {
|
|
695
|
+
if (value === "config" || value === "secret") {
|
|
696
|
+
return void 0;
|
|
697
|
+
}
|
|
698
|
+
if (value === "sensitive") {
|
|
699
|
+
return `The \`${optionName}\` flag accepts \`config\` or \`secret\`. Use \`--type secret\` or the legacy \`--sensitive\` flag.`;
|
|
700
|
+
}
|
|
701
|
+
if (value === "plain" || value === "encrypted") {
|
|
702
|
+
return `The \`${optionName}\` flag accepts \`config\` or \`secret\`. Use \`--type config\` for readable values.`;
|
|
703
|
+
}
|
|
704
|
+
return `The \`${optionName}\` flag must be either \`config\` or \`secret\`.`;
|
|
705
|
+
}
|
|
706
|
+
function resolveEnvVarTypeOption(options) {
|
|
707
|
+
const usedDeprecatedVisibility = options.visibility !== void 0;
|
|
708
|
+
if (options.type !== void 0) {
|
|
709
|
+
const error = invalidTypeOptionError("--type", options.type);
|
|
710
|
+
if (error) {
|
|
711
|
+
return {
|
|
712
|
+
usedDeprecatedVisibility,
|
|
713
|
+
error,
|
|
714
|
+
errorReason: "invalid_type"
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (options.visibility !== void 0) {
|
|
719
|
+
const error = invalidTypeOptionError("--visibility", options.visibility);
|
|
720
|
+
if (error) {
|
|
721
|
+
return {
|
|
722
|
+
usedDeprecatedVisibility,
|
|
723
|
+
error,
|
|
724
|
+
errorReason: "invalid_visibility"
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
if (options.type !== void 0 && options.visibility !== void 0 && options.type !== options.visibility) {
|
|
729
|
+
return {
|
|
730
|
+
usedDeprecatedVisibility,
|
|
731
|
+
error: `\`--type ${options.type}\` conflicts with \`--visibility ${options.visibility}\`. \`--visibility\` is a deprecated alias of \`--type\`; remove it.`,
|
|
732
|
+
errorReason: "conflicting_type_visibility"
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
if (options.type !== void 0) {
|
|
736
|
+
return {
|
|
737
|
+
explicitVisibility: options.type,
|
|
738
|
+
source: "type",
|
|
739
|
+
usedDeprecatedVisibility
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
if (options.visibility !== void 0) {
|
|
743
|
+
return {
|
|
744
|
+
explicitVisibility: options.visibility,
|
|
745
|
+
source: "visibility",
|
|
746
|
+
usedDeprecatedVisibility
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
return { usedDeprecatedVisibility };
|
|
750
|
+
}
|
|
751
|
+
function isSecretEnvVar(env) {
|
|
752
|
+
return env.type === "sensitive" || env.visibility === "secret";
|
|
753
|
+
}
|
|
754
|
+
function formatVisibilityLabel(visibility, type) {
|
|
755
|
+
const resolved = visibility ?? visibilityFromEnvType(type);
|
|
756
|
+
if (resolved === "config") {
|
|
757
|
+
return "Config";
|
|
758
|
+
}
|
|
759
|
+
if (resolved === "secret") {
|
|
760
|
+
return "Secret";
|
|
761
|
+
}
|
|
762
|
+
return void 0;
|
|
763
|
+
}
|
|
764
|
+
function visibilityFromEnvType(type) {
|
|
765
|
+
if (type === "sensitive") {
|
|
766
|
+
return "secret";
|
|
767
|
+
}
|
|
768
|
+
if (type === "plain" || type === "encrypted") {
|
|
769
|
+
return "config";
|
|
770
|
+
}
|
|
771
|
+
return void 0;
|
|
772
|
+
}
|
|
773
|
+
function hasNonDevelopmentTarget(envTargets) {
|
|
774
|
+
return envTargets.some((target) => target !== "development");
|
|
775
|
+
}
|
|
776
|
+
function getPublicPrefixSecretVisibilityError(key, options) {
|
|
777
|
+
const publicPrefix = getApiPublicPrefix(key);
|
|
778
|
+
if (!publicPrefix) {
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
const wouldBeSecret = options.visibility === "secret" || options.type === "sensitive";
|
|
782
|
+
if (!wouldBeSecret) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
const privateKey = key.slice(publicPrefix.length);
|
|
786
|
+
if (options.context === "update") {
|
|
787
|
+
return `\`${publicPrefix}\` exposes this value to anyone visiting your site, so \`${key}\` cannot be a Secret. To keep it private, add \`${privateKey}\` as a Secret, then remove \`${key}\`. If the value is safe to expose, keep it as Config.`;
|
|
788
|
+
}
|
|
789
|
+
return `\`${publicPrefix}\` exposes this value to anyone visiting your site, so \`${key}\` cannot be a Secret. To keep it private, rename the variable to \`${privateKey}\` and keep the Secret type. If the value is safe to expose, use \`--type config\`.`;
|
|
790
|
+
}
|
|
791
|
+
function shouldOmitInferredVisibility(key, envTargets, teamSensitivePolicyOn) {
|
|
792
|
+
if (!getApiPublicPrefix(key)) {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
if (!hasNonDevelopmentTarget(envTargets)) {
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
return teamSensitivePolicyOn;
|
|
799
|
+
}
|
|
800
|
+
function resolveEnvVarVisibility(options) {
|
|
801
|
+
if (options.explicitVisibility !== void 0) {
|
|
802
|
+
if (options.explicitVisibility !== "config" && options.explicitVisibility !== "secret") {
|
|
803
|
+
const optionName = options.explicitOptionSource === "visibility" ? "--visibility" : "--type";
|
|
804
|
+
return {
|
|
805
|
+
error: options.explicitVisibility === "sensitive" ? `The \`${optionName}\` flag accepts \`config\` or \`secret\`. Use \`--type secret\` or the legacy \`--sensitive\` flag.` : options.explicitVisibility === "plain" || options.explicitVisibility === "encrypted" ? `The \`${optionName}\` flag accepts \`config\` or \`secret\`. Use \`--type config\` for readable values.` : `The \`${optionName}\` flag must be either \`config\` or \`secret\`.`
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
const publicPrefixError2 = getPublicPrefixSecretVisibilityError(
|
|
809
|
+
options.key,
|
|
810
|
+
{
|
|
811
|
+
visibility: options.explicitVisibility,
|
|
812
|
+
type: options.type,
|
|
813
|
+
context: options.context
|
|
814
|
+
}
|
|
815
|
+
);
|
|
816
|
+
if (publicPrefixError2) {
|
|
817
|
+
return { error: publicPrefixError2 };
|
|
818
|
+
}
|
|
819
|
+
return { visibility: options.explicitVisibility };
|
|
820
|
+
}
|
|
821
|
+
const inferred = visibilityFromEnvType(options.type);
|
|
822
|
+
if (inferred === void 0) {
|
|
823
|
+
return {};
|
|
824
|
+
}
|
|
825
|
+
if (shouldOmitInferredVisibility(
|
|
826
|
+
options.key,
|
|
827
|
+
options.envTargets,
|
|
828
|
+
options.teamSensitivePolicyOn
|
|
829
|
+
)) {
|
|
830
|
+
return {};
|
|
831
|
+
}
|
|
832
|
+
const publicPrefixError = getPublicPrefixSecretVisibilityError(options.key, {
|
|
833
|
+
visibility: inferred,
|
|
834
|
+
type: options.type,
|
|
835
|
+
context: options.context
|
|
836
|
+
});
|
|
837
|
+
if (publicPrefixError) {
|
|
838
|
+
return { error: publicPrefixError };
|
|
839
|
+
}
|
|
840
|
+
return { visibility: inferred };
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/util/env/secret-read-guidance.ts
|
|
844
|
+
function getUnavailableSecretValuesMessage(environment, count) {
|
|
845
|
+
const values = count === 1 ? "value" : "values";
|
|
846
|
+
if (environment === "development") {
|
|
847
|
+
return `${count} Development Secret ${values} ${count === 1 ? "was" : "were"} not returned by Vercel.`;
|
|
848
|
+
}
|
|
849
|
+
return `${count} Secret ${values} cannot be pulled from the \`${environment}\` Environment.`;
|
|
850
|
+
}
|
|
851
|
+
function getLocalSecretFallbackMessage(count) {
|
|
852
|
+
return ` Define ${count === 1 ? "it" : "them"} in a local .env file.`;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// src/util/env/update-oidc-token-contents.ts
|
|
856
|
+
var CONTENTS_HEADER = "# Created by Vercel CLI";
|
|
857
|
+
function updateOidcTokenContents(existing, token) {
|
|
858
|
+
const assignment = `${VERCEL_OIDC_TOKEN}="${escapeValue(token)}"`;
|
|
859
|
+
const oidcAssignment = new RegExp(
|
|
860
|
+
`^(\\uFEFF?)[\\t ]*(?:export[\\t ]+)?${VERCEL_OIDC_TOKEN}[\\t ]*=[^\\r\\n]*(\\r\\n|\\n|\\r|$)`,
|
|
861
|
+
"gm"
|
|
862
|
+
);
|
|
863
|
+
let tokenWritten = false;
|
|
864
|
+
const withoutDuplicates = existing.replace(
|
|
865
|
+
oidcAssignment,
|
|
866
|
+
(_match, byteOrderMark, lineEnding2) => {
|
|
867
|
+
if (token !== void 0 && !tokenWritten) {
|
|
868
|
+
tokenWritten = true;
|
|
869
|
+
return `${byteOrderMark}${assignment}${lineEnding2}`;
|
|
870
|
+
}
|
|
871
|
+
return byteOrderMark;
|
|
872
|
+
}
|
|
873
|
+
);
|
|
874
|
+
if (token === void 0 || tokenWritten) {
|
|
875
|
+
return withoutDuplicates;
|
|
876
|
+
}
|
|
877
|
+
const lineEnding = withoutDuplicates.match(/\r\n|\n|\r/)?.[0] ?? "\n";
|
|
878
|
+
const hasTrailingLineEnding = /(?:\r\n|\n|\r)$/.test(withoutDuplicates);
|
|
879
|
+
const hasTrailingBlankLine = /(?:\r\n|\n|\r){2}$/.test(withoutDuplicates);
|
|
880
|
+
const separator = withoutDuplicates.length === 0 || hasTrailingBlankLine ? "" : hasTrailingLineEnding ? lineEnding : `${lineEnding}${lineEnding}`;
|
|
881
|
+
return `${withoutDuplicates}${separator}${CONTENTS_HEADER}${lineEnding}${assignment}${lineEnding}`;
|
|
882
|
+
}
|
|
883
|
+
function escapeValue(value) {
|
|
884
|
+
return value ? value.replace(/\n/g, "\\n").replace(/\r/g, "\\r") : "";
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// src/commands/env/pull.ts
|
|
888
|
+
var import_error_utils = __toESM(require_dist(), 1);
|
|
889
|
+
var import_json_parse_better_errors = __toESM(require_json_parse_better_errors(), 1);
|
|
890
|
+
|
|
891
|
+
// src/util/telemetry/commands/env/pull.ts
|
|
892
|
+
var EnvPullTelemetryClient = class extends TelemetryClient {
|
|
893
|
+
trackCliArgumentFilename(filename) {
|
|
894
|
+
if (filename) {
|
|
895
|
+
this.trackCliArgument({
|
|
896
|
+
arg: "filename",
|
|
897
|
+
value: this.redactedValue
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
trackCliOptionEnvironment(environment) {
|
|
902
|
+
if (environment) {
|
|
903
|
+
this.trackCliOption({
|
|
904
|
+
option: "environment",
|
|
905
|
+
value: STANDARD_ENVIRONMENTS.includes(
|
|
906
|
+
environment
|
|
907
|
+
) ? environment : this.redactedValue
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
trackCliOptionGitBranch(gitBranch) {
|
|
912
|
+
if (gitBranch) {
|
|
913
|
+
this.trackCliOption({
|
|
914
|
+
option: "git-branch",
|
|
915
|
+
value: this.redactedValue
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
trackCliFlagYes(yes) {
|
|
920
|
+
if (yes) {
|
|
921
|
+
this.trackCliFlag("yes");
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
trackCliOptionId(id) {
|
|
925
|
+
if (id) {
|
|
926
|
+
this.trackCliOption({
|
|
927
|
+
option: "id",
|
|
928
|
+
value: this.redactedValue
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
// src/commands/env/pull.ts
|
|
935
|
+
var CONTENTS_PREFIX = "# Created by Vercel CLI\n";
|
|
936
|
+
function printEnvPullWarning(message) {
|
|
937
|
+
output_manager_default.print(`${import_chalk2.default.yellow("!")} ${message}
|
|
938
|
+
`);
|
|
939
|
+
}
|
|
940
|
+
function readHeadSync(path, length) {
|
|
941
|
+
const buffer = Buffer.alloc(length);
|
|
942
|
+
const fd = openSync(path, "r");
|
|
943
|
+
try {
|
|
944
|
+
readSync(
|
|
945
|
+
fd,
|
|
946
|
+
buffer,
|
|
947
|
+
0,
|
|
948
|
+
buffer.length,
|
|
949
|
+
null
|
|
950
|
+
);
|
|
951
|
+
} finally {
|
|
952
|
+
closeSync(fd);
|
|
953
|
+
}
|
|
954
|
+
return buffer.toString();
|
|
955
|
+
}
|
|
956
|
+
function tryReadHeadSync(path, length) {
|
|
957
|
+
try {
|
|
958
|
+
return readHeadSync(path, length);
|
|
959
|
+
} catch (err) {
|
|
960
|
+
if (!(0, import_error_utils.isErrnoException)(err) || err.code !== "ENOENT") {
|
|
961
|
+
throw err;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
var VARIABLES_TO_IGNORE = [
|
|
966
|
+
"VERCEL_ANALYTICS_ID",
|
|
967
|
+
"VERCEL_SPEED_INSIGHTS_ID",
|
|
968
|
+
"VERCEL_WEB_ANALYTICS_ID"
|
|
969
|
+
];
|
|
970
|
+
var SENSITIVE_PLACEHOLDER = SENSITIVE_ENV_VALUE_PLACEHOLDER;
|
|
971
|
+
async function getRedactedSensitiveKeys(client, projectId, source, target, gitBranch, records) {
|
|
972
|
+
const emptyKeys = Object.keys(records).filter((key) => !records[key]);
|
|
973
|
+
if (!projectId || emptyKeys.length === 0) {
|
|
974
|
+
return /* @__PURE__ */ new Set();
|
|
975
|
+
}
|
|
976
|
+
try {
|
|
977
|
+
const { envs } = await getEnvRecords(client, projectId, source, {
|
|
978
|
+
target,
|
|
979
|
+
gitBranch
|
|
980
|
+
});
|
|
981
|
+
const sensitiveKeys = new Set(
|
|
982
|
+
envs.filter(isSecretEnvVar).map((env) => env.key)
|
|
983
|
+
);
|
|
984
|
+
return new Set(emptyKeys.filter((key) => sensitiveKeys.has(key)));
|
|
985
|
+
} catch {
|
|
986
|
+
return /* @__PURE__ */ new Set();
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
async function pull(client, argv, source = "vercel-cli:env:pull", options = {}) {
|
|
990
|
+
const telemetryClient = new EnvPullTelemetryClient({
|
|
991
|
+
opts: {
|
|
992
|
+
store: client.telemetryEventStore
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
let parsedArgs;
|
|
996
|
+
const flagsSpecification = getFlagsSpecification(pullSubcommand.options);
|
|
997
|
+
try {
|
|
998
|
+
parsedArgs = parseArguments(argv, flagsSpecification);
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
printError(err);
|
|
1001
|
+
return 1;
|
|
1002
|
+
}
|
|
1003
|
+
const { args, flags: opts } = parsedArgs;
|
|
1004
|
+
if (args.length > 1) {
|
|
1005
|
+
output_manager_default.error(
|
|
1006
|
+
`Invalid number of arguments. Usage: ${getCommandName(`env pull <file>`)}`
|
|
1007
|
+
);
|
|
1008
|
+
return 1;
|
|
1009
|
+
}
|
|
1010
|
+
const [rawFilename] = args;
|
|
1011
|
+
const filename = rawFilename || ".env.local";
|
|
1012
|
+
const skipConfirmation = opts["--yes"];
|
|
1013
|
+
const gitBranch = opts["--git-branch"];
|
|
1014
|
+
telemetryClient.trackCliArgumentFilename(args[0]);
|
|
1015
|
+
telemetryClient.trackCliFlagYes(skipConfirmation);
|
|
1016
|
+
telemetryClient.trackCliOptionGitBranch(gitBranch);
|
|
1017
|
+
telemetryClient.trackCliOptionEnvironment(opts["--environment"]);
|
|
1018
|
+
telemetryClient.trackCliOptionId(opts["--id"]);
|
|
1019
|
+
telemetryClient.trackCliOptionProject(opts["--project"]);
|
|
1020
|
+
let link = await resolveProjectContext({
|
|
1021
|
+
client,
|
|
1022
|
+
projectNameOrId: opts["--project"]
|
|
1023
|
+
});
|
|
1024
|
+
if (link.status === "error") {
|
|
1025
|
+
return link.exitCode;
|
|
1026
|
+
} else if (link.status === "not_linked") {
|
|
1027
|
+
if (client.nonInteractive) {
|
|
1028
|
+
const preserved = getPreservedArgsForEnvPull(client.argv);
|
|
1029
|
+
const linkArgv = [
|
|
1030
|
+
...client.argv.slice(0, 2),
|
|
1031
|
+
"link",
|
|
1032
|
+
"--scope",
|
|
1033
|
+
"<scope>",
|
|
1034
|
+
...preserved
|
|
1035
|
+
];
|
|
1036
|
+
outputAgentError(
|
|
1037
|
+
client,
|
|
1038
|
+
{
|
|
1039
|
+
status: "error",
|
|
1040
|
+
reason: "not_linked",
|
|
1041
|
+
message: `Your codebase isn't linked to a project on Vercel. Run \`${getCommandNamePlain(
|
|
1042
|
+
"link"
|
|
1043
|
+
)}\` to begin. Use \`--yes\` for non-interactive; use \`--scope\` or \`--project\` to specify team or project.`,
|
|
1044
|
+
next: [
|
|
1045
|
+
{ command: buildCommandWithYes(linkArgv) },
|
|
1046
|
+
{ command: buildCommandWithYes(client.argv) }
|
|
1047
|
+
]
|
|
1048
|
+
},
|
|
1049
|
+
1
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
if (!client.nonInteractive && client.stdin.isTTY && !skipConfirmation) {
|
|
1053
|
+
const ensuredLink = await ensureLink("env pull", client, client.cwd, {
|
|
1054
|
+
link,
|
|
1055
|
+
// The env vars are pulled below, so don't offer to pull them twice.
|
|
1056
|
+
pullEnv: false
|
|
1057
|
+
});
|
|
1058
|
+
if (typeof ensuredLink === "number") {
|
|
1059
|
+
return ensuredLink;
|
|
1060
|
+
}
|
|
1061
|
+
link = ensuredLink;
|
|
1062
|
+
} else {
|
|
1063
|
+
output_manager_default.error(
|
|
1064
|
+
`Your codebase isn\u2019t linked to a project on Vercel. Run ${getCommandName(
|
|
1065
|
+
"link"
|
|
1066
|
+
)} to begin.`
|
|
1067
|
+
);
|
|
1068
|
+
return 1;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
client.config.currentTeam = link.org.type === "team" ? link.org.id : void 0;
|
|
1072
|
+
const deploymentId = opts["--id"];
|
|
1073
|
+
if (deploymentId && opts["--project"]) {
|
|
1074
|
+
const deployment = await getDeployment(client, link.org.slug, deploymentId);
|
|
1075
|
+
if (deployment.projectId && deployment.projectId !== link.project.id) {
|
|
1076
|
+
output_manager_default.error(
|
|
1077
|
+
`Deployment ${import_chalk2.default.bold(deploymentId)} does not belong to project ${import_chalk2.default.bold(link.project.name)}.`
|
|
1078
|
+
);
|
|
1079
|
+
return 1;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
const environment = parseTarget({
|
|
1083
|
+
flagName: "environment",
|
|
1084
|
+
flags: opts
|
|
1085
|
+
}) || "development";
|
|
1086
|
+
await envPullCommandLogic(
|
|
1087
|
+
client,
|
|
1088
|
+
filename,
|
|
1089
|
+
!!skipConfirmation,
|
|
1090
|
+
environment,
|
|
1091
|
+
link,
|
|
1092
|
+
gitBranch,
|
|
1093
|
+
client.cwd,
|
|
1094
|
+
source,
|
|
1095
|
+
deploymentId,
|
|
1096
|
+
options
|
|
1097
|
+
);
|
|
1098
|
+
return 0;
|
|
1099
|
+
}
|
|
1100
|
+
async function envPullCommandLogic(client, filename, skipConfirmation, environment, link, gitBranch, cwd, source, deploymentId, { oidcTokenOnly = false } = {}) {
|
|
1101
|
+
const fullPath = resolve(cwd, filename);
|
|
1102
|
+
const head = tryReadHeadSync(fullPath, Buffer.byteLength(CONTENTS_PREFIX));
|
|
1103
|
+
const exists = typeof head !== "undefined";
|
|
1104
|
+
if (head === CONTENTS_PREFIX && !oidcTokenOnly) {
|
|
1105
|
+
output_manager_default.log(`Overwriting existing ${import_chalk2.default.bold(filename)} file`);
|
|
1106
|
+
} else if (exists && !skipConfirmation && !oidcTokenOnly) {
|
|
1107
|
+
if (client.nonInteractive) {
|
|
1108
|
+
const preserved = getPreservedArgsForEnvPull(client.argv).filter(
|
|
1109
|
+
(arg) => arg !== "--yes" && arg !== "-y"
|
|
1110
|
+
);
|
|
1111
|
+
const suffix = preserved.length > 0 ? ` ${preserved.join(" ")}` : "";
|
|
1112
|
+
outputActionRequired(client, {
|
|
1113
|
+
status: "action_required",
|
|
1114
|
+
reason: "env_file_exists",
|
|
1115
|
+
message: `File ${param(filename)} already exists and was not created by Vercel CLI. Use --yes to overwrite or specify a different filename.`,
|
|
1116
|
+
next: [
|
|
1117
|
+
{
|
|
1118
|
+
command: getCommandNamePlain(`env pull ${filename} --yes${suffix}`),
|
|
1119
|
+
when: "Overwrite this file"
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
command: getCommandNamePlain(`env pull <filename>${suffix}`),
|
|
1123
|
+
when: "Use a different filename"
|
|
1124
|
+
}
|
|
1125
|
+
]
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
if (!await client.input.confirm(
|
|
1129
|
+
`Found existing file ${param(filename)}. Do you want to overwrite?`,
|
|
1130
|
+
false
|
|
1131
|
+
)) {
|
|
1132
|
+
output_manager_default.log("Canceled");
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
const projectSlugLink = formatProject(link.org.slug, link.project.name);
|
|
1137
|
+
const downloadMessage = oidcTokenOnly ? `Downloading a fresh \`${import_chalk2.default.cyan(
|
|
1138
|
+
VERCEL_OIDC_TOKEN
|
|
1139
|
+
)}\` for ${projectSlugLink}` : gitBranch ? `Downloading \`${import_chalk2.default.cyan(
|
|
1140
|
+
environment
|
|
1141
|
+
)}\` environment variables for ${projectSlugLink} and any overrides for branch ${import_chalk2.default.cyan(
|
|
1142
|
+
gitBranch
|
|
1143
|
+
)}` : `Downloading \`${import_chalk2.default.cyan(
|
|
1144
|
+
environment
|
|
1145
|
+
)}\` environment variables for ${projectSlugLink}`;
|
|
1146
|
+
output_manager_default.log(downloadMessage);
|
|
1147
|
+
output_manager_default.spinner("Downloading");
|
|
1148
|
+
const pullId = deploymentId || link.project.id;
|
|
1149
|
+
const pullResult = await pullEnvRecords(client, pullId, source, {
|
|
1150
|
+
target: environment || "development",
|
|
1151
|
+
gitBranch
|
|
1152
|
+
});
|
|
1153
|
+
const records = deploymentId ? pullResult.buildEnv : pullResult.env;
|
|
1154
|
+
let deltaString = "";
|
|
1155
|
+
let oldEnv;
|
|
1156
|
+
if (exists && !oidcTokenOnly) {
|
|
1157
|
+
oldEnv = await createEnvObject(fullPath);
|
|
1158
|
+
}
|
|
1159
|
+
let contents;
|
|
1160
|
+
let fileChanged = true;
|
|
1161
|
+
const keptLocalKeys = [];
|
|
1162
|
+
const preservedLocalSecretKeys = [];
|
|
1163
|
+
let redactedSecretCount = 0;
|
|
1164
|
+
let placeholderSecretCount = 0;
|
|
1165
|
+
if (oidcTokenOnly) {
|
|
1166
|
+
const existingContents = exists ? await (0, import_fs_extra2.readFile)(fullPath, "utf8") : "";
|
|
1167
|
+
contents = updateOidcTokenContents(
|
|
1168
|
+
existingContents,
|
|
1169
|
+
records[VERCEL_OIDC_TOKEN] || void 0
|
|
1170
|
+
);
|
|
1171
|
+
fileChanged = contents !== existingContents;
|
|
1172
|
+
} else {
|
|
1173
|
+
const sensitiveKeys = await getRedactedSensitiveKeys(
|
|
1174
|
+
client,
|
|
1175
|
+
deploymentId ? void 0 : link.project.id,
|
|
1176
|
+
source,
|
|
1177
|
+
environment,
|
|
1178
|
+
gitBranch,
|
|
1179
|
+
records
|
|
1180
|
+
);
|
|
1181
|
+
redactedSecretCount = sensitiveKeys.size;
|
|
1182
|
+
const mergedRecords = { ...records };
|
|
1183
|
+
for (const key of sensitiveKeys) {
|
|
1184
|
+
const localValue = oldEnv?.[key];
|
|
1185
|
+
if (localValue && localValue !== SENSITIVE_PLACEHOLDER) {
|
|
1186
|
+
mergedRecords[key] = localValue;
|
|
1187
|
+
preservedLocalSecretKeys.push(key);
|
|
1188
|
+
} else {
|
|
1189
|
+
mergedRecords[key] = SENSITIVE_PLACEHOLDER;
|
|
1190
|
+
placeholderSecretCount++;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
if (oldEnv) {
|
|
1194
|
+
for (const [key, value] of Object.entries(oldEnv)) {
|
|
1195
|
+
if (!(key in mergedRecords) && key !== VERCEL_OIDC_TOKEN && !VARIABLES_TO_IGNORE.includes(key)) {
|
|
1196
|
+
mergedRecords[key] = value;
|
|
1197
|
+
keptLocalKeys.push(key);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
contents = CONTENTS_PREFIX + Object.keys(mergedRecords).sort().filter((key) => !VARIABLES_TO_IGNORE.includes(key)).map((key) => `${key}="${escapeValue2(mergedRecords[key])}"`).join("\n") + "\n";
|
|
1202
|
+
if (oldEnv) {
|
|
1203
|
+
const newEnv = (0, import_json_parse_better_errors.default)(
|
|
1204
|
+
JSON.stringify(mergedRecords).replace(/\\"/g, "")
|
|
1205
|
+
);
|
|
1206
|
+
deltaString = buildDeltaString(oldEnv, newEnv);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
if (fileChanged) {
|
|
1210
|
+
await (0, import_fs_extra2.outputFile)(fullPath, contents, "utf8");
|
|
1211
|
+
}
|
|
1212
|
+
if (deltaString) {
|
|
1213
|
+
output_manager_default.print("\n" + deltaString);
|
|
1214
|
+
} else if (oldEnv && exists) {
|
|
1215
|
+
output_manager_default.log("No changes found.");
|
|
1216
|
+
}
|
|
1217
|
+
if (keptLocalKeys.length > 0) {
|
|
1218
|
+
output_manager_default.log(
|
|
1219
|
+
`Kept ${keptLocalKeys.sort().map((key) => import_chalk2.default.bold(key)).join(", ")} (defined locally, not found in the ${import_chalk2.default.cyan(
|
|
1220
|
+
environment
|
|
1221
|
+
)} Environment)`
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
if (redactedSecretCount > 0) {
|
|
1225
|
+
const preservedMessage = preservedLocalSecretKeys.length > 0 ? ` Kept ${preservedLocalSecretKeys.length} existing local ${preservedLocalSecretKeys.length === 1 ? "value" : "values"}.` : "";
|
|
1226
|
+
const placeholderMessage = placeholderSecretCount > 0 ? ` Wrote "${SENSITIVE_PLACEHOLDER}" ${placeholderSecretCount === 1 ? "as a placeholder" : "as placeholders"} for the remaining ${placeholderSecretCount === 1 ? "value" : "values"}; replace ${placeholderSecretCount === 1 ? "it" : "them"} with local-only values.` : "";
|
|
1227
|
+
printEnvPullWarning(
|
|
1228
|
+
`${getUnavailableSecretValuesMessage(
|
|
1229
|
+
environment,
|
|
1230
|
+
redactedSecretCount
|
|
1231
|
+
)}${preservedMessage}${placeholderMessage}`
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
let isGitIgnoreUpdated = false;
|
|
1235
|
+
const fileExistsAfterPull = exists || contents.length > 0;
|
|
1236
|
+
if (filename === ".env.local" && fileExistsAfterPull) {
|
|
1237
|
+
const rootPath = link.repoRoot ?? cwd;
|
|
1238
|
+
isGitIgnoreUpdated = await addToGitIgnore(rootPath, ".env*");
|
|
1239
|
+
}
|
|
1240
|
+
if (!fileChanged && !isGitIgnoreUpdated) {
|
|
1241
|
+
output_manager_default.stopSpinner();
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
output_manager_default.print("\n");
|
|
1245
|
+
if (!fileChanged) {
|
|
1246
|
+
printAlignedLabel("Updated", `.gitignore for ${filename}`, { gutter: "\u2713" });
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
printAlignedLabel(
|
|
1250
|
+
exists ? "Updated" : "Created",
|
|
1251
|
+
`${filename} file${isGitIgnoreUpdated ? " and added it to .gitignore" : ""}`,
|
|
1252
|
+
{ gutter: "\u2713" }
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
function escapeValue2(value) {
|
|
1256
|
+
return value ? value.replace(new RegExp("\n", "g"), "\\n").replace(new RegExp("\r", "g"), "\\r") : "";
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
export {
|
|
1260
|
+
getEnvRecords,
|
|
1261
|
+
pullEnvRecords,
|
|
1262
|
+
createEnvObject,
|
|
1263
|
+
VERCEL_OIDC_TOKEN,
|
|
1264
|
+
SENSITIVE_ENV_VALUE_PLACEHOLDER,
|
|
1265
|
+
looksLikeSecret,
|
|
1266
|
+
looksLikeSecretValue,
|
|
1267
|
+
shouldConfirmRotationBeforeDelete,
|
|
1268
|
+
isFlagsSecretNeedingSplit,
|
|
1269
|
+
normalizeStdinEnvValue,
|
|
1270
|
+
getPublicPrefix,
|
|
1271
|
+
getFrameworkPublicPrefix,
|
|
1272
|
+
getApiPublicPrefix,
|
|
1273
|
+
getLocalSvelteKitPublicPrefixes,
|
|
1274
|
+
removePublicPrefix,
|
|
1275
|
+
validateEnvValue,
|
|
1276
|
+
getEnvKeyWarnings,
|
|
1277
|
+
ENV_VISIBILITY_DEPRECATION_MESSAGE,
|
|
1278
|
+
resolveEnvVarTypeOption,
|
|
1279
|
+
isSecretEnvVar,
|
|
1280
|
+
formatVisibilityLabel,
|
|
1281
|
+
getPublicPrefixSecretVisibilityError,
|
|
1282
|
+
resolveEnvVarVisibility,
|
|
1283
|
+
getUnavailableSecretValuesMessage,
|
|
1284
|
+
getLocalSecretFallbackMessage,
|
|
1285
|
+
SENSITIVE_PLACEHOLDER,
|
|
1286
|
+
pull,
|
|
1287
|
+
envPullCommandLogic
|
|
1288
|
+
};
|