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.
Files changed (154) hide show
  1. package/dist/chunks/{add-BKSHWTPX.js → add-KSJQYR5C.js} +23 -18
  2. package/dist/chunks/{add-RBW7QITR.js → add-PERLOALD.js} +37 -23
  3. package/dist/chunks/{add-HPLJZFM2.js → add-WU2QYHYL.js} +23 -18
  4. package/dist/chunks/{build-V4ZLAJWB.js → build-F3J6FLPD.js} +23 -18
  5. package/dist/chunks/{chunk-NGGLYKNU.js → chunk-26CU4Q3C.js} +3 -115
  6. package/dist/chunks/{chunk-QFAS4OVW.js → chunk-2JIX6UMI.js} +3 -84
  7. package/dist/chunks/chunk-2TSBB22D.js +14059 -0
  8. package/dist/chunks/chunk-332LMJLZ.js +16014 -0
  9. package/dist/chunks/{chunk-AYLY3ZVL.js → chunk-3VM7HWF6.js} +2 -2
  10. package/dist/chunks/chunk-4IALDGB7.js +22 -0
  11. package/dist/chunks/chunk-4IVSM24H.js +522 -0
  12. package/dist/chunks/{chunk-5XECIWME.js → chunk-5NF5HOBJ.js} +5 -3
  13. package/dist/chunks/chunk-6E6KPBXY.js +43 -0
  14. package/dist/chunks/chunk-7KROIXQM.js +59 -0
  15. package/dist/chunks/{chunk-ASBP32T6.js → chunk-7MRDIPJY.js} +1 -1
  16. package/dist/chunks/chunk-A5JZS6ZN.js +92 -0
  17. package/dist/chunks/{chunk-7ST552E3.js → chunk-AKLTIZCU.js} +1 -1
  18. package/dist/chunks/{chunk-26XDDLXM.js → chunk-ARU7VBKR.js} +2 -2
  19. package/dist/chunks/chunk-B5XLQKHI.js +849 -0
  20. package/dist/chunks/chunk-C762AAVU.js +137 -0
  21. package/dist/chunks/{chunk-WA2SJE5S.js → chunk-CEDN47PH.js} +4 -4
  22. package/dist/chunks/{chunk-ONRLTUP2.js → chunk-CNDPIHY5.js} +24 -22
  23. package/dist/chunks/{chunk-BMKU5KEL.js → chunk-CV5YC2EN.js} +1 -1
  24. package/dist/chunks/chunk-DBYHS3CK.js +257 -0
  25. package/dist/chunks/{chunk-HDBQPBL6.js → chunk-DSTNNQVV.js} +12 -8
  26. package/dist/chunks/{chunk-QAT3CW4G.js → chunk-EFYMIIER.js} +2 -2
  27. package/dist/chunks/{chunk-NBW3BWOJ.js → chunk-EPOLDWRA.js} +2 -2
  28. package/dist/chunks/{chunk-B4TXCKXE.js → chunk-EZQDYIVB.js} +10 -8
  29. package/dist/chunks/{chunk-2EAIC3SH.js → chunk-FL4JLNT2.js} +8 -8
  30. package/dist/chunks/chunk-FRVG4OW3.js +7438 -0
  31. package/dist/chunks/{chunk-FKDO3CM4.js → chunk-FVNJTRCE.js} +17 -13
  32. package/dist/chunks/chunk-FVT74RZ5.js +1536 -0
  33. package/dist/chunks/chunk-G3PXSXIB.js +18188 -0
  34. package/dist/chunks/chunk-G5FBSUL4.js +822 -0
  35. package/dist/chunks/{chunk-FRAXI2WT.js → chunk-GCVXKRR5.js} +3 -3
  36. package/dist/chunks/chunk-GHKJAK5V.js +1288 -0
  37. package/dist/chunks/{chunk-Q5K5DEOK.js → chunk-GUU4Z2AQ.js} +42 -28
  38. package/dist/chunks/{chunk-OQ3C5VXZ.js → chunk-GVNCVKCI.js} +4 -2
  39. package/dist/chunks/chunk-HB4UKFDO.js +1295 -0
  40. package/dist/chunks/chunk-HRXRELD3.js +338 -0
  41. package/dist/chunks/{chunk-IJ4X426J.js → chunk-IIMSID24.js} +1 -1
  42. package/dist/chunks/{chunk-O75LSD3C.js → chunk-JSD4EZL3.js} +1 -1
  43. package/dist/chunks/{chunk-7AEEQOD4.js → chunk-K3RED3VO.js} +1 -1
  44. package/dist/chunks/{chunk-RSEAADCE.js → chunk-KEKR7OCB.js} +6 -4
  45. package/dist/chunks/{chunk-3T7WSWZH.js → chunk-KFWQ3EFH.js} +1 -1
  46. package/dist/chunks/{chunk-L3UXB2CW.js → chunk-KW7BS25T.js} +1 -1
  47. package/dist/chunks/{chunk-RO44KX6Y.js → chunk-N4QHMXOO.js} +11 -7
  48. package/dist/chunks/{chunk-XRWOTCDO.js → chunk-ND5CF2H3.js} +1 -1
  49. package/dist/chunks/{chunk-RSJBU3ON.js → chunk-NSOYO6JQ.js} +35 -27
  50. package/dist/chunks/{chunk-RKDCNQ4S.js → chunk-NW34PW6V.js} +3 -105
  51. package/dist/chunks/{chunk-C5HKWXRR.js → chunk-OAMU5QO6.js} +1 -1
  52. package/dist/chunks/{chunk-MTWHQEXI.js → chunk-OIH6FP5Y.js} +5 -3
  53. package/dist/chunks/chunk-P7VSBDR4.js +827 -0
  54. package/dist/chunks/chunk-PEC3CQSK.js +90 -0
  55. package/dist/chunks/{chunk-QDV5LZ4Q.js → chunk-PFM75KY3.js} +12 -8
  56. package/dist/chunks/chunk-PJXMXMCO.js +81 -0
  57. package/dist/chunks/chunk-PNGVSHR3.js +40 -0
  58. package/dist/chunks/{chunk-TPATD2MM.js → chunk-QHS645AZ.js} +14 -6
  59. package/dist/chunks/{chunk-OTXE7MHI.js → chunk-QKX7WKIN.js} +8 -6
  60. package/dist/chunks/chunk-QOPTXV4G.js +417 -0
  61. package/dist/chunks/chunk-RN6V5ODW.js +114 -0
  62. package/dist/chunks/chunk-RVBZ64EQ.js +52 -0
  63. package/dist/chunks/chunk-SHFNEZVI.js +49 -0
  64. package/dist/chunks/{chunk-OO3OF6MK.js → chunk-TGNEG57M.js} +44 -15
  65. package/dist/chunks/{chunk-WNAKOXGK.js → chunk-TO7QZGYK.js} +1 -1
  66. package/dist/chunks/chunk-UARGTFCT.js +875 -0
  67. package/dist/chunks/{chunk-FWKSJYDV.js → chunk-UG2WOB5L.js} +1 -1
  68. package/dist/chunks/chunk-V4RMJKQP.js +36 -0
  69. package/dist/chunks/chunk-VT3Z7HF6.js +233 -0
  70. package/dist/chunks/chunk-VUS2JQB2.js +121 -0
  71. package/dist/chunks/{chunk-6CZZ3SH3.js → chunk-VYC45Q4Z.js} +2 -2
  72. package/dist/chunks/{chunk-4KVJ2M4J.js → chunk-WL6QYSGD.js} +78 -17
  73. package/dist/chunks/{chunk-FZRBF25Y.js → chunk-X7DBBZQD.js} +4 -4
  74. package/dist/chunks/{chunk-2NJJ2K5S.js → chunk-XD4DCYMX.js} +6 -6
  75. package/dist/chunks/{chunk-ZSFEACZU.js → chunk-XFF5TGRA.js} +1 -1
  76. package/dist/chunks/{chunk-6TBDHUXK.js → chunk-XIFATBH5.js} +21 -15
  77. package/dist/chunks/chunk-XNIZGCN5.js +58 -0
  78. package/dist/chunks/chunk-XPJLPUKO.js +117 -0
  79. package/dist/chunks/{chunk-FXD67VN5.js → chunk-XUAWTW4W.js} +1 -1
  80. package/dist/chunks/{chunk-I526H4AS.js → chunk-YS76T533.js} +2 -2
  81. package/dist/chunks/chunk-Z7JWYFOY.js +58 -0
  82. package/dist/chunks/{chunk-6JPVTPTU.js → chunk-ZBEECGFD.js} +3 -3
  83. package/dist/chunks/{chunk-52QYYTM5.js → chunk-ZDU2NODC.js} +3 -127
  84. package/dist/chunks/chunk-ZW6HETRE.js +97 -0
  85. package/dist/chunks/{clear-IYGWCNXT.js → clear-XUQO4ZTK.js} +23 -18
  86. package/dist/chunks/{compile-vercel-config-NEEBZRUJ.js → compile-vercel-config-D3ARNHTN.js} +8 -11
  87. package/dist/chunks/{config-6DS6BBR2.js → config-37OAE7QJ.js} +22 -17
  88. package/dist/chunks/{config-NTB5EMV4.js → config-MEDLXUVM.js} +23 -18
  89. package/dist/chunks/{delete-LLC2OGHA.js → delete-3N3YZZOF.js} +16 -12
  90. package/dist/chunks/{delete-LSGID5FV.js → delete-VSWDZ2SW.js} +19 -14
  91. package/dist/chunks/detect-projects-ODNU4PK2.js +18 -0
  92. package/dist/chunks/detect-services-TESZCQWG.js +40 -0
  93. package/dist/chunks/{disable-H4EXEQK7.js → disable-A4FLFMC7.js} +17 -13
  94. package/dist/chunks/{discard-FG6VKHWN.js → discard-CHGFULBZ.js} +17 -13
  95. package/dist/chunks/{edit-YE7D3CPJ.js → edit-JZ63AJYQ.js} +17 -13
  96. package/dist/chunks/{edit-BZJSGUHT.js → edit-MHSYAPDR.js} +19 -15
  97. package/dist/chunks/{enable-6ESD4QTE.js → enable-KD46SEC5.js} +17 -13
  98. package/dist/chunks/{exec-XH4K34JM.js → exec-4IPHZ55G.js} +9 -5
  99. package/dist/chunks/{export-QWSJROLG.js → export-42QZLBSN.js} +16 -13
  100. package/dist/chunks/{image-LTHQMKFG.js → image-GP4H73A2.js} +11 -8
  101. package/dist/chunks/{import-builders-6O7ILGQJ.js → import-builders-6TBLMPL2.js} +18 -13
  102. package/dist/chunks/{inspect-2C4ZSNYC.js → inspect-5FMWMY3C.js} +22 -18
  103. package/dist/chunks/{inspect-N6SMHV3Z.js → inspect-MUVK6MMT.js} +18 -14
  104. package/dist/chunks/{inspect-F7KCTHIL.js → inspect-Q3DWW7MC.js} +22 -18
  105. package/dist/chunks/{inspect-TWDPMXZ5.js → inspect-QFXAOUL4.js} +18 -14
  106. package/dist/chunks/{inspect-ICKNCDMT.js → inspect-RNTSYM6O.js} +18 -14
  107. package/dist/chunks/{list-NWTIJF3L.js → list-IHHIPXEC.js} +20 -16
  108. package/dist/chunks/{list-IPGQVBJO.js → list-JRNWLSO5.js} +16 -14
  109. package/dist/chunks/{list-DS7ZOUXA.js → list-XHD5DLEX.js} +23 -19
  110. package/dist/chunks/{login-F7A7ONKC.js → login-PCT6KFWY.js} +23 -18
  111. package/dist/chunks/{ls-NBDX3MKN.js → ls-GPEHEFCF.js} +24 -18
  112. package/dist/chunks/{ls-RNGO257R.js → ls-PF7F4PP4.js} +27 -23
  113. package/dist/chunks/{ls-XINES6PL.js → ls-PQZ2RIDX.js} +24 -18
  114. package/dist/chunks/{ls-D4TUDBIH.js → ls-SVOHC3XW.js} +24 -18
  115. package/dist/chunks/{ls-2QW3ZSM6.js → ls-TGHCCARZ.js} +24 -18
  116. package/dist/chunks/{ls-LSJEUPFX.js → ls-VRIH5WA3.js} +22 -15
  117. package/dist/chunks/{open-VRQDWZAW.js → open-E7DEKYDU.js} +18 -13
  118. package/dist/chunks/{permissions-6C5C7TEV.js → permissions-JKOONWVL.js} +14 -11
  119. package/dist/chunks/{publish-GVIZPNLN.js → publish-EDDELDE5.js} +17 -13
  120. package/dist/chunks/pull-646WEVDE.js +45 -0
  121. package/dist/chunks/{push-EFZ5P5Z6.js → push-LTNW5OVD.js} +23 -18
  122. package/dist/chunks/{query-GBS2PIT4.js → query-LU4N6KPO.js} +22 -19
  123. package/dist/chunks/{reorder-TN65IFRL.js → reorder-22PKJMZP.js} +17 -13
  124. package/dist/chunks/{reply-DYVEV3PY.js → reply-SF2EZMVZ.js} +17 -13
  125. package/dist/chunks/{resolve-JAWFBPUM.js → resolve-ZCZGXTOT.js} +16 -12
  126. package/dist/chunks/resolve-deployment-framework-preset-NPE6RLV3.js +36 -0
  127. package/dist/chunks/{restore-TJVMHUBQ.js → restore-VJAWZXB4.js} +17 -13
  128. package/dist/chunks/{rm-7XACNZ2U.js → rm-KN2QFCKO.js} +23 -18
  129. package/dist/chunks/{rm-REJVXALW.js → rm-KVEAJPRE.js} +23 -18
  130. package/dist/chunks/{rm-CBPNMSRP.js → rm-OSZ5FZUM.js} +23 -16
  131. package/dist/chunks/{rm-5B5VHWWN.js → rm-W722Q2AO.js} +21 -18
  132. package/dist/chunks/{rm-HQ5CYNJA.js → rm-WNPGTUBH.js} +23 -18
  133. package/dist/chunks/{routes-2OLIBRYX.js → routes-QVMBXOSX.js} +7 -3
  134. package/dist/chunks/{rule-inspect-ZSTDDFID.js → rule-inspect-25Z6SNX3.js} +28 -24
  135. package/dist/chunks/{rules-VGV4M4KY.js → rules-65LKAQ35.js} +15 -12
  136. package/dist/chunks/{schema-45SJNY5L.js → schema-7D6IGJEJ.js} +9 -7
  137. package/dist/chunks/{schema-GMTQOQCV.js → schema-NXCW4M75.js} +19 -17
  138. package/dist/chunks/{set-Z5FO2FCC.js → set-FYJVKMPV.js} +20 -13
  139. package/dist/chunks/setup-and-link-KXPZE32P.js +65 -0
  140. package/dist/chunks/{tags-SDRXWJ63.js → tags-ANIRP5E3.js} +10 -7
  141. package/dist/chunks/{types-JGANJ5EQ.js → types-4GAJ7XQQ.js} +9 -7
  142. package/dist/chunks/{update-JBQBC3IV.js → update-UT6CTKVG.js} +32 -19
  143. package/dist/commands/build/index.js +86 -49
  144. package/dist/commands/deploy/index.js +75 -66
  145. package/dist/commands/dev/index.js +98 -52
  146. package/dist/commands/env/index.js +67 -43
  147. package/dist/commands/link/index.js +48 -27
  148. package/dist/commands/list/index.js +33 -22
  149. package/dist/commands-bulk.js +1659 -1287
  150. package/dist/index.js +62 -40
  151. package/dist/version.mjs +1 -1
  152. package/package.json +46 -46
  153. package/dist/chunks/chunk-WYU64FLP.js +0 -62123
  154. 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
+ };