netlify-cli 10.6.3 → 10.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "10.6.3",
3
+ "version": "10.7.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "10.6.3",
9
+ "version": "10.7.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
- "@netlify/build": "^27.3.1",
14
- "@netlify/config": "^18.1.0",
15
- "@netlify/edge-bundler": "^1.4.1",
13
+ "@netlify/build": "^27.3.2",
14
+ "@netlify/config": "^18.1.1",
15
+ "@netlify/edge-bundler": "^1.4.2",
16
16
  "@netlify/framework-info": "^9.1.0",
17
17
  "@netlify/local-functions-proxy": "^1.1.1",
18
- "@netlify/plugins-list": "^6.28.0",
18
+ "@netlify/plugins-list": "^6.30.0",
19
19
  "@netlify/zip-it-and-ship-it": "^5.11.1",
20
20
  "@octokit/rest": "^18.0.0",
21
21
  "@sindresorhus/slugify": "^1.1.0",
@@ -1177,13 +1177,13 @@
1177
1177
  }
1178
1178
  },
1179
1179
  "node_modules/@netlify/build": {
1180
- "version": "27.3.1",
1181
- "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.3.1.tgz",
1182
- "integrity": "sha512-7b1/mgZKRK4mDxA0GsaUHX/8bkzKSm1YufedOyZquq13WxMubrBqY55jsBBblT2SOd+PQgTq+/Nb/tgx12nU0Q==",
1180
+ "version": "27.3.2",
1181
+ "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.3.2.tgz",
1182
+ "integrity": "sha512-QoaRwx+qt7582mXSZP0s3YCsK2/xUOsEfhx2Q3PvYKKdVDGjx5MROMuCdc480e8KPWsTTUheB2+A5RuB9dpcLQ==",
1183
1183
  "dependencies": {
1184
1184
  "@bugsnag/js": "^7.0.0",
1185
1185
  "@netlify/cache-utils": "^4.0.0",
1186
- "@netlify/config": "^18.1.0",
1186
+ "@netlify/config": "^18.1.1",
1187
1187
  "@netlify/edge-bundler": "^1.4.1",
1188
1188
  "@netlify/functions-utils": "^4.2.0",
1189
1189
  "@netlify/git-utils": "^4.0.0",
@@ -1764,9 +1764,9 @@
1764
1764
  }
1765
1765
  },
1766
1766
  "node_modules/@netlify/build/node_modules/read-pkg-up/node_modules/type-fest": {
1767
- "version": "2.14.0",
1768
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.14.0.tgz",
1769
- "integrity": "sha512-hQnTQkFjL5ik6HF2fTAM8ycbr94UbQXK364wF930VHb0dfBJ5JBP8qwrR8TaK9zwUEk7meruo2JAUDMwvuxd/w==",
1767
+ "version": "2.15.1",
1768
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.15.1.tgz",
1769
+ "integrity": "sha512-LYSjcIz3NmoQksXq/3/B7Nfad+T8mkaI628agAAnHCpXPTBRMK2ygt3eABpzII8CbZZM8dLdVQ4Gr8ousjFjMw==",
1770
1770
  "engines": {
1771
1771
  "node": ">=12.20"
1772
1772
  },
@@ -1775,9 +1775,9 @@
1775
1775
  }
1776
1776
  },
1777
1777
  "node_modules/@netlify/build/node_modules/read-pkg/node_modules/type-fest": {
1778
- "version": "2.14.0",
1779
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.14.0.tgz",
1780
- "integrity": "sha512-hQnTQkFjL5ik6HF2fTAM8ycbr94UbQXK364wF930VHb0dfBJ5JBP8qwrR8TaK9zwUEk7meruo2JAUDMwvuxd/w==",
1778
+ "version": "2.15.1",
1779
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.15.1.tgz",
1780
+ "integrity": "sha512-LYSjcIz3NmoQksXq/3/B7Nfad+T8mkaI628agAAnHCpXPTBRMK2ygt3eABpzII8CbZZM8dLdVQ4Gr8ousjFjMw==",
1781
1781
  "engines": {
1782
1782
  "node": ">=12.20"
1783
1783
  },
@@ -1969,9 +1969,9 @@
1969
1969
  }
1970
1970
  },
1971
1971
  "node_modules/@netlify/config": {
1972
- "version": "18.1.0",
1973
- "resolved": "https://registry.npmjs.org/@netlify/config/-/config-18.1.0.tgz",
1974
- "integrity": "sha512-l5CpXb3qM2fmduu3VnrlBNBZ1Xtwm0+ZLZCIUkDa3GFe3X2LLXN2TEttHP/KFSQg7LmRRYX154ReYcpH0QJNpA==",
1972
+ "version": "18.1.1",
1973
+ "resolved": "https://registry.npmjs.org/@netlify/config/-/config-18.1.1.tgz",
1974
+ "integrity": "sha512-w3rIWV72anBCnAb69rCTnuwkLHhZUgZPf9Gsr0Y5AIf/sWJ7cbxwo9cAewgfqVt7ZOFniiQD5ePOaZOawGdn8A==",
1975
1975
  "dependencies": {
1976
1976
  "chalk": "^5.0.0",
1977
1977
  "cron-parser": "^4.1.0",
@@ -2279,9 +2279,9 @@
2279
2279
  }
2280
2280
  },
2281
2281
  "node_modules/@netlify/config/node_modules/type-fest": {
2282
- "version": "2.14.0",
2283
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.14.0.tgz",
2284
- "integrity": "sha512-hQnTQkFjL5ik6HF2fTAM8ycbr94UbQXK364wF930VHb0dfBJ5JBP8qwrR8TaK9zwUEk7meruo2JAUDMwvuxd/w==",
2282
+ "version": "2.15.1",
2283
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.15.1.tgz",
2284
+ "integrity": "sha512-LYSjcIz3NmoQksXq/3/B7Nfad+T8mkaI628agAAnHCpXPTBRMK2ygt3eABpzII8CbZZM8dLdVQ4Gr8ousjFjMw==",
2285
2285
  "engines": {
2286
2286
  "node": ">=12.20"
2287
2287
  },
@@ -2301,9 +2301,9 @@
2301
2301
  }
2302
2302
  },
2303
2303
  "node_modules/@netlify/edge-bundler": {
2304
- "version": "1.4.1",
2305
- "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.4.1.tgz",
2306
- "integrity": "sha512-sgahUAtGiOHGT/mznoxsLrUmKKq8pzEitS4i5CNHFbdPcY2wUnqHTiKGNLEl1VLtenyLRa6RAujjxRVpYE90mg==",
2304
+ "version": "1.4.2",
2305
+ "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.4.2.tgz",
2306
+ "integrity": "sha512-grllAfoFzZu6m63pkcm8GqoG8wng6AIKNjY/Ay6UTMn+E2lBgB6pw2fF7xT8mGYWSB2TLdRlQ4RyPE/DUoyoIQ==",
2307
2307
  "dependencies": {
2308
2308
  "common-path-prefix": "^3.0.0",
2309
2309
  "del": "^6.0.0",
@@ -3534,9 +3534,9 @@
3534
3534
  "integrity": "sha512-ZJF4nbLPfxsWrVgp2reCb23HMxsWl5+r+K0RtIhxcZ/RxbHVihRA9mwyzIcxPWrT5x9uAAxCr1aKGP7IdsDe+Q=="
3535
3535
  },
3536
3536
  "node_modules/@netlify/plugins-list": {
3537
- "version": "6.29.0",
3538
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.29.0.tgz",
3539
- "integrity": "sha512-H81D32COgftfzJhY+TWNtxd8EXaQS1c/Gkj3WI/v4xhsZvw/6MOzKtDopK7Mq7nYk+aKc2OqxfOuQNR02FpQug==",
3537
+ "version": "6.30.0",
3538
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.30.0.tgz",
3539
+ "integrity": "sha512-NF0G7rMl/FbCkZMDiihoDW70i96aF3fguHvuspucstM4ArAdMai5b3rEKSOO2SXTbmQHaAlQEpiYAPZsGwU7jg==",
3540
3540
  "engines": {
3541
3541
  "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
3542
3542
  }
@@ -22643,9 +22643,9 @@
22643
22643
  }
22644
22644
  },
22645
22645
  "node_modules/winston": {
22646
- "version": "3.7.2",
22647
- "resolved": "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz",
22648
- "integrity": "sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng==",
22646
+ "version": "3.8.0",
22647
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.0.tgz",
22648
+ "integrity": "sha512-Iix1w8rIq2kBDkGvclO0db2CVOHYVamCIkVWcUbs567G9i2pdB+gvqLgDgxx4B4HXHYD6U4Zybh6ojepUOqcFQ==",
22649
22649
  "dependencies": {
22650
22650
  "@dabh/diagnostics": "^2.0.2",
22651
22651
  "async": "^3.2.3",
@@ -23705,13 +23705,13 @@
23705
23705
  }
23706
23706
  },
23707
23707
  "@netlify/build": {
23708
- "version": "27.3.1",
23709
- "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.3.1.tgz",
23710
- "integrity": "sha512-7b1/mgZKRK4mDxA0GsaUHX/8bkzKSm1YufedOyZquq13WxMubrBqY55jsBBblT2SOd+PQgTq+/Nb/tgx12nU0Q==",
23708
+ "version": "27.3.2",
23709
+ "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.3.2.tgz",
23710
+ "integrity": "sha512-QoaRwx+qt7582mXSZP0s3YCsK2/xUOsEfhx2Q3PvYKKdVDGjx5MROMuCdc480e8KPWsTTUheB2+A5RuB9dpcLQ==",
23711
23711
  "requires": {
23712
23712
  "@bugsnag/js": "^7.0.0",
23713
23713
  "@netlify/cache-utils": "^4.0.0",
23714
- "@netlify/config": "^18.1.0",
23714
+ "@netlify/config": "^18.1.1",
23715
23715
  "@netlify/edge-bundler": "^1.4.1",
23716
23716
  "@netlify/functions-utils": "^4.2.0",
23717
23717
  "@netlify/git-utils": "^4.0.0",
@@ -24059,9 +24059,9 @@
24059
24059
  },
24060
24060
  "dependencies": {
24061
24061
  "type-fest": {
24062
- "version": "2.14.0",
24063
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.14.0.tgz",
24064
- "integrity": "sha512-hQnTQkFjL5ik6HF2fTAM8ycbr94UbQXK364wF930VHb0dfBJ5JBP8qwrR8TaK9zwUEk7meruo2JAUDMwvuxd/w=="
24062
+ "version": "2.15.1",
24063
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.15.1.tgz",
24064
+ "integrity": "sha512-LYSjcIz3NmoQksXq/3/B7Nfad+T8mkaI628agAAnHCpXPTBRMK2ygt3eABpzII8CbZZM8dLdVQ4Gr8ousjFjMw=="
24065
24065
  }
24066
24066
  }
24067
24067
  },
@@ -24076,9 +24076,9 @@
24076
24076
  },
24077
24077
  "dependencies": {
24078
24078
  "type-fest": {
24079
- "version": "2.14.0",
24080
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.14.0.tgz",
24081
- "integrity": "sha512-hQnTQkFjL5ik6HF2fTAM8ycbr94UbQXK364wF930VHb0dfBJ5JBP8qwrR8TaK9zwUEk7meruo2JAUDMwvuxd/w=="
24079
+ "version": "2.15.1",
24080
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.15.1.tgz",
24081
+ "integrity": "sha512-LYSjcIz3NmoQksXq/3/B7Nfad+T8mkaI628agAAnHCpXPTBRMK2ygt3eABpzII8CbZZM8dLdVQ4Gr8ousjFjMw=="
24082
24082
  }
24083
24083
  }
24084
24084
  },
@@ -24192,9 +24192,9 @@
24192
24192
  }
24193
24193
  },
24194
24194
  "@netlify/config": {
24195
- "version": "18.1.0",
24196
- "resolved": "https://registry.npmjs.org/@netlify/config/-/config-18.1.0.tgz",
24197
- "integrity": "sha512-l5CpXb3qM2fmduu3VnrlBNBZ1Xtwm0+ZLZCIUkDa3GFe3X2LLXN2TEttHP/KFSQg7LmRRYX154ReYcpH0QJNpA==",
24195
+ "version": "18.1.1",
24196
+ "resolved": "https://registry.npmjs.org/@netlify/config/-/config-18.1.1.tgz",
24197
+ "integrity": "sha512-w3rIWV72anBCnAb69rCTnuwkLHhZUgZPf9Gsr0Y5AIf/sWJ7cbxwo9cAewgfqVt7ZOFniiQD5ePOaZOawGdn8A==",
24198
24198
  "requires": {
24199
24199
  "chalk": "^5.0.0",
24200
24200
  "cron-parser": "^4.1.0",
@@ -24370,9 +24370,9 @@
24370
24370
  "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="
24371
24371
  },
24372
24372
  "type-fest": {
24373
- "version": "2.14.0",
24374
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.14.0.tgz",
24375
- "integrity": "sha512-hQnTQkFjL5ik6HF2fTAM8ycbr94UbQXK364wF930VHb0dfBJ5JBP8qwrR8TaK9zwUEk7meruo2JAUDMwvuxd/w=="
24373
+ "version": "2.15.1",
24374
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.15.1.tgz",
24375
+ "integrity": "sha512-LYSjcIz3NmoQksXq/3/B7Nfad+T8mkaI628agAAnHCpXPTBRMK2ygt3eABpzII8CbZZM8dLdVQ4Gr8ousjFjMw=="
24376
24376
  },
24377
24377
  "yocto-queue": {
24378
24378
  "version": "1.0.0",
@@ -24382,9 +24382,9 @@
24382
24382
  }
24383
24383
  },
24384
24384
  "@netlify/edge-bundler": {
24385
- "version": "1.4.1",
24386
- "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.4.1.tgz",
24387
- "integrity": "sha512-sgahUAtGiOHGT/mznoxsLrUmKKq8pzEitS4i5CNHFbdPcY2wUnqHTiKGNLEl1VLtenyLRa6RAujjxRVpYE90mg==",
24385
+ "version": "1.4.2",
24386
+ "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.4.2.tgz",
24387
+ "integrity": "sha512-grllAfoFzZu6m63pkcm8GqoG8wng6AIKNjY/Ay6UTMn+E2lBgB6pw2fF7xT8mGYWSB2TLdRlQ4RyPE/DUoyoIQ==",
24388
24388
  "requires": {
24389
24389
  "common-path-prefix": "^3.0.0",
24390
24390
  "del": "^6.0.0",
@@ -25065,9 +25065,9 @@
25065
25065
  "integrity": "sha512-ZJF4nbLPfxsWrVgp2reCb23HMxsWl5+r+K0RtIhxcZ/RxbHVihRA9mwyzIcxPWrT5x9uAAxCr1aKGP7IdsDe+Q=="
25066
25066
  },
25067
25067
  "@netlify/plugins-list": {
25068
- "version": "6.29.0",
25069
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.29.0.tgz",
25070
- "integrity": "sha512-H81D32COgftfzJhY+TWNtxd8EXaQS1c/Gkj3WI/v4xhsZvw/6MOzKtDopK7Mq7nYk+aKc2OqxfOuQNR02FpQug=="
25068
+ "version": "6.30.0",
25069
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.30.0.tgz",
25070
+ "integrity": "sha512-NF0G7rMl/FbCkZMDiihoDW70i96aF3fguHvuspucstM4ArAdMai5b3rEKSOO2SXTbmQHaAlQEpiYAPZsGwU7jg=="
25071
25071
  },
25072
25072
  "@netlify/run-utils": {
25073
25073
  "version": "4.0.1",
@@ -39695,9 +39695,9 @@
39695
39695
  }
39696
39696
  },
39697
39697
  "winston": {
39698
- "version": "3.7.2",
39699
- "resolved": "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz",
39700
- "integrity": "sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng==",
39698
+ "version": "3.8.0",
39699
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.0.tgz",
39700
+ "integrity": "sha512-Iix1w8rIq2kBDkGvclO0db2CVOHYVamCIkVWcUbs567G9i2pdB+gvqLgDgxx4B4HXHYD6U4Zybh6ojepUOqcFQ==",
39701
39701
  "requires": {
39702
39702
  "@dabh/diagnostics": "^2.0.2",
39703
39703
  "async": "^3.2.3",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "10.6.3",
4
+ "version": "10.7.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
@@ -55,6 +55,7 @@
55
55
  "Jake Jarvis <jake@jarv.is> (https://twitter.com/jakejarvis)",
56
56
  "Jakob Warkotsch <j.warkotsch@gmail.com>",
57
57
  "James George (https://twitter.com/james_madhacks)",
58
+ "Jason Barry (https://twitter.com/jasbarry)",
58
59
  "Jason Lengstorf <jason@lengstorf.com> (https://twitter.com/jlengstorf)",
59
60
  "Jeremy Monson (www.surfline.com)",
60
61
  "Jessica Parsons",
@@ -212,12 +213,12 @@
212
213
  "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,yml,json,html}\" \"*.{mjs,cjs,js,yml,json,html}\" \".*.{mjs,cjs,js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!**/*/package-lock.json\" \"!.github/**/*.md\""
213
214
  },
214
215
  "dependencies": {
215
- "@netlify/build": "^27.3.1",
216
- "@netlify/config": "^18.1.0",
217
- "@netlify/edge-bundler": "^1.4.1",
216
+ "@netlify/build": "^27.3.2",
217
+ "@netlify/config": "^18.1.1",
218
+ "@netlify/edge-bundler": "^1.4.2",
218
219
  "@netlify/framework-info": "^9.1.0",
219
220
  "@netlify/local-functions-proxy": "^1.1.1",
220
- "@netlify/plugins-list": "^6.28.0",
221
+ "@netlify/plugins-list": "^6.30.0",
221
222
  "@netlify/zip-it-and-ship-it": "^5.11.1",
222
223
  "@octokit/rest": "^18.0.0",
223
224
  "@sindresorhus/slugify": "^1.1.0",
@@ -26,6 +26,7 @@ const {
26
26
  getNetlifyGraphConfig,
27
27
  readGraphQLOperationsSourceFile,
28
28
  } = require('../../lib/one-graph/cli-netlify-graph')
29
+ const { startSpinner, stopSpinner } = require('../../lib/spinner')
29
30
  const {
30
31
  BANG,
31
32
  NETLIFYDEV,
@@ -115,7 +116,7 @@ const cleanupBeforeExit = async ({ exitCode }) => {
115
116
  * @param {NodeJS.ProcessEnv} env
116
117
  * @returns {execa.ExecaChildProcess<string>}
117
118
  */
118
- const runCommand = (command, env = {}) => {
119
+ const runCommand = (command, env = {}, spinner = null) => {
119
120
  const commandProcess = execa.command(command, {
120
121
  preferLocal: true,
121
122
  // we use reject=false to avoid rejecting synchronously when the command doesn't exist
@@ -125,8 +126,23 @@ const runCommand = (command, env = {}) => {
125
126
  windowsHide: false,
126
127
  })
127
128
 
128
- commandProcess.stdout.pipe(stripAnsiCc.stream()).pipe(process.stdout)
129
- commandProcess.stderr.pipe(stripAnsiCc.stream()).pipe(process.stderr)
129
+ // This ensures that an active spinner stays at the bottom of the commandline
130
+ // even though the actual framework command might be outputting stuff
131
+ const pipeDataWithSpinner = (writeStream, chunk) => {
132
+ if (spinner && spinner.isSpinning) {
133
+ spinner.clear()
134
+ spinner.isSilent = true
135
+ }
136
+ writeStream.write(chunk, () => {
137
+ if (spinner && spinner.isSpinning) {
138
+ spinner.isSilent = false
139
+ spinner.render()
140
+ }
141
+ })
142
+ }
143
+
144
+ commandProcess.stdout.pipe(stripAnsiCc.stream()).on('data', pipeDataWithSpinner.bind(null, process.stdout))
145
+ commandProcess.stderr.pipe(stripAnsiCc.stream()).on('data', pipeDataWithSpinner.bind(null, process.stderr))
130
146
  process.stdin.pipe(commandProcess.stdin)
131
147
 
132
148
  // we can't try->await->catch since we don't want to block on the framework server which
@@ -173,15 +189,16 @@ const startFrameworkServer = async function ({ settings }) {
173
189
 
174
190
  log(`${NETLIFYDEVLOG} Starting Netlify Dev with ${settings.framework || 'custom config'}`)
175
191
 
176
- runCommand(settings.command, settings.env)
192
+ const spinner = startSpinner({
193
+ text: `Waiting for framework port ${settings.frameworkPort}. This can be configured using the 'targetPort' property in the netlify.toml`,
194
+ })
195
+
196
+ runCommand(settings.command, settings.env, spinner)
177
197
 
178
198
  try {
179
- log(
180
- `${NETLIFYDEVLOG} Waiting for framework port ${settings.frameworkPort}. This can be configured using the 'targetPort' property in the netlify.toml`,
181
- )
182
199
  const open = await waitPort({
183
200
  port: settings.frameworkPort,
184
- output: 'dots',
201
+ output: 'silent',
185
202
  timeout: FRAMEWORK_PORT_TIMEOUT,
186
203
  ...(settings.pollingStrategies.includes('HTTP') && { protocol: 'http' }),
187
204
  })
@@ -189,7 +206,10 @@ const startFrameworkServer = async function ({ settings }) {
189
206
  if (!open) {
190
207
  throw new Error(`Timed out waiting for port '${settings.frameworkPort}' to be open`)
191
208
  }
209
+
210
+ stopSpinner({ error: false, spinner })
192
211
  } catch {
212
+ stopSpinner({ error: true, spinner })
193
213
  log(NETLIFYDEVERR, `Netlify Dev could not connect to localhost:${settings.frameworkPort}.`)
194
214
  log(NETLIFYDEVERR, `Please make sure your framework server is running on port ${settings.frameworkPort}`)
195
215
  exit(1)
@@ -5,7 +5,7 @@ const AsciiTable = require('ascii-table')
5
5
  const dotenv = require('dotenv')
6
6
  const isEmpty = require('lodash/isEmpty')
7
7
 
8
- const { exit, log, logJson } = require('../../utils')
8
+ const { exit, log, logJson, translateFromEnvelopeToMongo, translateFromMongoToEnvelope } = require('../../utils')
9
9
 
10
10
  /**
11
11
  * The env:import command
@@ -23,13 +23,6 @@ const envImport = async (fileName, options, command) => {
23
23
  return false
24
24
  }
25
25
 
26
- const siteData = await api.getSite({ siteId })
27
-
28
- // Get current environment variables set in the UI
29
- const {
30
- build_settings: { env = {} },
31
- } = siteData
32
-
33
26
  let importedEnv = {}
34
27
  try {
35
28
  const envFileContents = await readFile(fileName, 'utf-8')
@@ -44,21 +37,14 @@ const envImport = async (fileName, options, command) => {
44
37
  return false
45
38
  }
46
39
 
47
- // Apply environment variable updates
48
- const siteResult = await api.updateSite({
49
- siteId,
50
- body: {
51
- build_settings: {
52
- // Only set imported variables if --replaceExisting or otherwise merge
53
- // imported ones with the current environment variables.
54
- env: options.replaceExisting ? importedEnv : { ...env, ...importedEnv },
55
- },
56
- },
57
- })
40
+ const siteData = await api.getSite({ siteId })
41
+
42
+ const importIntoService = siteData.use_envelope ? importIntoEnvelope : importIntoMongo
43
+ const finalEnv = await importIntoService({ api, importedEnv, options, siteData })
58
44
 
59
45
  // Return new environment variables of site if using json flag
60
46
  if (options.json) {
61
- logJson(siteResult.build_settings.env)
47
+ logJson(finalEnv)
62
48
  return false
63
49
  }
64
50
 
@@ -71,6 +57,66 @@ const envImport = async (fileName, options, command) => {
71
57
  log(table.toString())
72
58
  }
73
59
 
60
+ /**
61
+ * Updates the imported env in the site record
62
+ * @returns {Promise<object>}
63
+ */
64
+ const importIntoMongo = async ({ api, importedEnv, options, siteData }) => {
65
+ const { env = {} } = siteData.build_settings
66
+ const siteId = siteData.id
67
+
68
+ const finalEnv = options.replaceExisting ? importedEnv : { ...env, ...importedEnv }
69
+
70
+ // Apply environment variable updates
71
+ await api.updateSite({
72
+ siteId,
73
+ body: {
74
+ build_settings: {
75
+ // Only set imported variables if --replaceExisting or otherwise merge
76
+ // imported ones with the current environment variables.
77
+ env: finalEnv,
78
+ },
79
+ },
80
+ })
81
+
82
+ return finalEnv
83
+ }
84
+
85
+ /**
86
+ * Saves the imported env in the Envelope service
87
+ * @returns {Promise<object>}
88
+ */
89
+ const importIntoEnvelope = async ({ api, importedEnv, options, siteData }) => {
90
+ // fetch env vars
91
+ const accountId = siteData.account_slug
92
+ const siteId = siteData.id
93
+ const dotEnvKeys = Object.keys(importedEnv)
94
+ const envelopeVariables = await api.getEnvVars({ accountId, siteId })
95
+ const envelopeKeys = envelopeVariables.map(({ key }) => key)
96
+
97
+ // if user intends to replace all existing env vars
98
+ // either replace; delete all existing env vars on the site
99
+ // or, merge; delete only the existing env vars that would collide with new .env entries
100
+ const keysToDelete = options.replaceExisting ? envelopeKeys : envelopeKeys.filter((key) => dotEnvKeys.includes(key))
101
+
102
+ // delete marked env vars in parallel
103
+ await Promise.all(keysToDelete.map((key) => api.deleteEnvVar({ accountId, siteId, key })))
104
+
105
+ // hit create endpoint
106
+ const body = translateFromMongoToEnvelope(importedEnv)
107
+ try {
108
+ await api.createEnvVars({ accountId, siteId, body })
109
+ } catch (error) {
110
+ throw error.json ? error.json.msg : error
111
+ }
112
+
113
+ // return final env to aid in --json output (for testing)
114
+ return {
115
+ ...translateFromEnvelopeToMongo(envelopeVariables.filter(({ key }) => !keysToDelete.includes(key))),
116
+ ...importedEnv,
117
+ }
118
+ }
119
+
74
120
  /**
75
121
  * Creates the `netlify env:import` command
76
122
  * @param {import('../base-command').BaseCommand} program
@@ -2,7 +2,13 @@
2
2
 
3
3
  const { isEmpty } = require('lodash')
4
4
 
5
- const { chalk, error: logError, log } = require('../../utils')
5
+ const {
6
+ chalk,
7
+ error: logError,
8
+ log,
9
+ translateFromEnvelopeToMongo,
10
+ translateFromMongoToEnvelope,
11
+ } = require('../../utils')
6
12
 
7
13
  const safeGetSite = async (api, siteId) => {
8
14
  try {
@@ -51,6 +57,37 @@ const envMigrate = async (options, command) => {
51
57
  return false
52
58
  }
53
59
 
60
+ // determine if siteFrom and/or siteTo is on Envelope
61
+ let method
62
+ if (!siteFrom.use_envelope && !siteTo.use_envelope) {
63
+ method = mongoToMongo
64
+ } else if (!siteFrom.use_envelope && siteTo.use_envelope) {
65
+ method = mongoToEnvelope
66
+ } else if (siteFrom.use_envelope && !siteTo.use_envelope) {
67
+ method = envelopeToMongo
68
+ } else {
69
+ method = envelopeToEnvelope
70
+ }
71
+ const success = await method({ api, siteFrom, siteTo })
72
+
73
+ if (!success) {
74
+ return false
75
+ }
76
+
77
+ log(
78
+ `Successfully migrated environment variables from ${chalk.greenBright(siteFrom.name)} to ${chalk.greenBright(
79
+ siteTo.name,
80
+ )}`,
81
+ )
82
+
83
+ return true
84
+ }
85
+
86
+ /**
87
+ * Copies the env from a site not configured with Envelope to a different site not configured with Envelope
88
+ * @returns {Promise<boolean>}
89
+ */
90
+ const mongoToMongo = async ({ api, siteFrom, siteTo }) => {
54
91
  const [
55
92
  {
56
93
  build_settings: { env: envFrom = {} },
@@ -73,7 +110,7 @@ const envMigrate = async (options, command) => {
73
110
 
74
111
  // Apply environment variable updates
75
112
  await api.updateSite({
76
- siteId: siteId.to,
113
+ siteId: siteTo.id,
77
114
  body: {
78
115
  build_settings: {
79
116
  env: mergedEnv,
@@ -81,11 +118,107 @@ const envMigrate = async (options, command) => {
81
118
  },
82
119
  })
83
120
 
84
- log(
85
- `Successfully migrated environment variables from ${chalk.greenBright(siteFrom.name)} to ${chalk.greenBright(
86
- siteTo.name,
87
- )}`,
88
- )
121
+ return true
122
+ }
123
+
124
+ /**
125
+ * Copies the env from a site not configured with Envelope to a site configured with Envelope
126
+ * @returns {Promise<boolean>}
127
+ */
128
+ const mongoToEnvelope = async ({ api, siteFrom, siteTo }) => {
129
+ const envFrom = siteFrom.build_settings.env || {}
130
+ const keysFrom = Object.keys(envFrom)
131
+
132
+ if (isEmpty(envFrom)) {
133
+ log(`${chalk.greenBright(siteFrom.name)} has no environment variables, nothing to migrate`)
134
+ return false
135
+ }
136
+
137
+ const accountId = siteTo.account_slug
138
+ const siteId = siteTo.id
139
+
140
+ const envelopeTo = await api.getEnvVars({ accountId, siteId })
141
+
142
+ const envVarsToDelete = envelopeTo.filter(({ key }) => keysFrom.includes(key))
143
+ // delete marked env vars in parallel
144
+ await Promise.all(envVarsToDelete.map(({ key }) => api.deleteEnvVar({ accountId, siteId, key })))
145
+
146
+ // hit create endpoint
147
+ const body = translateFromMongoToEnvelope(envFrom)
148
+ try {
149
+ await api.createEnvVars({ accountId, siteId, body })
150
+ } catch (error) {
151
+ throw error.json ? error.json.msg : error
152
+ }
153
+
154
+ return true
155
+ }
156
+
157
+ /**
158
+ * Copies the env from a site configured with Envelope to a site not configured with Envelope
159
+ * @returns {Promise<boolean>}
160
+ */
161
+ const envelopeToMongo = async ({ api, siteFrom, siteTo }) => {
162
+ const envelopeVariables = await api.getEnvVars({ accountId: siteFrom.account_slug, siteId: siteFrom.id })
163
+ const envFrom = translateFromEnvelopeToMongo(envelopeVariables)
164
+
165
+ if (isEmpty(envFrom)) {
166
+ log(`${chalk.greenBright(siteFrom.name)} has no environment variables, nothing to migrate`)
167
+ return false
168
+ }
169
+
170
+ const envTo = siteTo.build_settings.env || {}
171
+
172
+ // Merge from site A to site B
173
+ const mergedEnv = {
174
+ ...envTo,
175
+ ...envFrom,
176
+ }
177
+
178
+ // Apply environment variable updates
179
+ await api.updateSite({
180
+ siteId: siteTo.id,
181
+ body: {
182
+ build_settings: {
183
+ env: mergedEnv,
184
+ },
185
+ },
186
+ })
187
+
188
+ return true
189
+ }
190
+
191
+ /**
192
+ * Copies the env from a site configured with Envelope to a different site configured with Envelope
193
+ * @returns {Promise<boolean>}
194
+ */
195
+ const envelopeToEnvelope = async ({ api, siteFrom, siteTo }) => {
196
+ const [envelopeFrom, envelopeTo] = await Promise.all([
197
+ api.getEnvVars({ accountId: siteFrom.account_slug, siteId: siteFrom.id }),
198
+ api.getEnvVars({ accountId: siteTo.account_slug, siteId: siteTo.id }),
199
+ ])
200
+
201
+ const keysFrom = envelopeFrom.map(({ key }) => key)
202
+
203
+ if (isEmpty(keysFrom)) {
204
+ log(`${chalk.greenBright(siteFrom.name)} has no environment variables, nothing to migrate`)
205
+ return false
206
+ }
207
+
208
+ const accountId = siteTo.account_slug
209
+ const siteId = siteTo.id
210
+ const envVarsToDelete = envelopeTo.filter(({ key }) => keysFrom.includes(key))
211
+ // delete marked env vars in parallel
212
+ await Promise.all(envVarsToDelete.map(({ key }) => api.deleteEnvVar({ accountId, siteId, key })))
213
+
214
+ // hit create endpoint
215
+ try {
216
+ await api.createEnvVars({ accountId, siteId, body: envelopeFrom })
217
+ } catch (error) {
218
+ throw error.json ? error.json.msg : error
219
+ }
220
+
221
+ return true
89
222
  }
90
223
 
91
224
  /**
@@ -1,15 +1,15 @@
1
1
  // @ts-check
2
- const { log, logJson } = require('../../utils')
2
+ const { log, logJson, translateFromEnvelopeToMongo } = require('../../utils')
3
3
 
4
4
  /**
5
5
  * The env:set command
6
- * @param {string} name Environment variable name
6
+ * @param {string} key Environment variable key
7
7
  * @param {string} value Value to set to
8
8
  * @param {import('commander').OptionValues} options
9
9
  * @param {import('../base-command').BaseCommand} command
10
10
  * @returns {Promise<boolean>}
11
11
  */
12
- const envSet = async (name, value, options, command) => {
12
+ const envSet = async (key, value, options, command) => {
13
13
  const { api, site } = command.netlify
14
14
  const siteId = site.id
15
15
 
@@ -21,32 +21,67 @@ const envSet = async (name, value, options, command) => {
21
21
  const siteData = await api.getSite({ siteId })
22
22
 
23
23
  // Get current environment variables set in the UI
24
- const {
25
- build_settings: { env = {} },
26
- } = siteData
24
+ const setInService = siteData.use_envelope ? setInEnvelope : setInMongo
25
+ const finalEnv = await setInService({ api, siteData, key, value })
27
26
 
27
+ // Return new environment variables of site if using json flag
28
+ if (options.json) {
29
+ logJson(finalEnv)
30
+ return false
31
+ }
32
+
33
+ log(`Set environment variable ${key}=${value} for site ${siteData.name}`)
34
+ }
35
+
36
+ /**
37
+ * Updates the env for a site record with a new key/value pair
38
+ * @returns {Promise<object>}
39
+ */
40
+ const setInMongo = async ({ api, key, siteData, value }) => {
41
+ const { env = {} } = siteData.build_settings
28
42
  const newEnv = {
29
43
  ...env,
30
- [name]: value,
44
+ [key]: value,
31
45
  }
32
-
33
46
  // Apply environment variable updates
34
- const siteResult = await api.updateSite({
35
- siteId,
47
+ await api.updateSite({
48
+ siteId: siteData.id,
36
49
  body: {
37
50
  build_settings: {
38
51
  env: newEnv,
39
52
  },
40
53
  },
41
54
  })
55
+ return newEnv
56
+ }
42
57
 
43
- // Return new environment variables of site if using json flag
44
- if (options.json) {
45
- logJson(siteResult.build_settings.env)
46
- return false
58
+ /**
59
+ * Updates the env for a site configured with Envelope with a new key/value pair
60
+ * @returns {Promise<object>}
61
+ */
62
+ const setInEnvelope = async ({ api, key, siteData, value }) => {
63
+ const accountId = siteData.account_slug
64
+ const siteId = siteData.id
65
+ // fetch envelope env vars
66
+ const envelopeVariables = await api.getEnvVars({ accountId, siteId })
67
+ const scopes = ['builds', 'functions', 'runtime', 'post_processing']
68
+ const values = [{ context: 'all', value }]
69
+ // check if we need to create or update
70
+ const exists = envelopeVariables.some((envVar) => envVar.key === key)
71
+ const method = exists ? api.updateEnvVar : api.createEnvVars
72
+ const body = exists ? { key, scopes, values } : [{ key, scopes, values }]
73
+
74
+ try {
75
+ await method({ accountId, siteId, key, body })
76
+ } catch (error) {
77
+ throw error.json ? error.json.msg : error
47
78
  }
48
79
 
49
- log(`Set environment variable ${name}=${value} for site ${siteData.name}`)
80
+ const env = translateFromEnvelopeToMongo(envelopeVariables)
81
+ return {
82
+ ...env,
83
+ [key]: value,
84
+ }
50
85
  }
51
86
 
52
87
  /**
@@ -57,11 +92,11 @@ const envSet = async (name, value, options, command) => {
57
92
  const createEnvSetCommand = (program) =>
58
93
  program
59
94
  .command('env:set')
60
- .argument('<name>', 'Environment variable name')
95
+ .argument('<key>', 'Environment variable key')
61
96
  .argument('[value]', 'Value to set to', '')
62
97
  .description('Set value of environment variable')
63
- .action(async (name, value, options, command) => {
64
- await envSet(name, value, options, command)
98
+ .action(async (key, value, options, command) => {
99
+ await envSet(key, value, options, command)
65
100
  })
66
101
 
67
102
  module.exports = { createEnvSetCommand }
@@ -1,14 +1,14 @@
1
1
  // @ts-check
2
- const { log, logJson } = require('../../utils')
2
+ const { log, logJson, translateFromEnvelopeToMongo } = require('../../utils')
3
3
 
4
4
  /**
5
5
  * The env:unset command
6
- * @param {string} name Environment variable name
6
+ * @param {string} key Environment variable key
7
7
  * @param {import('commander').OptionValues} options
8
8
  * @param {import('../base-command').BaseCommand} command
9
9
  * @returns {Promise<boolean>}
10
10
  */
11
- const envUnset = async (name, options, command) => {
11
+ const envUnset = async (key, options, command) => {
12
12
  const { api, site } = command.netlify
13
13
  const siteId = site.id
14
14
 
@@ -19,6 +19,23 @@ const envUnset = async (name, options, command) => {
19
19
 
20
20
  const siteData = await api.getSite({ siteId })
21
21
 
22
+ const unsetInService = siteData.use_envelope ? unsetInEnvelope : unsetInMongo
23
+ const finalEnv = await unsetInService({ api, siteData, key })
24
+
25
+ // Return new environment variables of site if using json flag
26
+ if (options.json) {
27
+ logJson(finalEnv)
28
+ return false
29
+ }
30
+
31
+ log(`Unset environment variable ${key} for site ${siteData.name}`)
32
+ }
33
+
34
+ /**
35
+ * Deletes a given key from the env of a site record
36
+ * @returns {Promise<object>}
37
+ */
38
+ const unsetInMongo = async ({ api, key, siteData }) => {
22
39
  // Get current environment variables set in the UI
23
40
  const {
24
41
  build_settings: { env = {} },
@@ -27,11 +44,11 @@ const envUnset = async (name, options, command) => {
27
44
  const newEnv = env
28
45
 
29
46
  // Delete environment variable from current variables
30
- delete newEnv[name]
47
+ delete newEnv[key]
31
48
 
32
49
  // Apply environment variable updates
33
- const siteResult = await api.updateSite({
34
- siteId,
50
+ await api.updateSite({
51
+ siteId: siteData.id,
35
52
  body: {
36
53
  build_settings: {
37
54
  env: newEnv,
@@ -39,13 +56,36 @@ const envUnset = async (name, options, command) => {
39
56
  },
40
57
  })
41
58
 
42
- // Return new environment variables of site if using json flag
43
- if (options.json) {
44
- logJson(siteResult.build_settings.env)
45
- return false
59
+ return newEnv
60
+ }
61
+
62
+ /**
63
+ * Deletes a given key from the env of a site configured with Envelope
64
+ * @returns {Promise<object>}
65
+ */
66
+ const unsetInEnvelope = async ({ api, key, siteData }) => {
67
+ const accountId = siteData.account_slug
68
+ const siteId = siteData.id
69
+ // fetch envelope env vars
70
+ const envelopeVariables = await api.getEnvVars({ accountId, siteId })
71
+
72
+ // check if the given key exists
73
+ const env = translateFromEnvelopeToMongo(envelopeVariables)
74
+ if (!env[key]) {
75
+ // if not, no need to call delete; return early
76
+ return env
46
77
  }
47
78
 
48
- log(`Unset environment variable ${name} for site ${siteData.name}`)
79
+ // delete the given key
80
+ try {
81
+ await api.deleteEnvVar({ accountId, siteId, key })
82
+ } catch (error) {
83
+ throw error.json ? error.json.msg : error
84
+ }
85
+
86
+ delete env[key]
87
+
88
+ return env
49
89
  }
50
90
 
51
91
  /**
@@ -57,10 +97,10 @@ const createEnvUnsetCommand = (program) =>
57
97
  program
58
98
  .command('env:unset')
59
99
  .aliases(['env:delete', 'env:remove'])
60
- .argument('<name>', 'Environment variable name')
100
+ .argument('<key>', 'Environment variable key')
61
101
  .description('Unset an environment variable which removes it from the UI')
62
- .action(async (name, options, command) => {
63
- await envUnset(name, options, command)
102
+ .action(async (key, options, command) => {
103
+ await envUnset(key, options, command)
64
104
  })
65
105
 
66
106
  module.exports = { createEnvUnsetCommand }
@@ -11,7 +11,7 @@ const {
11
11
  const { NETLIFYDEVERR, chalk, error, log } = require('../../utils')
12
12
  const { openBrowser } = require('../../utils/open-browser')
13
13
 
14
- const { createPersistedQuery, ensureAppForSite } = OneGraphCliClient
14
+ const { ensureAppForSite, executeCreatePersistedQueryMutation } = OneGraphCliClient
15
15
 
16
16
  /**
17
17
  * Creates the `netlify graph:edit` command
@@ -50,12 +50,26 @@ const graphEdit = async (options, command) => {
50
50
  })
51
51
 
52
52
  const { branch } = gitRepoInfo()
53
- const persistedDoc = await createPersistedQuery(netlifyToken, {
54
- appId: siteId,
55
- description: 'Temporary snapshot of local queries',
56
- document: graphqlDocument,
57
- tags: ['netlify-cli', `session:${oneGraphSessionId}`, `git-branch:${branch}`],
58
- })
53
+ const persistedResult = await executeCreatePersistedQueryMutation(
54
+ {
55
+ nfToken: netlifyToken,
56
+ appId: siteId,
57
+ description: 'Temporary snapshot of local queries',
58
+ query: graphqlDocument,
59
+ tags: ['netlify-cli', `session:${oneGraphSessionId}`, `git-branch:${branch}`],
60
+ },
61
+ {
62
+ accessToken: netlifyToken,
63
+
64
+ siteId,
65
+ },
66
+ )
67
+
68
+ const persistedDoc =
69
+ persistedResult.data &&
70
+ persistedResult.data.oneGraph &&
71
+ persistedResult.data.oneGraph.createPersistedQuery &&
72
+ persistedResult.data.oneGraph.createPersistedQuery.persistedQuery
59
73
 
60
74
  const newMetadata = { docId: persistedDoc.id }
61
75
 
@@ -102,7 +102,7 @@ const graphOperations = async (options, command) => {
102
102
  * @param {import('../base-command').BaseCommand} program
103
103
  * @returns
104
104
  */
105
- const createGraphOperationCommand = (program) =>
105
+ const createGraphOperationsCommand = (program) =>
106
106
  program
107
107
  .command('graph:operations')
108
108
  .description('List all of the locally available operations')
@@ -110,4 +110,4 @@ const createGraphOperationCommand = (program) =>
110
110
  await graphOperations(options, command)
111
111
  })
112
112
 
113
- module.exports = { createGraphOperationCommand }
113
+ module.exports = { createGraphOperationsCommand }
@@ -3,7 +3,7 @@ const { createGraphConfigWriteCommand } = require('./graph-config-write')
3
3
  const { createGraphEditCommand } = require('./graph-edit')
4
4
  const { createGraphHandlerCommand } = require('./graph-handler')
5
5
  const { createGraphLibraryCommand } = require('./graph-library')
6
- const { createGraphOperationCommand } = require('./graph-operations')
6
+ const { createGraphOperationsCommand } = require('./graph-operations')
7
7
  const { createGraphPullCommand } = require('./graph-pull')
8
8
 
9
9
  /**
@@ -25,7 +25,7 @@ const createGraphCommand = (program) => {
25
25
  createGraphEditCommand(program)
26
26
  createGraphHandlerCommand(program)
27
27
  createGraphLibraryCommand(program)
28
- createGraphOperationCommand(program)
28
+ createGraphOperationsCommand(program)
29
29
  createGraphPullCommand(program)
30
30
 
31
31
  return program
@@ -128,8 +128,14 @@ const monitorCLISessionEvents = (input) => {
128
128
  const { events } = next
129
129
 
130
130
  if (events.length !== 0) {
131
- const ackIds = await onEvents(events)
132
- await OneGraphClient.ackCLISessionEvents({ appId, authToken: netlifyToken, sessionId, eventIds: ackIds })
131
+ let ackIds = []
132
+ try {
133
+ ackIds = await onEvents(events)
134
+ } catch (eventHandlerError) {
135
+ warn(`Error handling event: ${eventHandlerError}`)
136
+ } finally {
137
+ await OneGraphClient.ackCLISessionEvents({ appId, authToken: netlifyToken, sessionId, eventIds: ackIds })
138
+ }
133
139
  }
134
140
 
135
141
  await enabledServiceWatcher(netlifyToken, appId)
@@ -474,14 +480,31 @@ const persistNewOperationsDocForSession = async ({
474
480
  siteRoot,
475
481
  }) => {
476
482
  const { branch } = gitRepoInfo()
477
- const payload = {
478
- appId: siteId,
479
- description: 'Temporary snapshot of local queries',
480
- document: operationsDoc,
481
- tags: ['netlify-cli', `session:${oneGraphSessionId}`, `git-branch:${branch}`, `local-change`],
483
+ const persistedResult = await executeCreatePersistedQueryMutation(
484
+ {
485
+ nfToken: netlifyToken,
486
+ appId: siteId,
487
+ description: 'Temporary snapshot of local queries',
488
+ query: operationsDoc,
489
+ tags: ['netlify-cli', `session:${oneGraphSessionId}`, `git-branch:${branch}`, `local-change`],
490
+ },
491
+ {
492
+ accessToken: netlifyToken,
493
+ siteId,
494
+ },
495
+ )
496
+
497
+ const persistedDoc =
498
+ persistedResult.data &&
499
+ persistedResult.data.oneGraph &&
500
+ persistedResult.data.oneGraph.createPersistedQuery &&
501
+ persistedResult.data.oneGraph.createPersistedQuery.persistedQuery
502
+
503
+ if (!persistedDoc) {
504
+ warn(`Failed to create persisted query for editing, ${JSON.stringify(persistedResult, null, 2)}`)
482
505
  }
483
- const persistedDoc = await executeCreatePersistedQueryMutation(netlifyToken, payload)
484
- const newMetadata = await { docId: persistedDoc.id }
506
+
507
+ const newMetadata = { docId: persistedDoc.id }
485
508
  const result = await upsertMergeCLISessionMetadata({
486
509
  netlifyGraphConfig,
487
510
  netlifyToken,
@@ -697,7 +720,8 @@ const ensureCLISession = async ({ metadata, netlifyToken, site, state }) => {
697
720
 
698
721
  const OneGraphCliClient = {
699
722
  ackCLISessionEvents: OneGraphClient.ackCLISessionEvents,
700
- createPersistedQuery: executeCreatePersistedQueryMutation,
723
+ executeCreatePersistedQueryMutation: OneGraphClient.executeCreatePersistedQueryMutation,
724
+ executeCreateApiTokenMutation: OneGraphClient.executeCreateApiTokenMutation,
701
725
  fetchCliSessionEvents: OneGraphClient.fetchCliSessionEvents,
702
726
  ensureAppForSite,
703
727
  updateCLISessionMetadata,
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Translates a Mongo env into an Envelope env
3
+ * @param {object} env - The site's env as it exists in Mongo
4
+ * @returns {Array<object>} The array of Envelope env vars
5
+ */
6
+ const translateFromMongoToEnvelope = (env = {}) => {
7
+ const envVars = Object.entries(env).map(([key, value]) => ({
8
+ key,
9
+ scopes: ['builds', 'functions', 'runtime', 'post_processing'],
10
+ values: [
11
+ {
12
+ context: 'all',
13
+ value,
14
+ },
15
+ ],
16
+ }))
17
+
18
+ return envVars
19
+ }
20
+
21
+ /**
22
+ * Translates an Envelope env into a Mongo env
23
+ * @param {Array<object>} envVars - The array of Envelope env vars
24
+ * @returns {object} The env object as compatible with Mongo
25
+ */
26
+ const translateFromEnvelopeToMongo = (envVars = []) =>
27
+ envVars
28
+ .sort((left, right) => (left.key.toLowerCase() < right.key.toLowerCase() ? -1 : 1))
29
+ .reduce((acc, cur) => {
30
+ const envVar = cur.values.find((val) => ['dev', 'all'].includes(val.context))
31
+ if (envVar && envVar.value) {
32
+ return {
33
+ ...acc,
34
+ [cur.key]: envVar.value,
35
+ }
36
+ }
37
+ return acc
38
+ }, {})
39
+
40
+ module.exports = {
41
+ translateFromMongoToEnvelope,
42
+ translateFromEnvelopeToMongo,
43
+ }
@@ -4,6 +4,7 @@ const createStreamPromise = require('./create-stream-promise')
4
4
  const deploy = require('./deploy')
5
5
  const detectServerSettings = require('./detect-server-settings')
6
6
  const dev = require('./dev')
7
+ const env = require('./env')
7
8
  const execa = require('./execa')
8
9
  const functions = require('./functions')
9
10
  const getGlobalConfig = require('./get-global-config')
@@ -24,6 +25,7 @@ module.exports = {
24
25
  ...deploy,
25
26
  ...detectServerSettings,
26
27
  ...dev,
28
+ ...env,
27
29
  ...functions,
28
30
  ...getRepoData,
29
31
  ...ghAuth,