netlify-cli 9.4.2 → 9.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "9.4.2",
3
+ "version": "9.6.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "9.4.2",
9
+ "version": "9.6.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
- "@netlify/build": "^26.3.1",
14
- "@netlify/config": "^17.0.8",
13
+ "@netlify/build": "^26.3.2",
14
+ "@netlify/config": "^17.0.9",
15
15
  "@netlify/framework-info": "^9.0.0",
16
16
  "@netlify/local-functions-proxy": "^1.1.1",
17
17
  "@netlify/plugin-edge-handlers": "^3.0.6",
18
- "@netlify/plugins-list": "^6.10.2",
18
+ "@netlify/plugins-list": "^6.11.0",
19
19
  "@netlify/routing-local-proxy": "^0.34.1",
20
- "@netlify/zip-it-and-ship-it": "^5.7.4",
20
+ "@netlify/zip-it-and-ship-it": "^5.7.5",
21
21
  "@octokit/rest": "^18.0.0",
22
22
  "@sindresorhus/slugify": "^1.1.0",
23
23
  "ansi-escapes": "^5.0.0",
@@ -81,7 +81,7 @@
81
81
  "minimist": "^1.2.5",
82
82
  "multiparty": "^4.2.1",
83
83
  "netlify": "^11.0.0",
84
- "netlify-headers-parser": "^6.0.1",
84
+ "netlify-headers-parser": "^6.0.2",
85
85
  "netlify-onegraph-internal": "0.0.50",
86
86
  "netlify-redirect-parser": "^13.0.2",
87
87
  "netlify-redirector": "^0.2.1",
@@ -2358,9 +2358,9 @@
2358
2358
  }
2359
2359
  },
2360
2360
  "node_modules/@netlify/build": {
2361
- "version": "26.3.1",
2362
- "resolved": "https://registry.npmjs.org/@netlify/build/-/build-26.3.1.tgz",
2363
- "integrity": "sha512-8+Npnnd3UWQYkV4IhJdI39a24YiQaeDk4arkH712l/d42M65bZiHX59Zm7smXpGm9o2VEXM+z5dTlk7fMEw1bg==",
2361
+ "version": "26.3.2",
2362
+ "resolved": "https://registry.npmjs.org/@netlify/build/-/build-26.3.2.tgz",
2363
+ "integrity": "sha512-EMgdZKf6Xa9ZQEdDEHl5s2Kj9xQw69mRPI4f7o5eVltatquxxUSL+pBnSqHauaEsGfPXlP8ymadTGTxaF0DxUA==",
2364
2364
  "dependencies": {
2365
2365
  "@bugsnag/js": "^7.0.0",
2366
2366
  "@netlify/cache-utils": "^4.0.0",
@@ -2370,7 +2370,7 @@
2370
2370
  "@netlify/plugin-edge-handlers": "^3.0.6",
2371
2371
  "@netlify/plugins-list": "^6.10.2",
2372
2372
  "@netlify/run-utils": "^4.0.0",
2373
- "@netlify/zip-it-and-ship-it": "5.7.4",
2373
+ "@netlify/zip-it-and-ship-it": "5.7.5",
2374
2374
  "@sindresorhus/slugify": "^2.0.0",
2375
2375
  "@types/node": "^16.0.0",
2376
2376
  "ansi-escapes": "^5.0.0",
@@ -3110,9 +3110,9 @@
3110
3110
  }
3111
3111
  },
3112
3112
  "node_modules/@netlify/config": {
3113
- "version": "17.0.8",
3114
- "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.8.tgz",
3115
- "integrity": "sha512-8yD5ZLpGNeFm7hiaAXv8vgi18ieQfFPw9PrO13QEiuIozyHkBR6NR1/A0FdHtPZoPD8SPBsoVm0/XmYBhBOnKA==",
3113
+ "version": "17.0.9",
3114
+ "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.9.tgz",
3115
+ "integrity": "sha512-qd7q2aiZVyO2Mou3ltR9sgSFckMU8E+YBwHOasyleH6EJjRIV3uuT/K4e3SSwB6k+f26MOHCjz+87ecN04/26A==",
3116
3116
  "dependencies": {
3117
3117
  "chalk": "^5.0.0",
3118
3118
  "cron-parser": "^4.1.0",
@@ -3128,7 +3128,7 @@
3128
3128
  "js-yaml": "^4.0.0",
3129
3129
  "map-obj": "^5.0.0",
3130
3130
  "netlify": "^11.0.0",
3131
- "netlify-headers-parser": "^6.0.1",
3131
+ "netlify-headers-parser": "^6.0.2",
3132
3132
  "netlify-redirect-parser": "^13.0.2",
3133
3133
  "omit.js": "^2.0.2",
3134
3134
  "p-locate": "^6.0.0",
@@ -3183,18 +3183,18 @@
3183
3183
  }
3184
3184
  },
3185
3185
  "node_modules/@netlify/config/node_modules/execa": {
3186
- "version": "6.0.0",
3187
- "resolved": "https://registry.npmjs.org/execa/-/execa-6.0.0.tgz",
3188
- "integrity": "sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q==",
3186
+ "version": "6.1.0",
3187
+ "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz",
3188
+ "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==",
3189
3189
  "dependencies": {
3190
3190
  "cross-spawn": "^7.0.3",
3191
3191
  "get-stream": "^6.0.1",
3192
3192
  "human-signals": "^3.0.1",
3193
3193
  "is-stream": "^3.0.0",
3194
3194
  "merge-stream": "^2.0.0",
3195
- "npm-run-path": "^5.0.1",
3195
+ "npm-run-path": "^5.1.0",
3196
3196
  "onetime": "^6.0.0",
3197
- "signal-exit": "^3.0.5",
3197
+ "signal-exit": "^3.0.7",
3198
3198
  "strip-final-newline": "^3.0.0"
3199
3199
  },
3200
3200
  "engines": {
@@ -3645,6 +3645,70 @@
3645
3645
  "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
3646
3646
  }
3647
3647
  },
3648
+ "node_modules/@netlify/functions-utils/node_modules/@babel/parser": {
3649
+ "version": "7.16.8",
3650
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
3651
+ "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
3652
+ "bin": {
3653
+ "parser": "bin/babel-parser.js"
3654
+ },
3655
+ "engines": {
3656
+ "node": ">=6.0.0"
3657
+ }
3658
+ },
3659
+ "node_modules/@netlify/functions-utils/node_modules/@netlify/zip-it-and-ship-it": {
3660
+ "version": "5.7.4",
3661
+ "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.4.tgz",
3662
+ "integrity": "sha512-HMPf4pX561H5d59h8Y20Qjzo+5BbFkvpnTSWnzdSjQR85dhT8CVKeX9NdLKoKHG82+M75ErfOCY5Db7VsgKAWA==",
3663
+ "dependencies": {
3664
+ "@babel/parser": "7.16.8",
3665
+ "@netlify/esbuild": "^0.13.6",
3666
+ "@vercel/nft": "^0.17.0",
3667
+ "archiver": "^5.3.0",
3668
+ "common-path-prefix": "^3.0.0",
3669
+ "cp-file": "^9.0.0",
3670
+ "del": "^6.0.0",
3671
+ "elf-cam": "^0.1.1",
3672
+ "end-of-stream": "^1.4.4",
3673
+ "es-module-lexer": "^0.9.0",
3674
+ "execa": "^5.0.0",
3675
+ "filter-obj": "^2.0.1",
3676
+ "find-up": "^5.0.0",
3677
+ "glob": "^7.1.6",
3678
+ "is-builtin-module": "^3.1.0",
3679
+ "junk": "^3.1.0",
3680
+ "locate-path": "^6.0.0",
3681
+ "merge-options": "^3.0.4",
3682
+ "minimatch": "^3.0.4",
3683
+ "p-map": "^4.0.0",
3684
+ "path-exists": "^4.0.0",
3685
+ "pkg-dir": "^5.0.0",
3686
+ "precinct": "^8.2.0",
3687
+ "read-package-json-fast": "^2.0.2",
3688
+ "require-package-name": "^2.0.1",
3689
+ "resolve": "^2.0.0-next.1",
3690
+ "semver": "^7.0.0",
3691
+ "tmp-promise": "^3.0.2",
3692
+ "toml": "^3.0.0",
3693
+ "typescript": "^4.6.0-beta",
3694
+ "unixify": "^1.0.0",
3695
+ "yargs": "^16.0.0"
3696
+ },
3697
+ "bin": {
3698
+ "zip-it-and-ship-it": "dist/bin.js"
3699
+ },
3700
+ "engines": {
3701
+ "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
3702
+ }
3703
+ },
3704
+ "node_modules/@netlify/functions-utils/node_modules/@netlify/zip-it-and-ship-it/node_modules/path-exists": {
3705
+ "version": "4.0.0",
3706
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
3707
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
3708
+ "engines": {
3709
+ "node": ">=8"
3710
+ }
3711
+ },
3648
3712
  "node_modules/@netlify/functions-utils/node_modules/path-exists": {
3649
3713
  "version": "5.0.0",
3650
3714
  "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
@@ -3653,6 +3717,35 @@
3653
3717
  "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
3654
3718
  }
3655
3719
  },
3720
+ "node_modules/@netlify/functions-utils/node_modules/typescript": {
3721
+ "version": "4.6.0-dev.20220211",
3722
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20220211.tgz",
3723
+ "integrity": "sha512-wMVJ7QGajX2OXpGrX8cphiTsyab79JS88F00azUMgO65ooUFgyFFQaXn2zOO8h8RluD6kHWzCM3WTa0Tc0Ui+g==",
3724
+ "bin": {
3725
+ "tsc": "bin/tsc",
3726
+ "tsserver": "bin/tsserver"
3727
+ },
3728
+ "engines": {
3729
+ "node": ">=4.2.0"
3730
+ }
3731
+ },
3732
+ "node_modules/@netlify/functions-utils/node_modules/yargs": {
3733
+ "version": "16.2.0",
3734
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
3735
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
3736
+ "dependencies": {
3737
+ "cliui": "^7.0.2",
3738
+ "escalade": "^3.1.1",
3739
+ "get-caller-file": "^2.0.5",
3740
+ "require-directory": "^2.1.1",
3741
+ "string-width": "^4.2.0",
3742
+ "y18n": "^5.0.5",
3743
+ "yargs-parser": "^20.2.2"
3744
+ },
3745
+ "engines": {
3746
+ "node": ">=10"
3747
+ }
3748
+ },
3656
3749
  "node_modules/@netlify/git-utils": {
3657
3750
  "version": "4.1.1",
3658
3751
  "resolved": "https://registry.npmjs.org/@netlify/git-utils/-/git-utils-4.1.1.tgz",
@@ -4039,9 +4132,9 @@
4039
4132
  }
4040
4133
  },
4041
4134
  "node_modules/@netlify/plugins-list": {
4042
- "version": "6.10.2",
4043
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.10.2.tgz",
4044
- "integrity": "sha512-Agkt26O+bBQq3iXq7tSnDqWn+Ew3M7ImtoBNy/KI2KhNGaW1Mu31F9sIJqxvTUjVjBfklSI/L9M5GBWVAgk08A==",
4135
+ "version": "6.11.0",
4136
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.11.0.tgz",
4137
+ "integrity": "sha512-b6+htKVooVnUPbq2zlCPUcWJSvR18a20cl1W3MS3EThEbXM/CCQWcCEqjwk+Q5VCH2hoJoaHlLhO/lIHpwn8Ig==",
4045
4138
  "engines": {
4046
4139
  "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
4047
4140
  }
@@ -4208,9 +4301,9 @@
4208
4301
  }
4209
4302
  },
4210
4303
  "node_modules/@netlify/zip-it-and-ship-it": {
4211
- "version": "5.7.4",
4212
- "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.4.tgz",
4213
- "integrity": "sha512-HMPf4pX561H5d59h8Y20Qjzo+5BbFkvpnTSWnzdSjQR85dhT8CVKeX9NdLKoKHG82+M75ErfOCY5Db7VsgKAWA==",
4304
+ "version": "5.7.5",
4305
+ "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.5.tgz",
4306
+ "integrity": "sha512-v3buWIrlm0+lmDwI2qHRU4t7zR3LtfU0T2JYUPGIz0D8ezsnHihj0wbBf3lMZnQmHwrqQURQYL9nQTrpwH3YoA==",
4214
4307
  "dependencies": {
4215
4308
  "@babel/parser": "7.16.8",
4216
4309
  "@netlify/esbuild": "^0.13.6",
@@ -4230,7 +4323,7 @@
4230
4323
  "junk": "^3.1.0",
4231
4324
  "locate-path": "^6.0.0",
4232
4325
  "merge-options": "^3.0.4",
4233
- "minimatch": "^3.0.4",
4326
+ "minimatch": "^4.0.0",
4234
4327
  "p-map": "^4.0.0",
4235
4328
  "path-exists": "^4.0.0",
4236
4329
  "pkg-dir": "^5.0.0",
@@ -4241,7 +4334,6 @@
4241
4334
  "semver": "^7.0.0",
4242
4335
  "tmp-promise": "^3.0.2",
4243
4336
  "toml": "^3.0.0",
4244
- "typescript": "^4.6.0-beta",
4245
4337
  "unixify": "^1.0.0",
4246
4338
  "yargs": "^16.0.0"
4247
4339
  },
@@ -4263,16 +4355,15 @@
4263
4355
  "node": ">=6.0.0"
4264
4356
  }
4265
4357
  },
4266
- "node_modules/@netlify/zip-it-and-ship-it/node_modules/typescript": {
4267
- "version": "4.6.0-dev.20220208",
4268
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20220208.tgz",
4269
- "integrity": "sha512-2yfS4UYfkLnpVkjs2IEl7T++ojqdPiV5S/akYv1trTf50TZHmGnyhF5Umo2iLWZEuSDmBCe2K52x5qzBXDi+mQ==",
4270
- "bin": {
4271
- "tsc": "bin/tsc",
4272
- "tsserver": "bin/tsserver"
4358
+ "node_modules/@netlify/zip-it-and-ship-it/node_modules/minimatch": {
4359
+ "version": "4.1.1",
4360
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.1.1.tgz",
4361
+ "integrity": "sha512-9ObkVPP8aM2KWHw1RMAaOoEzHjcqzE1dmEQHAOq9ySRhvVMru1VKqniUs/g6Us4KSwXKk0+uLko6caynDcWEWQ==",
4362
+ "dependencies": {
4363
+ "brace-expansion": "^1.1.7"
4273
4364
  },
4274
4365
  "engines": {
4275
- "node": ">=4.2.0"
4366
+ "node": ">=10"
4276
4367
  }
4277
4368
  },
4278
4369
  "node_modules/@netlify/zip-it-and-ship-it/node_modules/yargs": {
@@ -16674,20 +16765,61 @@
16674
16765
  }
16675
16766
  },
16676
16767
  "node_modules/netlify-headers-parser": {
16677
- "version": "6.0.1",
16678
- "resolved": "https://registry.npmjs.org/netlify-headers-parser/-/netlify-headers-parser-6.0.1.tgz",
16679
- "integrity": "sha512-4S1WBAe7M5QwB4OZ1rq4bw2hEwhP1G4nCk2OCD7zkTQgVoWUGzgjmn2vuTaDPuoj0s26sfTLD4Es+cPHN9m/+A==",
16768
+ "version": "6.0.2",
16769
+ "resolved": "https://registry.npmjs.org/netlify-headers-parser/-/netlify-headers-parser-6.0.2.tgz",
16770
+ "integrity": "sha512-ahDNi7R+Io4iMylyFrOfRUcBUELrXCT0hNVdqPKTHhH917NHiDCH69f6IhhqbzSaZ2/zGFPBrxA3FzJ48yXs3Q==",
16680
16771
  "dependencies": {
16681
- "escape-string-regexp": "^4.0.0",
16682
- "is-plain-obj": "^3.0.0",
16683
- "map-obj": "^4.2.1",
16684
- "path-exists": "^4.0.0",
16772
+ "escape-string-regexp": "^5.0.0",
16773
+ "is-plain-obj": "^4.0.0",
16774
+ "map-obj": "^5.0.0",
16775
+ "path-exists": "^5.0.0",
16685
16776
  "toml": "^3.0.0"
16686
16777
  },
16687
16778
  "engines": {
16688
16779
  "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
16689
16780
  }
16690
16781
  },
16782
+ "node_modules/netlify-headers-parser/node_modules/escape-string-regexp": {
16783
+ "version": "5.0.0",
16784
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
16785
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
16786
+ "engines": {
16787
+ "node": ">=12"
16788
+ },
16789
+ "funding": {
16790
+ "url": "https://github.com/sponsors/sindresorhus"
16791
+ }
16792
+ },
16793
+ "node_modules/netlify-headers-parser/node_modules/is-plain-obj": {
16794
+ "version": "4.0.0",
16795
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.0.0.tgz",
16796
+ "integrity": "sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw==",
16797
+ "engines": {
16798
+ "node": ">=12"
16799
+ },
16800
+ "funding": {
16801
+ "url": "https://github.com/sponsors/sindresorhus"
16802
+ }
16803
+ },
16804
+ "node_modules/netlify-headers-parser/node_modules/map-obj": {
16805
+ "version": "5.0.0",
16806
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz",
16807
+ "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==",
16808
+ "engines": {
16809
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
16810
+ },
16811
+ "funding": {
16812
+ "url": "https://github.com/sponsors/sindresorhus"
16813
+ }
16814
+ },
16815
+ "node_modules/netlify-headers-parser/node_modules/path-exists": {
16816
+ "version": "5.0.0",
16817
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
16818
+ "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
16819
+ "engines": {
16820
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
16821
+ }
16822
+ },
16691
16823
  "node_modules/netlify-onegraph-internal": {
16692
16824
  "version": "0.0.50",
16693
16825
  "resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.0.50.tgz",
@@ -25364,9 +25496,9 @@
25364
25496
  }
25365
25497
  },
25366
25498
  "@netlify/build": {
25367
- "version": "26.3.1",
25368
- "resolved": "https://registry.npmjs.org/@netlify/build/-/build-26.3.1.tgz",
25369
- "integrity": "sha512-8+Npnnd3UWQYkV4IhJdI39a24YiQaeDk4arkH712l/d42M65bZiHX59Zm7smXpGm9o2VEXM+z5dTlk7fMEw1bg==",
25499
+ "version": "26.3.2",
25500
+ "resolved": "https://registry.npmjs.org/@netlify/build/-/build-26.3.2.tgz",
25501
+ "integrity": "sha512-EMgdZKf6Xa9ZQEdDEHl5s2Kj9xQw69mRPI4f7o5eVltatquxxUSL+pBnSqHauaEsGfPXlP8ymadTGTxaF0DxUA==",
25370
25502
  "requires": {
25371
25503
  "@bugsnag/js": "^7.0.0",
25372
25504
  "@netlify/cache-utils": "^4.0.0",
@@ -25376,7 +25508,7 @@
25376
25508
  "@netlify/plugin-edge-handlers": "^3.0.6",
25377
25509
  "@netlify/plugins-list": "^6.10.2",
25378
25510
  "@netlify/run-utils": "^4.0.0",
25379
- "@netlify/zip-it-and-ship-it": "5.7.4",
25511
+ "@netlify/zip-it-and-ship-it": "5.7.5",
25380
25512
  "@sindresorhus/slugify": "^2.0.0",
25381
25513
  "@types/node": "^16.0.0",
25382
25514
  "ansi-escapes": "^5.0.0",
@@ -25829,9 +25961,9 @@
25829
25961
  }
25830
25962
  },
25831
25963
  "@netlify/config": {
25832
- "version": "17.0.8",
25833
- "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.8.tgz",
25834
- "integrity": "sha512-8yD5ZLpGNeFm7hiaAXv8vgi18ieQfFPw9PrO13QEiuIozyHkBR6NR1/A0FdHtPZoPD8SPBsoVm0/XmYBhBOnKA==",
25964
+ "version": "17.0.9",
25965
+ "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.9.tgz",
25966
+ "integrity": "sha512-qd7q2aiZVyO2Mou3ltR9sgSFckMU8E+YBwHOasyleH6EJjRIV3uuT/K4e3SSwB6k+f26MOHCjz+87ecN04/26A==",
25835
25967
  "requires": {
25836
25968
  "chalk": "^5.0.0",
25837
25969
  "cron-parser": "^4.1.0",
@@ -25847,7 +25979,7 @@
25847
25979
  "js-yaml": "^4.0.0",
25848
25980
  "map-obj": "^5.0.0",
25849
25981
  "netlify": "^11.0.0",
25850
- "netlify-headers-parser": "^6.0.1",
25982
+ "netlify-headers-parser": "^6.0.2",
25851
25983
  "netlify-redirect-parser": "^13.0.2",
25852
25984
  "omit.js": "^2.0.2",
25853
25985
  "p-locate": "^6.0.0",
@@ -25878,18 +26010,18 @@
25878
26010
  "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="
25879
26011
  },
25880
26012
  "execa": {
25881
- "version": "6.0.0",
25882
- "resolved": "https://registry.npmjs.org/execa/-/execa-6.0.0.tgz",
25883
- "integrity": "sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q==",
26013
+ "version": "6.1.0",
26014
+ "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz",
26015
+ "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==",
25884
26016
  "requires": {
25885
26017
  "cross-spawn": "^7.0.3",
25886
26018
  "get-stream": "^6.0.1",
25887
26019
  "human-signals": "^3.0.1",
25888
26020
  "is-stream": "^3.0.0",
25889
26021
  "merge-stream": "^2.0.0",
25890
- "npm-run-path": "^5.0.1",
26022
+ "npm-run-path": "^5.1.0",
25891
26023
  "onetime": "^6.0.0",
25892
- "signal-exit": "^3.0.5",
26024
+ "signal-exit": "^3.0.7",
25893
26025
  "strip-final-newline": "^3.0.0"
25894
26026
  }
25895
26027
  },
@@ -26165,10 +26297,80 @@
26165
26297
  "path-exists": "^5.0.0"
26166
26298
  },
26167
26299
  "dependencies": {
26300
+ "@babel/parser": {
26301
+ "version": "7.16.8",
26302
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
26303
+ "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw=="
26304
+ },
26305
+ "@netlify/zip-it-and-ship-it": {
26306
+ "version": "5.7.4",
26307
+ "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.4.tgz",
26308
+ "integrity": "sha512-HMPf4pX561H5d59h8Y20Qjzo+5BbFkvpnTSWnzdSjQR85dhT8CVKeX9NdLKoKHG82+M75ErfOCY5Db7VsgKAWA==",
26309
+ "requires": {
26310
+ "@babel/parser": "7.16.8",
26311
+ "@netlify/esbuild": "^0.13.6",
26312
+ "@vercel/nft": "^0.17.0",
26313
+ "archiver": "^5.3.0",
26314
+ "common-path-prefix": "^3.0.0",
26315
+ "cp-file": "^9.0.0",
26316
+ "del": "^6.0.0",
26317
+ "elf-cam": "^0.1.1",
26318
+ "end-of-stream": "^1.4.4",
26319
+ "es-module-lexer": "^0.9.0",
26320
+ "execa": "^5.0.0",
26321
+ "filter-obj": "^2.0.1",
26322
+ "find-up": "^5.0.0",
26323
+ "glob": "^7.1.6",
26324
+ "is-builtin-module": "^3.1.0",
26325
+ "junk": "^3.1.0",
26326
+ "locate-path": "^6.0.0",
26327
+ "merge-options": "^3.0.4",
26328
+ "minimatch": "^3.0.4",
26329
+ "p-map": "^4.0.0",
26330
+ "path-exists": "^4.0.0",
26331
+ "pkg-dir": "^5.0.0",
26332
+ "precinct": "^8.2.0",
26333
+ "read-package-json-fast": "^2.0.2",
26334
+ "require-package-name": "^2.0.1",
26335
+ "resolve": "^2.0.0-next.1",
26336
+ "semver": "^7.0.0",
26337
+ "tmp-promise": "^3.0.2",
26338
+ "toml": "^3.0.0",
26339
+ "typescript": "^4.6.0-beta",
26340
+ "unixify": "^1.0.0",
26341
+ "yargs": "^16.0.0"
26342
+ },
26343
+ "dependencies": {
26344
+ "path-exists": {
26345
+ "version": "4.0.0",
26346
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
26347
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
26348
+ }
26349
+ }
26350
+ },
26168
26351
  "path-exists": {
26169
26352
  "version": "5.0.0",
26170
26353
  "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
26171
26354
  "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="
26355
+ },
26356
+ "typescript": {
26357
+ "version": "4.6.0-dev.20220211",
26358
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20220211.tgz",
26359
+ "integrity": "sha512-wMVJ7QGajX2OXpGrX8cphiTsyab79JS88F00azUMgO65ooUFgyFFQaXn2zOO8h8RluD6kHWzCM3WTa0Tc0Ui+g=="
26360
+ },
26361
+ "yargs": {
26362
+ "version": "16.2.0",
26363
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
26364
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
26365
+ "requires": {
26366
+ "cliui": "^7.0.2",
26367
+ "escalade": "^3.1.1",
26368
+ "get-caller-file": "^2.0.5",
26369
+ "require-directory": "^2.1.1",
26370
+ "string-width": "^4.2.0",
26371
+ "y18n": "^5.0.5",
26372
+ "yargs-parser": "^20.2.2"
26373
+ }
26172
26374
  }
26173
26375
  }
26174
26376
  },
@@ -26384,9 +26586,9 @@
26384
26586
  }
26385
26587
  },
26386
26588
  "@netlify/plugins-list": {
26387
- "version": "6.10.2",
26388
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.10.2.tgz",
26389
- "integrity": "sha512-Agkt26O+bBQq3iXq7tSnDqWn+Ew3M7ImtoBNy/KI2KhNGaW1Mu31F9sIJqxvTUjVjBfklSI/L9M5GBWVAgk08A=="
26589
+ "version": "6.11.0",
26590
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.11.0.tgz",
26591
+ "integrity": "sha512-b6+htKVooVnUPbq2zlCPUcWJSvR18a20cl1W3MS3EThEbXM/CCQWcCEqjwk+Q5VCH2hoJoaHlLhO/lIHpwn8Ig=="
26390
26592
  },
26391
26593
  "@netlify/routing-local-proxy": {
26392
26594
  "version": "0.34.1",
@@ -26486,9 +26688,9 @@
26486
26688
  }
26487
26689
  },
26488
26690
  "@netlify/zip-it-and-ship-it": {
26489
- "version": "5.7.4",
26490
- "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.4.tgz",
26491
- "integrity": "sha512-HMPf4pX561H5d59h8Y20Qjzo+5BbFkvpnTSWnzdSjQR85dhT8CVKeX9NdLKoKHG82+M75ErfOCY5Db7VsgKAWA==",
26691
+ "version": "5.7.5",
26692
+ "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.5.tgz",
26693
+ "integrity": "sha512-v3buWIrlm0+lmDwI2qHRU4t7zR3LtfU0T2JYUPGIz0D8ezsnHihj0wbBf3lMZnQmHwrqQURQYL9nQTrpwH3YoA==",
26492
26694
  "requires": {
26493
26695
  "@babel/parser": "7.16.8",
26494
26696
  "@netlify/esbuild": "^0.13.6",
@@ -26508,7 +26710,7 @@
26508
26710
  "junk": "^3.1.0",
26509
26711
  "locate-path": "^6.0.0",
26510
26712
  "merge-options": "^3.0.4",
26511
- "minimatch": "^3.0.4",
26713
+ "minimatch": "^4.0.0",
26512
26714
  "p-map": "^4.0.0",
26513
26715
  "path-exists": "^4.0.0",
26514
26716
  "pkg-dir": "^5.0.0",
@@ -26519,7 +26721,6 @@
26519
26721
  "semver": "^7.0.0",
26520
26722
  "tmp-promise": "^3.0.2",
26521
26723
  "toml": "^3.0.0",
26522
- "typescript": "^4.6.0-beta",
26523
26724
  "unixify": "^1.0.0",
26524
26725
  "yargs": "^16.0.0"
26525
26726
  },
@@ -26529,10 +26730,13 @@
26529
26730
  "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
26530
26731
  "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw=="
26531
26732
  },
26532
- "typescript": {
26533
- "version": "4.6.0-dev.20220208",
26534
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20220208.tgz",
26535
- "integrity": "sha512-2yfS4UYfkLnpVkjs2IEl7T++ojqdPiV5S/akYv1trTf50TZHmGnyhF5Umo2iLWZEuSDmBCe2K52x5qzBXDi+mQ=="
26733
+ "minimatch": {
26734
+ "version": "4.1.1",
26735
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.1.1.tgz",
26736
+ "integrity": "sha512-9ObkVPP8aM2KWHw1RMAaOoEzHjcqzE1dmEQHAOq9ySRhvVMru1VKqniUs/g6Us4KSwXKk0+uLko6caynDcWEWQ==",
26737
+ "requires": {
26738
+ "brace-expansion": "^1.1.7"
26739
+ }
26536
26740
  },
26537
26741
  "yargs": {
26538
26742
  "version": "16.2.0",
@@ -36025,15 +36229,37 @@
36025
36229
  }
36026
36230
  },
36027
36231
  "netlify-headers-parser": {
36028
- "version": "6.0.1",
36029
- "resolved": "https://registry.npmjs.org/netlify-headers-parser/-/netlify-headers-parser-6.0.1.tgz",
36030
- "integrity": "sha512-4S1WBAe7M5QwB4OZ1rq4bw2hEwhP1G4nCk2OCD7zkTQgVoWUGzgjmn2vuTaDPuoj0s26sfTLD4Es+cPHN9m/+A==",
36232
+ "version": "6.0.2",
36233
+ "resolved": "https://registry.npmjs.org/netlify-headers-parser/-/netlify-headers-parser-6.0.2.tgz",
36234
+ "integrity": "sha512-ahDNi7R+Io4iMylyFrOfRUcBUELrXCT0hNVdqPKTHhH917NHiDCH69f6IhhqbzSaZ2/zGFPBrxA3FzJ48yXs3Q==",
36031
36235
  "requires": {
36032
- "escape-string-regexp": "^4.0.0",
36033
- "is-plain-obj": "^3.0.0",
36034
- "map-obj": "^4.2.1",
36035
- "path-exists": "^4.0.0",
36236
+ "escape-string-regexp": "^5.0.0",
36237
+ "is-plain-obj": "^4.0.0",
36238
+ "map-obj": "^5.0.0",
36239
+ "path-exists": "^5.0.0",
36036
36240
  "toml": "^3.0.0"
36241
+ },
36242
+ "dependencies": {
36243
+ "escape-string-regexp": {
36244
+ "version": "5.0.0",
36245
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
36246
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="
36247
+ },
36248
+ "is-plain-obj": {
36249
+ "version": "4.0.0",
36250
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.0.0.tgz",
36251
+ "integrity": "sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw=="
36252
+ },
36253
+ "map-obj": {
36254
+ "version": "5.0.0",
36255
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz",
36256
+ "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA=="
36257
+ },
36258
+ "path-exists": {
36259
+ "version": "5.0.0",
36260
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
36261
+ "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="
36262
+ }
36037
36263
  }
36038
36264
  },
36039
36265
  "netlify-onegraph-internal": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "9.4.2",
4
+ "version": "9.6.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
@@ -199,14 +199,14 @@
199
199
  "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\" \"!site/package-lock.json\" \"!.github/**/*.md\""
200
200
  },
201
201
  "dependencies": {
202
- "@netlify/build": "^26.3.1",
203
- "@netlify/config": "^17.0.8",
202
+ "@netlify/build": "^26.3.2",
203
+ "@netlify/config": "^17.0.9",
204
204
  "@netlify/framework-info": "^9.0.0",
205
205
  "@netlify/local-functions-proxy": "^1.1.1",
206
206
  "@netlify/plugin-edge-handlers": "^3.0.6",
207
- "@netlify/plugins-list": "^6.10.2",
207
+ "@netlify/plugins-list": "^6.11.0",
208
208
  "@netlify/routing-local-proxy": "^0.34.1",
209
- "@netlify/zip-it-and-ship-it": "^5.7.4",
209
+ "@netlify/zip-it-and-ship-it": "^5.7.5",
210
210
  "@octokit/rest": "^18.0.0",
211
211
  "@sindresorhus/slugify": "^1.1.0",
212
212
  "ansi-escapes": "^5.0.0",
@@ -270,7 +270,7 @@
270
270
  "minimist": "^1.2.5",
271
271
  "multiparty": "^4.2.1",
272
272
  "netlify": "^11.0.0",
273
- "netlify-headers-parser": "^6.0.1",
273
+ "netlify-headers-parser": "^6.0.2",
274
274
  "netlify-onegraph-internal": "0.0.50",
275
275
  "netlify-redirect-parser": "^13.0.2",
276
276
  "netlify-redirector": "^0.2.1",
@@ -1,4 +1,5 @@
1
1
  // @ts-check
2
+ const events = require('events')
2
3
  const process = require('process')
3
4
  const { format } = require('util')
4
5
 
@@ -28,6 +29,7 @@ const {
28
29
  pollForToken,
29
30
  sortOptions,
30
31
  track,
32
+ watchDebounced,
31
33
  } = require('../utils')
32
34
 
33
35
  // Netlify CLI client id. Lives in bot@netlify.com
@@ -119,6 +121,11 @@ class BaseCommand extends Command {
119
121
  await this.init(actionCommand)
120
122
  debug(`${name}:preAction`)('end')
121
123
  })
124
+ .hook('postAction', async () => {
125
+ if (this.configWatcherHandle) {
126
+ await this.configWatcherHandle.close()
127
+ }
128
+ })
122
129
  )
123
130
  }
124
131
 
@@ -430,6 +437,24 @@ class BaseCommand extends Command {
430
437
  const globalConfig = await getGlobalConfig()
431
438
  const { NetlifyAPI } = await jsClient
432
439
 
440
+ const configWatcher = new events.EventEmitter()
441
+
442
+ // Only set up a watcher if we know the config path.
443
+ if (configPath) {
444
+ const configWatcherHandle = await watchDebounced(configPath, {
445
+ depth: 1,
446
+ onChange: async () => {
447
+ const { config: newConfig } = await actionCommand.getConfig({ cwd, state, token, ...apiUrlOpts })
448
+
449
+ const normalizedNewConfig = normalizeConfig(newConfig)
450
+ configWatcher.emit('change', normalizedNewConfig)
451
+ },
452
+ })
453
+
454
+ // chokidar handler
455
+ this.configWatcherHandle = configWatcherHandle
456
+ }
457
+
433
458
  actionCommand.netlify = {
434
459
  // api methods
435
460
  api: new NetlifyAPI(token || '', apiOpts),
@@ -455,6 +480,8 @@ class BaseCommand extends Command {
455
480
  globalConfig,
456
481
  // state of current site dir
457
482
  state,
483
+ // netlify.toml file watcher
484
+ configWatcher,
458
485
  }
459
486
  debug(`${this.name()}:init`)('end')
460
487
  }
@@ -14,6 +14,7 @@ const { startFunctionsServer } = require('../../lib/functions/server')
14
14
  const {
15
15
  OneGraphCliClient,
16
16
  loadCLISession,
17
+ markCliSessionInactive,
17
18
  persistNewOperationsDocForSession,
18
19
  startOneGraphCLISession,
19
20
  } = require('../../lib/one-graph/cli-client')
@@ -78,6 +79,30 @@ const isNonExistingCommandError = ({ command, error: commandError }) => {
78
79
  )
79
80
  }
80
81
 
82
+ /**
83
+ * @type {(() => Promise<void>)[]} - array of functions to run before the process exits
84
+ */
85
+ const cleanupWork = []
86
+
87
+ let cleanupStarted = false
88
+
89
+ /**
90
+ * @param {object} input
91
+ * @param {number=} input.exitCode The exit code to return when exiting the process after cleanup
92
+ */
93
+ const cleanupBeforeExit = async ({ exitCode }) => {
94
+ // If cleanup has started, then wherever started it will be responsible for exiting
95
+ if (!cleanupStarted) {
96
+ cleanupStarted = true
97
+ try {
98
+ // eslint-disable-next-line no-unused-vars
99
+ const cleanupFinished = await Promise.all(cleanupWork.map((cleanup) => cleanup()))
100
+ } finally {
101
+ process.exit(exitCode)
102
+ }
103
+ }
104
+ }
105
+
81
106
  /**
82
107
  * Run a command and pipe stdout, stderr and stdin
83
108
  * @param {string} command
@@ -100,30 +125,29 @@ const runCommand = (command, env = {}) => {
100
125
 
101
126
  // we can't try->await->catch since we don't want to block on the framework server which
102
127
  // is a long running process
103
- // eslint-disable-next-line promise/catch-or-return,promise/prefer-await-to-then
104
- commandProcess.then(async () => {
105
- const result = await commandProcess
106
- const [commandWithoutArgs] = command.split(' ')
107
- // eslint-disable-next-line promise/always-return
108
- if (result.failed && isNonExistingCommandError({ command: commandWithoutArgs, error: result })) {
109
- log(
110
- NETLIFYDEVERR,
111
- `Failed running command: ${command}. Please verify ${chalk.magenta(`'${commandWithoutArgs}'`)} exists`,
112
- )
113
- } else {
114
- const errorMessage = result.failed
115
- ? `${NETLIFYDEVERR} ${result.shortMessage}`
116
- : `${NETLIFYDEVWARN} "${command}" exited with code ${result.exitCode}`
117
-
118
- log(`${errorMessage}. Shutting down Netlify Dev server`)
119
- }
120
- process.exit(1)
121
- })
122
- ;['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP', 'exit'].forEach((signal) => {
123
- process.on(signal, () => {
124
- commandProcess.kill('SIGTERM', { forceKillAfterTimeout: 500 })
125
- process.exit()
128
+ // eslint-disable-next-line promise/catch-or-return
129
+ commandProcess
130
+ // eslint-disable-next-line promise/prefer-await-to-then
131
+ .then(async () => {
132
+ const result = await commandProcess
133
+ const [commandWithoutArgs] = command.split(' ')
134
+ if (result.failed && isNonExistingCommandError({ command: commandWithoutArgs, error: result })) {
135
+ log(
136
+ NETLIFYDEVERR,
137
+ `Failed running command: ${command}. Please verify ${chalk.magenta(`'${commandWithoutArgs}'`)} exists`,
138
+ )
139
+ } else {
140
+ const errorMessage = result.failed
141
+ ? `${NETLIFYDEVERR} ${result.shortMessage}`
142
+ : `${NETLIFYDEVWARN} "${command}" exited with code ${result.exitCode}`
143
+
144
+ log(`${errorMessage}. Shutting down Netlify Dev server`)
145
+ }
146
+
147
+ return await cleanupBeforeExit({ exitCode: 1 })
126
148
  })
149
+ ;['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP', 'exit'].forEach((signal) => {
150
+ process.on(signal, async () => await cleanupBeforeExit({}))
127
151
  })
128
152
 
129
153
  return commandProcess
@@ -322,26 +346,48 @@ const dev = async (options, command) => {
322
346
  } else if (startNetlifyGraphWatcher) {
323
347
  const netlifyToken = await command.authenticate()
324
348
  await OneGraphCliClient.ensureAppForSite(netlifyToken, site.id)
325
- const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options, settings })
326
349
 
327
- let graphqlDocument = readGraphQLOperationsSourceFile(netlifyGraphConfig)
350
+ let stopWatchingCLISessions
328
351
 
329
- if (!graphqlDocument || graphqlDocument.trim().length === 0) {
330
- graphqlDocument = defaultExampleOperationsDoc
331
- }
352
+ const createOrResumeSession = async function () {
353
+ const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options, settings })
332
354
 
333
- await startOneGraphCLISession({ netlifyGraphConfig, netlifyToken, site, state })
355
+ let graphqlDocument = readGraphQLOperationsSourceFile(netlifyGraphConfig)
334
356
 
335
- // Should be created by startOneGraphCLISession
336
- const oneGraphSessionId = loadCLISession(state)
357
+ if (!graphqlDocument || graphqlDocument.trim().length === 0) {
358
+ graphqlDocument = defaultExampleOperationsDoc
359
+ }
337
360
 
338
- await persistNewOperationsDocForSession({
339
- netlifyToken,
340
- oneGraphSessionId,
341
- operationsDoc: graphqlDocument,
342
- siteId: site.id,
361
+ stopWatchingCLISessions = await startOneGraphCLISession({ netlifyGraphConfig, netlifyToken, site, state })
362
+
363
+ // Should be created by startOneGraphCLISession
364
+ const oneGraphSessionId = loadCLISession(state)
365
+
366
+ await persistNewOperationsDocForSession({
367
+ netlifyGraphConfig,
368
+ netlifyToken,
369
+ oneGraphSessionId,
370
+ operationsDoc: graphqlDocument,
371
+ siteId: site.id,
372
+ siteRoot: site.root,
373
+ })
374
+
375
+ return oneGraphSessionId
376
+ }
377
+
378
+ //
379
+ // Set up a handler for config changes.
380
+ command.netlify.configWatcher.on('change', (newConfig) => {
381
+ command.netlify.config = newConfig
382
+ stopWatchingCLISessions()
383
+ createOrResumeSession()
343
384
  })
344
385
 
386
+ const oneGraphSessionId = await createOrResumeSession()
387
+ const cleanupSession = () => markCliSessionInactive({ netlifyToken, sessionId: oneGraphSessionId, siteId: site.id })
388
+
389
+ cleanupWork.push(cleanupSession)
390
+
345
391
  const graphEditUrl = getGraphEditUrlBySiteId({ siteId: site.id, oneGraphSessionId })
346
392
 
347
393
  log(
@@ -1,13 +1,7 @@
1
1
  // @ts-check
2
2
  const gitRepoInfo = require('git-repo-info')
3
3
 
4
- const {
5
- OneGraphCliClient,
6
- createCLISession,
7
- generateSessionName,
8
- loadCLISession,
9
- upsertMergeCLISessionMetadata,
10
- } = require('../../lib/one-graph/cli-client')
4
+ const { OneGraphCliClient, ensureCLISession, upsertMergeCLISessionMetadata } = require('../../lib/one-graph/cli-client')
11
5
  const {
12
6
  defaultExampleOperationsDoc,
13
7
  getGraphEditUrlBySiteId,
@@ -48,13 +42,12 @@ const graphEdit = async (options, command) => {
48
42
 
49
43
  await ensureAppForSite(netlifyToken, siteId)
50
44
 
51
- let oneGraphSessionId = loadCLISession(state)
52
- if (!oneGraphSessionId) {
53
- const sessionName = generateSessionName()
54
- const oneGraphSession = await createCLISession({ netlifyToken, siteId: site.id, sessionName, metadata: {} })
55
- state.set('oneGraphSessionId', oneGraphSession.id)
56
- oneGraphSessionId = state.get('oneGraphSessionId')
57
- }
45
+ const oneGraphSessionId = await ensureCLISession({
46
+ metadata: {},
47
+ netlifyToken,
48
+ site,
49
+ state,
50
+ })
58
51
 
59
52
  const { branch } = gitRepoInfo()
60
53
  const persistedDoc = await createPersistedQuery(netlifyToken, {
@@ -1,20 +1,28 @@
1
1
  // @ts-check
2
+ const inquirer = require('inquirer')
3
+ const { GraphQL } = require('netlify-onegraph-internal')
4
+
2
5
  const {
3
6
  buildSchema,
7
+ defaultExampleOperationsDoc,
8
+ extractFunctionsFromOperationDoc,
4
9
  generateHandlerByOperationName,
5
10
  getNetlifyGraphConfig,
11
+ readGraphQLOperationsSourceFile,
6
12
  readGraphQLSchemaFile,
7
13
  } = require('../../lib/one-graph/cli-netlify-graph')
8
14
  const { error, log } = require('../../utils')
9
15
 
16
+ const { parse } = GraphQL
17
+
10
18
  /**
11
19
  * Creates the `netlify graph:handler` command
12
- * @param {string} operationName
20
+ * @param {string} userOperationName
13
21
  * @param {import('commander').OptionValues} options
14
22
  * @param {import('../base-command').BaseCommand} command
15
23
  * @returns
16
24
  */
17
- const graphHandler = async (operationName, options, command) => {
25
+ const graphHandler = async (userOperationName, options, command) => {
18
26
  const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
19
27
 
20
28
  const schemaString = readGraphQLSchemaFile(netlifyGraphConfig)
@@ -31,6 +39,64 @@ const graphHandler = async (operationName, options, command) => {
31
39
  error(`Failed to parse Netlify GraphQL schema`)
32
40
  }
33
41
 
42
+ let operationName = userOperationName
43
+ if (!operationName) {
44
+ try {
45
+ let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
46
+ if (currentOperationsDoc.trim().length === 0) {
47
+ currentOperationsDoc = defaultExampleOperationsDoc
48
+ }
49
+
50
+ const parsedDoc = parse(currentOperationsDoc)
51
+ const { functions } = extractFunctionsFromOperationDoc(parsedDoc)
52
+
53
+ const sorted = Object.values(functions).sort((aItem, bItem) =>
54
+ aItem.operationName.localeCompare(bItem.operationName),
55
+ )
56
+
57
+ const perPage = 50
58
+
59
+ const allOperationChoices = sorted.map((operation) => ({
60
+ name: `${operation.operationName} (${operation.kind})`,
61
+ value: operation.operationName,
62
+ }))
63
+
64
+ const filterOperationNames = (operationChoices, input) =>
65
+ operationChoices.filter((operation) => operation.value.toLowerCase().match(input.toLowerCase()))
66
+
67
+ // eslint-disable-next-line node/global-require
68
+ const inquirerAutocompletePrompt = require('inquirer-autocomplete-prompt')
69
+ /** multiple matching detectors, make the user choose */
70
+ inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
71
+
72
+ const { selectedOperationName } = await inquirer.prompt({
73
+ name: 'selectedOperationName',
74
+ message: `For which operation would you like to generate a handler?`,
75
+ type: 'autocomplete',
76
+ pageSize: perPage,
77
+ source(_, input) {
78
+ if (!input || input === '') {
79
+ return allOperationChoices
80
+ }
81
+
82
+ const filteredChoices = filterOperationNames(allOperationChoices, input)
83
+ // only show filtered results
84
+ return filteredChoices
85
+ },
86
+ })
87
+
88
+ if (selectedOperationName) {
89
+ operationName = selectedOperationName
90
+ }
91
+ } catch (parseError) {
92
+ parseError(`Error parsing operations library: ${parseError}`)
93
+ }
94
+ }
95
+
96
+ if (!operationName) {
97
+ error(`No operation name provided`)
98
+ }
99
+
34
100
  generateHandlerByOperationName({ logger: log, netlifyGraphConfig, schema, operationName, handlerOptions: {} })
35
101
  }
36
102
 
@@ -42,7 +108,7 @@ const graphHandler = async (operationName, options, command) => {
42
108
  const createGraphHandlerCommand = (program) =>
43
109
  program
44
110
  .command('graph:handler')
45
- .argument('<name>', 'Operation name')
111
+ .argument('[name]', 'Operation name')
46
112
  .description(
47
113
  'Generate a handler for a Graph operation given its name. See `graph:operations` for a list of operations.',
48
114
  )
@@ -5,12 +5,11 @@ const { env } = require('process')
5
5
 
6
6
  const terminalLink = require('terminal-link')
7
7
 
8
- const { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, chalk, log, warn } = require('../../utils')
8
+ const { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, chalk, log, warn, watchDebounced } = require('../../utils')
9
9
  const { getLogMessage } = require('../log')
10
10
 
11
11
  const { NetlifyFunction } = require('./netlify-function')
12
12
  const runtimes = require('./runtimes')
13
- const { watchDebounced } = require('./watcher')
14
13
 
15
14
  const ZIP_EXTENSION = '.zip'
16
15
 
@@ -10,8 +10,7 @@ const { GraphQL, InternalConsole, OneGraphClient } = require('netlify-onegraph-i
10
10
  const { NetlifyGraph } = require('netlify-onegraph-internal')
11
11
 
12
12
  // eslint-disable-next-line no-unused-vars
13
- const { StateConfig, USER_AGENT, chalk, error, log, warn } = require('../../utils')
14
- const { watchDebounced } = require('../functions/watcher')
13
+ const { StateConfig, USER_AGENT, chalk, error, log, warn, watchDebounced } = require('../../utils')
15
14
 
16
15
  const {
17
16
  generateFunctionsFile,
@@ -24,7 +23,13 @@ const {
24
23
 
25
24
  const { parse } = GraphQL
26
25
  const { defaultExampleOperationsDoc, extractFunctionsFromOperationDoc } = NetlifyGraph
27
- const { createPersistedQuery, ensureAppForSite, updateCLISessionMetadata } = OneGraphClient
26
+ const {
27
+ createPersistedQuery,
28
+ ensureAppForSite,
29
+ executeMarkCliSessionActiveHeartbeat,
30
+ executeMarkCliSessionInactive,
31
+ updateCLISessionMetadata,
32
+ } = OneGraphClient
28
33
 
29
34
  const internalConsole = {
30
35
  log,
@@ -51,13 +56,31 @@ InternalConsole.registerConsole(internalConsole)
51
56
  * @param {function} input.onEvents A function to call when CLI events are received and need to be processed
52
57
  * @param {string} input.sessionId The session id to monitor CLI events for
53
58
  * @param {StateConfig} input.state A function to call to set/get the current state of the local Netlify project
59
+ * @param {any} input.site The site object
54
60
  * @returns
55
61
  */
56
62
  const monitorCLISessionEvents = (input) => {
57
- const { appId, netlifyGraphConfig, netlifyToken, onClose, onError, onEvents, sessionId, state } = input
63
+ const { appId, netlifyGraphConfig, netlifyToken, onClose, onError, onEvents, sessionId, site, state } = input
58
64
 
59
65
  const frequency = 5000
66
+ // 30 minutes
67
+ const defaultHeartbeatFrequency = 1_800_000
60
68
  let shouldClose = false
69
+ let nextMarkActiveHeartbeat = defaultHeartbeatFrequency
70
+
71
+ const markActiveHelper = async () => {
72
+ const fullSession = await OneGraphClient.fetchCliSession({ authToken: netlifyToken, appId, sessionId })
73
+ // @ts-ignore
74
+ const heartbeatIntervalms = fullSession.session.cliHeartbeatIntervalMs || defaultHeartbeatFrequency
75
+ nextMarkActiveHeartbeat = heartbeatIntervalms
76
+ const markCLISessionActiveResult = await executeMarkCliSessionActiveHeartbeat(netlifyToken, site.id, sessionId)
77
+ if (markCLISessionActiveResult.errors && markCLISessionActiveResult.errors.length !== 0) {
78
+ warn(`Failed to mark CLI session active: ${markCLISessionActiveResult.errors.join(', ')}`)
79
+ }
80
+ setTimeout(markActiveHelper, nextMarkActiveHeartbeat)
81
+ }
82
+
83
+ setTimeout(markActiveHelper, nextMarkActiveHeartbeat)
61
84
 
62
85
  const enabledServiceWatcher = async (innerNetlifyToken, siteId) => {
63
86
  const enabledServices = state.get('oneGraphEnabledServices') || ['onegraph']
@@ -90,7 +113,7 @@ const monitorCLISessionEvents = (input) => {
90
113
  const helper = async () => {
91
114
  if (shouldClose) {
92
115
  clearTimeout(handle)
93
- onClose()
116
+ onClose && onClose()
94
117
  }
95
118
 
96
119
  const next = await OneGraphClient.fetchCliSessionEvents({ appId, authToken: netlifyToken, sessionId })
@@ -371,6 +394,7 @@ const upsertMergeCLISessionMetadata = async ({ netlifyToken, newMetadata, oneGra
371
394
 
372
395
  const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot })
373
396
 
397
+ // @ts-ignore
374
398
  const finalMetadata = { ...metadata, ...detectedMetadata, ...newMetadata }
375
399
  return OneGraphClient.updateCLISessionMetadata(netlifyToken, siteId, oneGraphSessionId, finalMetadata)
376
400
  }
@@ -429,24 +453,18 @@ const loadCLISession = (state) => state.get('oneGraphSessionId')
429
453
  const startOneGraphCLISession = async (input) => {
430
454
  const { netlifyGraphConfig, netlifyToken, site, state } = input
431
455
  OneGraphClient.ensureAppForSite(netlifyToken, site.id)
432
- let oneGraphSessionId = loadCLISession(state)
433
- if (!oneGraphSessionId) {
434
- const sessionName = generateSessionName()
435
- const sessionMetadata = {}
436
- const oneGraphSession = await createCLISession({
437
- netlifyToken,
438
- siteId: site.id,
439
- sessionName,
440
- metadata: sessionMetadata,
441
- })
442
- state.set('oneGraphSessionId', oneGraphSession.id)
443
- oneGraphSessionId = state.get('oneGraphSessionId')
444
- }
456
+
457
+ const oneGraphSessionId = await ensureCLISession({
458
+ metadata: {},
459
+ netlifyToken,
460
+ site,
461
+ state,
462
+ })
445
463
 
446
464
  const enabledServices = []
447
465
  const schema = await OneGraphClient.fetchOneGraphSchema(site.id, enabledServices)
448
466
 
449
- monitorOperationFile({
467
+ const opsFileWatcher = monitorOperationFile({
450
468
  netlifyGraphConfig,
451
469
  onChange: async (filePath) => {
452
470
  log('NetlifyGraph operation file changed at', filePath, 'updating function library...')
@@ -476,11 +494,12 @@ const startOneGraphCLISession = async (input) => {
476
494
  },
477
495
  })
478
496
 
479
- monitorCLISessionEvents({
497
+ const cliEventsCloseFn = monitorCLISessionEvents({
480
498
  appId: site.id,
481
499
  netlifyToken,
482
500
  netlifyGraphConfig,
483
501
  sessionId: oneGraphSessionId,
502
+ site,
484
503
  state,
485
504
  onEvents: async (events) => {
486
505
  for (const event of events) {
@@ -494,10 +513,27 @@ const startOneGraphCLISession = async (input) => {
494
513
  onError: (fetchEventError) => {
495
514
  error(`Netlify Graph upstream error: ${fetchEventError}`)
496
515
  },
497
- onClose: () => {
498
- log('Netlify Graph upstream closed')
499
- },
500
516
  })
517
+
518
+ return async function unregisterWatchers() {
519
+ const watcher = await opsFileWatcher
520
+ watcher.close()
521
+ cliEventsCloseFn()
522
+ }
523
+ }
524
+
525
+ /**
526
+ * Mark a session as inactive so it doesn't show up in any UI lists, and potentially becomes available to GC later
527
+ * @param {object} input
528
+ * @param {string} input.netlifyToken The (typically netlify) access token that is used for authentication, if any
529
+ * @param {string} input.siteId A function to call to set/get the current state of the local Netlify project
530
+ * @param {string} input.sessionId The session id to monitor CLI events for
531
+ */
532
+ const markCliSessionInactive = async ({ netlifyToken, sessionId, siteId }) => {
533
+ const result = await executeMarkCliSessionInactive(netlifyToken, siteId, sessionId)
534
+ if (result.errors) {
535
+ warn(`Unable to mark CLI session ${sessionId} inactive: ${JSON.stringify(result.errors, null, 2)}`)
536
+ }
501
537
  }
502
538
 
503
539
  /**
@@ -511,6 +547,70 @@ const generateSessionName = () => {
511
547
  return sessionName
512
548
  }
513
549
 
550
+ /**
551
+ * Ensures a cli session exists for the current checkout, or errors out if it doesn't and cannot create one.
552
+ */
553
+ const ensureCLISession = async ({ metadata, netlifyToken, site, state }) => {
554
+ let oneGraphSessionId = loadCLISession(state)
555
+ let parentCliSessionId = null
556
+
557
+ // Validate that session still exists and we can access it
558
+ try {
559
+ if (oneGraphSessionId) {
560
+ const sessionEvents = await OneGraphClient.fetchCliSessionEvents({
561
+ appId: site.id,
562
+ authToken: netlifyToken,
563
+ sessionId: oneGraphSessionId,
564
+ })
565
+ if (sessionEvents.errors) {
566
+ warn(`Unable to fetch cli session: ${JSON.stringify(sessionEvents.errors, null, 2)}`)
567
+ log(`Creating new cli session`)
568
+ parentCliSessionId = oneGraphSessionId
569
+ oneGraphSessionId = null
570
+ }
571
+ }
572
+ } catch (fetchSessionError) {
573
+ warn(`Unable to fetch cli session events: ${JSON.stringify(fetchSessionError, null, 2)}`)
574
+ oneGraphSessionId = null
575
+ }
576
+
577
+ if (!oneGraphSessionId) {
578
+ // If we can't access the session in the state.json or it doesn't exist, create a new one
579
+ const sessionName = generateSessionName()
580
+ const detectedMetadata = detectLocalCLISessionMetadata({ siteRoot: site.root })
581
+ const newSessionMetadata = parentCliSessionId ? { parentCliSessionId } : {}
582
+ const sessionMetadata = {
583
+ ...detectedMetadata,
584
+ ...newSessionMetadata,
585
+ ...metadata,
586
+ }
587
+ const oneGraphSession = await createCLISession({
588
+ netlifyToken,
589
+ siteId: site.id,
590
+ sessionName,
591
+ metadata: sessionMetadata,
592
+ })
593
+ state.set('oneGraphSessionId', oneGraphSession.id)
594
+ oneGraphSessionId = state.get('oneGraphSessionId')
595
+ }
596
+
597
+ if (!oneGraphSessionId) {
598
+ error('Unable to create or access Netlify Graph CLI session')
599
+ }
600
+
601
+ const { errors: markCLISessionActiveErrors } = await executeMarkCliSessionActiveHeartbeat(
602
+ netlifyToken,
603
+ site.id,
604
+ oneGraphSessionId,
605
+ )
606
+
607
+ if (markCLISessionActiveErrors) {
608
+ warn(`Unable to mark cli session active: ${JSON.stringify(markCLISessionActiveErrors, null, 2)}`)
609
+ }
610
+
611
+ return oneGraphSessionId
612
+ }
613
+
514
614
  const OneGraphCliClient = {
515
615
  ackCLISessionEvents: OneGraphClient.ackCLISessionEvents,
516
616
  createPersistedQuery,
@@ -522,10 +622,12 @@ const OneGraphCliClient = {
522
622
  module.exports = {
523
623
  OneGraphCliClient,
524
624
  createCLISession,
625
+ ensureCLISession,
525
626
  extractFunctionsFromOperationDoc,
526
627
  handleCliSessionEvent,
527
628
  generateSessionName,
528
629
  loadCLISession,
630
+ markCliSessionInactive,
529
631
  monitorCLISessionEvents,
530
632
  persistNewOperationsDocForSession,
531
633
  refetchAndGenerateFromOneGraph,
@@ -4,8 +4,12 @@ const process = require('process')
4
4
  const { format, inspect } = require('util')
5
5
 
6
6
  const { Instance: ChalkInstance } = require('chalk')
7
+ const chokidar = require('chokidar')
8
+ const decache = require('decache')
7
9
  const WSL = require('is-wsl')
10
+ const debounce = require('lodash/debounce')
8
11
  const { default: omit } = require('omit.js')
12
+ const pEvent = require('p-event')
9
13
 
10
14
  const { name, version } = require('../../package.json')
11
15
  const { clearSpinner, startSpinner } = require('../lib/spinner')
@@ -198,6 +202,34 @@ const normalizeConfig = (config) =>
198
202
  ? { ...config, build: omit(config.build, ['publish', 'publishOrigin']) }
199
203
  : config
200
204
 
205
+ const DEBOUNCE_WAIT = 100
206
+
207
+ const watchDebounced = async (target, { depth, onAdd = () => {}, onChange = () => {}, onUnlink = () => {} }) => {
208
+ const watcher = chokidar.watch(target, { depth, ignored: /node_modules/, ignoreInitial: true })
209
+
210
+ await pEvent(watcher, 'ready')
211
+
212
+ const debouncedOnChange = debounce(onChange, DEBOUNCE_WAIT)
213
+ const debouncedOnUnlink = debounce(onUnlink, DEBOUNCE_WAIT)
214
+ const debouncedOnAdd = debounce(onAdd, DEBOUNCE_WAIT)
215
+
216
+ watcher
217
+ .on('change', (path) => {
218
+ decache(path)
219
+ debouncedOnChange(path)
220
+ })
221
+ .on('unlink', (path) => {
222
+ decache(path)
223
+ debouncedOnUnlink(path)
224
+ })
225
+ .on('add', (path) => {
226
+ decache(path)
227
+ debouncedOnAdd(path)
228
+ })
229
+
230
+ return watcher
231
+ }
232
+
201
233
  module.exports = {
202
234
  BANG,
203
235
  chalk,
@@ -217,4 +249,5 @@ module.exports = {
217
249
  sortOptions,
218
250
  USER_AGENT,
219
251
  warn,
252
+ watchDebounced,
220
253
  }
@@ -1,35 +0,0 @@
1
- // @ts-check
2
- const chokidar = require('chokidar')
3
- const decache = require('decache')
4
- const debounce = require('lodash/debounce')
5
- const pEvent = require('p-event')
6
-
7
- const DEBOUNCE_WAIT = 100
8
-
9
- const watchDebounced = async (target, { depth, onAdd = () => {}, onChange = () => {}, onUnlink = () => {} }) => {
10
- const watcher = chokidar.watch(target, { depth, ignored: /node_modules/, ignoreInitial: true })
11
-
12
- await pEvent(watcher, 'ready')
13
-
14
- const debouncedOnChange = debounce(onChange, DEBOUNCE_WAIT)
15
- const debouncedOnUnlink = debounce(onUnlink, DEBOUNCE_WAIT)
16
- const debouncedOnAdd = debounce(onAdd, DEBOUNCE_WAIT)
17
-
18
- watcher
19
- .on('change', (path) => {
20
- decache(path)
21
- debouncedOnChange(path)
22
- })
23
- .on('unlink', (path) => {
24
- decache(path)
25
- debouncedOnUnlink(path)
26
- })
27
- .on('add', (path) => {
28
- decache(path)
29
- debouncedOnAdd(path)
30
- })
31
-
32
- return watcher
33
- }
34
-
35
- module.exports = { watchDebounced }