netlify-cli 8.13.2 → 8.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/npm-shrinkwrap.json +34 -75
- package/package.json +8 -7
- package/src/commands/dev/dev.js +1 -1
- package/src/commands/functions/functions-invoke.js +17 -2
- package/src/commands/link/link.js +5 -14
- package/src/commands/sites/sites-create.js +9 -2
- package/src/lib/functions/netlify-function.js +9 -1
- package/src/lib/functions/runtimes/js/builders/zisi.js +28 -6
- package/src/lib/functions/runtimes/js/index.js +2 -1
- package/src/lib/functions/scheduled.js +98 -0
- package/src/lib/functions/server.js +10 -0
- package/src/lib/one-graph/cli-netlify-graph.js +7 -6
- package/src/utils/functions/constants.js +5 -0
- package/src/utils/functions/get-functions.js +5 -3
- package/src/utils/functions/index.js +2 -0
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.15.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "netlify-cli",
|
|
9
|
-
"version": "8.
|
|
9
|
+
"version": "8.15.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"@sindresorhus/slugify": "^1.1.0",
|
|
23
23
|
"ansi-escapes": "^5.0.0",
|
|
24
24
|
"ansi-styles": "^5.0.0",
|
|
25
|
+
"ansi2html": "^0.0.1",
|
|
25
26
|
"ascii-table": "0.0.9",
|
|
26
27
|
"backoff": "^2.5.0",
|
|
27
28
|
"better-opn": "^3.0.0",
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
"content-type": "^1.0.4",
|
|
37
38
|
"cookie": "^0.4.0",
|
|
38
39
|
"copy-template-dir": "^1.4.0",
|
|
40
|
+
"cron-parser": "^4.2.1",
|
|
39
41
|
"debug": "^4.1.1",
|
|
40
42
|
"decache": "^4.6.0",
|
|
41
43
|
"del": "^6.0.0",
|
|
@@ -79,7 +81,7 @@
|
|
|
79
81
|
"multiparty": "^4.2.1",
|
|
80
82
|
"netlify": "^10.1.2",
|
|
81
83
|
"netlify-headers-parser": "^6.0.1",
|
|
82
|
-
"netlify-onegraph-internal": "0.0.
|
|
84
|
+
"netlify-onegraph-internal": "0.0.16",
|
|
83
85
|
"netlify-redirect-parser": "^13.0.1",
|
|
84
86
|
"netlify-redirector": "^0.2.1",
|
|
85
87
|
"node-fetch": "^2.6.0",
|
|
@@ -122,7 +124,7 @@
|
|
|
122
124
|
},
|
|
123
125
|
"devDependencies": {
|
|
124
126
|
"@babel/preset-react": "^7.12.13",
|
|
125
|
-
"@netlify/eslint-config-node": "^4.1.
|
|
127
|
+
"@netlify/eslint-config-node": "^4.1.7",
|
|
126
128
|
"ava": "^4.0.0",
|
|
127
129
|
"c8": "^7.11.0",
|
|
128
130
|
"eslint-plugin-sort-destructure-keys": "^1.3.5",
|
|
@@ -134,7 +136,6 @@
|
|
|
134
136
|
"ini": "^2.0.0",
|
|
135
137
|
"jsonwebtoken": "^8.5.1",
|
|
136
138
|
"mock-fs": "^5.1.2",
|
|
137
|
-
"mock-require": "^3.0.3",
|
|
138
139
|
"p-timeout": "^4.0.0",
|
|
139
140
|
"proxyquire": "^2.1.3",
|
|
140
141
|
"seedrandom": "^3.0.5",
|
|
@@ -2566,9 +2567,9 @@
|
|
|
2566
2567
|
}
|
|
2567
2568
|
},
|
|
2568
2569
|
"node_modules/@netlify/eslint-config-node": {
|
|
2569
|
-
"version": "4.1.
|
|
2570
|
-
"resolved": "https://registry.npmjs.org/@netlify/eslint-config-node/-/eslint-config-node-4.1.
|
|
2571
|
-
"integrity": "sha512-
|
|
2570
|
+
"version": "4.1.7",
|
|
2571
|
+
"resolved": "https://registry.npmjs.org/@netlify/eslint-config-node/-/eslint-config-node-4.1.7.tgz",
|
|
2572
|
+
"integrity": "sha512-3XYVE0Wnr8YmSTls7447fT4Lyr5goFJ1kK/xevdLVdlzinxd1Wc6SK4um5hZAvl6nrURmgRfLBSIqdpDeRFIlg==",
|
|
2572
2573
|
"dev": true,
|
|
2573
2574
|
"dependencies": {
|
|
2574
2575
|
"@babel/core": "^7.13.8",
|
|
@@ -4426,6 +4427,17 @@
|
|
|
4426
4427
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
4427
4428
|
}
|
|
4428
4429
|
},
|
|
4430
|
+
"node_modules/ansi2html": {
|
|
4431
|
+
"version": "0.0.1",
|
|
4432
|
+
"resolved": "https://registry.npmjs.org/ansi2html/-/ansi2html-0.0.1.tgz",
|
|
4433
|
+
"integrity": "sha1-u4gARhtECvALkb89c2al4LhHO6g=",
|
|
4434
|
+
"bin": {
|
|
4435
|
+
"ansi2html": "bin/ansi2html"
|
|
4436
|
+
},
|
|
4437
|
+
"engines": {
|
|
4438
|
+
"node": ">0.4"
|
|
4439
|
+
}
|
|
4440
|
+
},
|
|
4429
4441
|
"node_modules/any-observable": {
|
|
4430
4442
|
"version": "0.3.0",
|
|
4431
4443
|
"resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz",
|
|
@@ -10887,12 +10899,6 @@
|
|
|
10887
10899
|
"node": ">=6.0"
|
|
10888
10900
|
}
|
|
10889
10901
|
},
|
|
10890
|
-
"node_modules/get-caller-file": {
|
|
10891
|
-
"version": "1.0.3",
|
|
10892
|
-
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
|
10893
|
-
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
|
|
10894
|
-
"dev": true
|
|
10895
|
-
},
|
|
10896
10902
|
"node_modules/get-intrinsic": {
|
|
10897
10903
|
"version": "1.1.1",
|
|
10898
10904
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
|
@@ -14770,31 +14776,6 @@
|
|
|
14770
14776
|
"node": ">=12.0.0"
|
|
14771
14777
|
}
|
|
14772
14778
|
},
|
|
14773
|
-
"node_modules/mock-require": {
|
|
14774
|
-
"version": "3.0.3",
|
|
14775
|
-
"resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz",
|
|
14776
|
-
"integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==",
|
|
14777
|
-
"dev": true,
|
|
14778
|
-
"dependencies": {
|
|
14779
|
-
"get-caller-file": "^1.0.2",
|
|
14780
|
-
"normalize-path": "^2.1.1"
|
|
14781
|
-
},
|
|
14782
|
-
"engines": {
|
|
14783
|
-
"node": ">=4.3.0"
|
|
14784
|
-
}
|
|
14785
|
-
},
|
|
14786
|
-
"node_modules/mock-require/node_modules/normalize-path": {
|
|
14787
|
-
"version": "2.1.1",
|
|
14788
|
-
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
|
14789
|
-
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
|
|
14790
|
-
"dev": true,
|
|
14791
|
-
"dependencies": {
|
|
14792
|
-
"remove-trailing-separator": "^1.0.1"
|
|
14793
|
-
},
|
|
14794
|
-
"engines": {
|
|
14795
|
-
"node": ">=0.10.0"
|
|
14796
|
-
}
|
|
14797
|
-
},
|
|
14798
14779
|
"node_modules/module-definition": {
|
|
14799
14780
|
"version": "3.3.1",
|
|
14800
14781
|
"resolved": "https://registry.npmjs.org/module-definition/-/module-definition-3.3.1.tgz",
|
|
@@ -15052,9 +15033,9 @@
|
|
|
15052
15033
|
}
|
|
15053
15034
|
},
|
|
15054
15035
|
"node_modules/netlify-onegraph-internal": {
|
|
15055
|
-
"version": "0.0.
|
|
15056
|
-
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.0.
|
|
15057
|
-
"integrity": "sha512-
|
|
15036
|
+
"version": "0.0.16",
|
|
15037
|
+
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.0.16.tgz",
|
|
15038
|
+
"integrity": "sha512-reQ/C7ztbYCDMXqFLSw0rBwOi866sqdBjagUs6Ug6LXDkCIGHBTjMX0iwNhEn7+/WzV4f1lJj66NhdjF5Q4/aQ==",
|
|
15058
15039
|
"dependencies": {
|
|
15059
15040
|
"graphql": "16.0.0",
|
|
15060
15041
|
"node-fetch": "^2.6.0",
|
|
@@ -23445,9 +23426,9 @@
|
|
|
23445
23426
|
"integrity": "sha512-tiKmDcHM2riSVN79c0mJY/67EBDafXQAMitHuLiCDAMdtz3kfv+NqdVG5krgf5lWR8Uf8AeZrUW5Q9RP25REvw=="
|
|
23446
23427
|
},
|
|
23447
23428
|
"@netlify/eslint-config-node": {
|
|
23448
|
-
"version": "4.1.
|
|
23449
|
-
"resolved": "https://registry.npmjs.org/@netlify/eslint-config-node/-/eslint-config-node-4.1.
|
|
23450
|
-
"integrity": "sha512-
|
|
23429
|
+
"version": "4.1.7",
|
|
23430
|
+
"resolved": "https://registry.npmjs.org/@netlify/eslint-config-node/-/eslint-config-node-4.1.7.tgz",
|
|
23431
|
+
"integrity": "sha512-3XYVE0Wnr8YmSTls7447fT4Lyr5goFJ1kK/xevdLVdlzinxd1Wc6SK4um5hZAvl6nrURmgRfLBSIqdpDeRFIlg==",
|
|
23451
23432
|
"dev": true,
|
|
23452
23433
|
"requires": {
|
|
23453
23434
|
"@babel/core": "^7.13.8",
|
|
@@ -24813,6 +24794,11 @@
|
|
|
24813
24794
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
|
24814
24795
|
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
|
24815
24796
|
},
|
|
24797
|
+
"ansi2html": {
|
|
24798
|
+
"version": "0.0.1",
|
|
24799
|
+
"resolved": "https://registry.npmjs.org/ansi2html/-/ansi2html-0.0.1.tgz",
|
|
24800
|
+
"integrity": "sha1-u4gARhtECvALkb89c2al4LhHO6g="
|
|
24801
|
+
},
|
|
24816
24802
|
"any-observable": {
|
|
24817
24803
|
"version": "0.3.0",
|
|
24818
24804
|
"resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz",
|
|
@@ -29735,12 +29721,6 @@
|
|
|
29735
29721
|
"node-source-walk": "^4.0.0"
|
|
29736
29722
|
}
|
|
29737
29723
|
},
|
|
29738
|
-
"get-caller-file": {
|
|
29739
|
-
"version": "1.0.3",
|
|
29740
|
-
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
|
29741
|
-
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
|
|
29742
|
-
"dev": true
|
|
29743
|
-
},
|
|
29744
29724
|
"get-intrinsic": {
|
|
29745
29725
|
"version": "1.1.1",
|
|
29746
29726
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
|
@@ -32621,27 +32601,6 @@
|
|
|
32621
32601
|
"integrity": "sha512-YkjQkdLulFrz0vD4BfNQdQRVmgycXTV7ykuHMlyv+C8WCHazpkiQRDthwa02kSyo8wKnY9wRptHfQLgmf0eR+A==",
|
|
32622
32602
|
"dev": true
|
|
32623
32603
|
},
|
|
32624
|
-
"mock-require": {
|
|
32625
|
-
"version": "3.0.3",
|
|
32626
|
-
"resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz",
|
|
32627
|
-
"integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==",
|
|
32628
|
-
"dev": true,
|
|
32629
|
-
"requires": {
|
|
32630
|
-
"get-caller-file": "^1.0.2",
|
|
32631
|
-
"normalize-path": "^2.1.1"
|
|
32632
|
-
},
|
|
32633
|
-
"dependencies": {
|
|
32634
|
-
"normalize-path": {
|
|
32635
|
-
"version": "2.1.1",
|
|
32636
|
-
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
|
32637
|
-
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
|
|
32638
|
-
"dev": true,
|
|
32639
|
-
"requires": {
|
|
32640
|
-
"remove-trailing-separator": "^1.0.1"
|
|
32641
|
-
}
|
|
32642
|
-
}
|
|
32643
|
-
}
|
|
32644
|
-
},
|
|
32645
32604
|
"module-definition": {
|
|
32646
32605
|
"version": "3.3.1",
|
|
32647
32606
|
"resolved": "https://registry.npmjs.org/module-definition/-/module-definition-3.3.1.tgz",
|
|
@@ -32840,9 +32799,9 @@
|
|
|
32840
32799
|
}
|
|
32841
32800
|
},
|
|
32842
32801
|
"netlify-onegraph-internal": {
|
|
32843
|
-
"version": "0.0.
|
|
32844
|
-
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.0.
|
|
32845
|
-
"integrity": "sha512-
|
|
32802
|
+
"version": "0.0.16",
|
|
32803
|
+
"resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.0.16.tgz",
|
|
32804
|
+
"integrity": "sha512-reQ/C7ztbYCDMXqFLSw0rBwOi866sqdBjagUs6Ug6LXDkCIGHBTjMX0iwNhEn7+/WzV4f1lJj66NhdjF5Q4/aQ==",
|
|
32846
32805
|
"requires": {
|
|
32847
32806
|
"graphql": "16.0.0",
|
|
32848
32807
|
"node-fetch": "^2.6.0",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.15.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Mathias Biilmann <matt@netlify.com> (https://twitter.com/biilmann)",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"test:dev:ava": "ava --verbose",
|
|
65
65
|
"test:ci:ava": "c8 -r json ava",
|
|
66
66
|
"test:affected": "node ./tools/affected-test.js",
|
|
67
|
-
"e2e": "node ./tools/e2e/run.
|
|
67
|
+
"e2e": "node ./tools/e2e/run.mjs",
|
|
68
68
|
"docs": "node ./site/scripts/docs.js",
|
|
69
69
|
"watch": "c8 --reporter=lcov ava --watch",
|
|
70
70
|
"site:build": "run-s site:build:*",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"postinstall": "node ./scripts/postinstall.js"
|
|
74
74
|
},
|
|
75
75
|
"config": {
|
|
76
|
-
"eslint": "--ignore-path .gitignore --cache --format=codeframe --max-warnings=0 \"{src,tools,scripts,site,tests,.github}/**/*.{js,md,html}\" \"*.{js,md,html}\" \".*.{js,md,html}\"",
|
|
77
|
-
"prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{js,md,yml,json,html}\" \"*.{js,yml,json,html}\" \".*.{js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!.github/**/*.md\""
|
|
76
|
+
"eslint": "--ignore-path .gitignore --cache --format=codeframe --max-warnings=0 \"{src,tools,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,html}\" \"*.{mjs,cjs,js,md,html}\" \".*.{mjs,cjs,js,md,html}\"",
|
|
77
|
+
"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\" \"!.github/**/*.md\""
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@netlify/build": "^26.2.0",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"@sindresorhus/slugify": "^1.1.0",
|
|
90
90
|
"ansi-escapes": "^5.0.0",
|
|
91
91
|
"ansi-styles": "^5.0.0",
|
|
92
|
+
"ansi2html": "^0.0.1",
|
|
92
93
|
"ascii-table": "0.0.9",
|
|
93
94
|
"backoff": "^2.5.0",
|
|
94
95
|
"better-opn": "^3.0.0",
|
|
@@ -103,6 +104,7 @@
|
|
|
103
104
|
"content-type": "^1.0.4",
|
|
104
105
|
"cookie": "^0.4.0",
|
|
105
106
|
"copy-template-dir": "^1.4.0",
|
|
107
|
+
"cron-parser": "^4.2.1",
|
|
106
108
|
"debug": "^4.1.1",
|
|
107
109
|
"decache": "^4.6.0",
|
|
108
110
|
"del": "^6.0.0",
|
|
@@ -146,7 +148,7 @@
|
|
|
146
148
|
"multiparty": "^4.2.1",
|
|
147
149
|
"netlify": "^10.1.2",
|
|
148
150
|
"netlify-headers-parser": "^6.0.1",
|
|
149
|
-
"netlify-onegraph-internal": "0.0.
|
|
151
|
+
"netlify-onegraph-internal": "0.0.16",
|
|
150
152
|
"netlify-redirect-parser": "^13.0.1",
|
|
151
153
|
"netlify-redirector": "^0.2.1",
|
|
152
154
|
"node-fetch": "^2.6.0",
|
|
@@ -185,7 +187,7 @@
|
|
|
185
187
|
},
|
|
186
188
|
"devDependencies": {
|
|
187
189
|
"@babel/preset-react": "^7.12.13",
|
|
188
|
-
"@netlify/eslint-config-node": "^4.1.
|
|
190
|
+
"@netlify/eslint-config-node": "^4.1.7",
|
|
189
191
|
"ava": "^4.0.0",
|
|
190
192
|
"c8": "^7.11.0",
|
|
191
193
|
"eslint-plugin-sort-destructure-keys": "^1.3.5",
|
|
@@ -197,7 +199,6 @@
|
|
|
197
199
|
"ini": "^2.0.0",
|
|
198
200
|
"jsonwebtoken": "^8.5.1",
|
|
199
201
|
"mock-fs": "^5.1.2",
|
|
200
|
-
"mock-require": "^3.0.3",
|
|
201
202
|
"p-timeout": "^4.0.0",
|
|
202
203
|
"proxyquire": "^2.1.3",
|
|
203
204
|
"seedrandom": "^3.0.5",
|
package/src/commands/dev/dev.js
CHANGED
|
@@ -308,7 +308,7 @@ const dev = async (options, command) => {
|
|
|
308
308
|
} else if (startNetlifyGraphWatcher) {
|
|
309
309
|
const netlifyToken = await command.authenticate()
|
|
310
310
|
await OneGraphCliClient.ensureAppForSite(netlifyToken, site.id)
|
|
311
|
-
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options })
|
|
311
|
+
const netlifyGraphConfig = await getNetlifyGraphConfig({ command, options, settings })
|
|
312
312
|
|
|
313
313
|
log(`Starting Netlify Graph session, to edit your library run \`netlify graph:edit\` in another tab`)
|
|
314
314
|
|
|
@@ -3,10 +3,11 @@ const fs = require('fs')
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const process = require('process')
|
|
5
5
|
|
|
6
|
+
const CronParser = require('cron-parser')
|
|
6
7
|
const inquirer = require('inquirer')
|
|
7
8
|
const fetch = require('node-fetch')
|
|
8
9
|
|
|
9
|
-
const { BACKGROUND, NETLIFYDEVWARN, chalk, error, exit, getFunctions } = require('../../utils')
|
|
10
|
+
const { BACKGROUND, CLOCKWORK_USERAGENT, NETLIFYDEVWARN, chalk, error, exit, getFunctions } = require('../../utils')
|
|
10
11
|
|
|
11
12
|
// https://www.netlify.com/docs/functions/#event-triggered-functions
|
|
12
13
|
const events = [
|
|
@@ -130,6 +131,13 @@ const getFunctionToTrigger = function (options, argumentName) {
|
|
|
130
131
|
return argumentName
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
const getNextRun = function (schedule) {
|
|
135
|
+
const cron = CronParser.parseExpression(schedule, {
|
|
136
|
+
tz: 'Etc/UTC',
|
|
137
|
+
})
|
|
138
|
+
return cron.next().toDate()
|
|
139
|
+
}
|
|
140
|
+
|
|
133
141
|
/**
|
|
134
142
|
* The functions:invoke command
|
|
135
143
|
* @param {string} nameArgument
|
|
@@ -150,11 +158,18 @@ const functionsInvoke = async (nameArgument, options, command) => {
|
|
|
150
158
|
|
|
151
159
|
const functions = await getFunctions(functionsDir)
|
|
152
160
|
const functionToTrigger = await getNameFromArgs(functions, options, nameArgument)
|
|
161
|
+
const functionObj = functions.find((func) => func.name === functionToTrigger)
|
|
153
162
|
|
|
154
163
|
let headers = {}
|
|
155
164
|
let body = {}
|
|
156
165
|
|
|
157
|
-
if (
|
|
166
|
+
if (functionObj.schedule) {
|
|
167
|
+
body.next_run = getNextRun(functionObj.schedule)
|
|
168
|
+
headers = {
|
|
169
|
+
'user-agent': CLOCKWORK_USERAGENT,
|
|
170
|
+
'X-NF-Event': 'schedule',
|
|
171
|
+
}
|
|
172
|
+
} else if (eventTriggeredFunctions.has(functionToTrigger)) {
|
|
158
173
|
/** handle event triggered fns */
|
|
159
174
|
// https://www.netlify.com/docs/functions/#event-triggered-functions
|
|
160
175
|
const [name, event] = functionToTrigger.split('-')
|
|
@@ -276,16 +276,13 @@ const link = async (options, command) => {
|
|
|
276
276
|
return exit()
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
// If already linked to site. exit and prompt for unlink
|
|
280
279
|
if (siteData) {
|
|
280
|
+
// If already linked to site. exit and prompt for unlink
|
|
281
281
|
log(`Site already linked to "${siteData.name}"`)
|
|
282
282
|
log(`Admin url: ${siteData.admin_url}`)
|
|
283
283
|
log()
|
|
284
284
|
log(`To unlink this site, run: ${chalk.cyanBright('netlify unlink')}`)
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (options.id) {
|
|
285
|
+
} else if (options.id) {
|
|
289
286
|
try {
|
|
290
287
|
// @ts-ignore types from API are wrong they cannot recognize `getSite` of API
|
|
291
288
|
siteData = await api.getSite({ site_id: options.id })
|
|
@@ -306,11 +303,7 @@ const link = async (options, command) => {
|
|
|
306
303
|
linkType: 'manual',
|
|
307
304
|
kind: 'byId',
|
|
308
305
|
})
|
|
309
|
-
|
|
310
|
-
return exit()
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (options.name) {
|
|
306
|
+
} else if (options.name) {
|
|
314
307
|
let results
|
|
315
308
|
try {
|
|
316
309
|
results = await listSites({
|
|
@@ -341,11 +334,9 @@ const link = async (options, command) => {
|
|
|
341
334
|
linkType: 'manual',
|
|
342
335
|
kind: 'byName',
|
|
343
336
|
})
|
|
344
|
-
|
|
345
|
-
|
|
337
|
+
} else {
|
|
338
|
+
siteData = await linkPrompt(command.netlify, options)
|
|
346
339
|
}
|
|
347
|
-
|
|
348
|
-
siteData = await linkPrompt(command.netlify, options)
|
|
349
340
|
return siteData
|
|
350
341
|
}
|
|
351
342
|
|
|
@@ -9,6 +9,7 @@ const { v4: uuidv4 } = require('uuid')
|
|
|
9
9
|
|
|
10
10
|
const { chalk, error, getRepoData, log, logJson, track, warn } = require('../../utils')
|
|
11
11
|
const { configureRepo } = require('../../utils/init/config')
|
|
12
|
+
const { link } = require('../link')
|
|
12
13
|
|
|
13
14
|
const SITE_NAME_SUGGESTION_SUFFIX_LENGTH = 5
|
|
14
15
|
|
|
@@ -159,6 +160,11 @@ const sitesCreate = async (options, command) => {
|
|
|
159
160
|
)
|
|
160
161
|
}
|
|
161
162
|
|
|
163
|
+
if (!options.disableLinking) {
|
|
164
|
+
log()
|
|
165
|
+
await link({ id: site.id }, command)
|
|
166
|
+
}
|
|
167
|
+
|
|
162
168
|
return site
|
|
163
169
|
}
|
|
164
170
|
|
|
@@ -172,15 +178,16 @@ const createSitesCreateCommand = (program) =>
|
|
|
172
178
|
.command('sites:create')
|
|
173
179
|
.description(
|
|
174
180
|
`Create an empty site (advanced)
|
|
175
|
-
Create a blank site that isn't associated with any git remote.
|
|
181
|
+
Create a blank site that isn't associated with any git remote. Will link the site to the current working directory.`,
|
|
176
182
|
)
|
|
177
183
|
.option('-n, --name [name]', 'name of site')
|
|
178
184
|
.option('-a, --account-slug [slug]', 'account slug to create the site under')
|
|
179
185
|
.option('-c, --with-ci', 'initialize CI hooks during site creation')
|
|
180
186
|
.option('-m, --manual', 'force manual CI setup. Used --with-ci flag')
|
|
187
|
+
.option('--disable-linking', 'create the site without linking it to current directory')
|
|
181
188
|
.addHelpText(
|
|
182
189
|
'after',
|
|
183
|
-
`Create a blank site that isn't associated with any git remote.
|
|
190
|
+
`Create a blank site that isn't associated with any git remote. Will link the site to the current working directory.`,
|
|
184
191
|
)
|
|
185
192
|
.action(sitesCreate)
|
|
186
193
|
|
|
@@ -32,6 +32,7 @@ class NetlifyFunction {
|
|
|
32
32
|
// Determines whether this is a background function based on the function
|
|
33
33
|
// name.
|
|
34
34
|
this.isBackground = name.endsWith(BACKGROUND_SUFFIX)
|
|
35
|
+
this.schedule = null
|
|
35
36
|
|
|
36
37
|
// List of the function's source files. This starts out as an empty set
|
|
37
38
|
// and will get populated on every build.
|
|
@@ -44,6 +45,12 @@ class NetlifyFunction {
|
|
|
44
45
|
return /^[A-Za-z0-9_-]+$/.test(this.name)
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
async isScheduled() {
|
|
49
|
+
await this.buildQueue
|
|
50
|
+
|
|
51
|
+
return Boolean(this.schedule)
|
|
52
|
+
}
|
|
53
|
+
|
|
47
54
|
// The `build` method transforms source files into invocable functions. Its
|
|
48
55
|
// return value is an object with:
|
|
49
56
|
//
|
|
@@ -61,12 +68,13 @@ class NetlifyFunction {
|
|
|
61
68
|
this.buildQueue = buildFunction({ cache })
|
|
62
69
|
|
|
63
70
|
try {
|
|
64
|
-
const { srcFiles, ...buildData } = await this.buildQueue
|
|
71
|
+
const { schedule, srcFiles, ...buildData } = await this.buildQueue
|
|
65
72
|
const srcFilesSet = new Set(srcFiles)
|
|
66
73
|
const srcFilesDiff = this.getSrcFilesDiff(srcFilesSet)
|
|
67
74
|
|
|
68
75
|
this.buildData = buildData
|
|
69
76
|
this.srcFiles = srcFilesSet
|
|
77
|
+
this.schedule = schedule
|
|
70
78
|
|
|
71
79
|
return { srcFilesDiff }
|
|
72
80
|
} catch (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { mkdir, writeFile } = require('fs').promises
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
|
-
const { zipFunction } = require('@netlify/zip-it-and-ship-it')
|
|
4
|
+
const { listFunction, zipFunction } = require('@netlify/zip-it-and-ship-it')
|
|
5
5
|
const decache = require('decache')
|
|
6
6
|
const readPkgUp = require('read-pkg-up')
|
|
7
7
|
const sourceMapSupport = require('source-map-support')
|
|
@@ -35,7 +35,11 @@ const buildFunction = async ({ cache, config, directory, func, hasTypeModule, pr
|
|
|
35
35
|
// root of the functions directory (e.g. `functions/my-func.js`). In
|
|
36
36
|
// this case, we use `mainFile` as the function path of `zipFunction`.
|
|
37
37
|
const entryPath = functionDirectory === directory ? func.mainFile : functionDirectory
|
|
38
|
-
const {
|
|
38
|
+
const {
|
|
39
|
+
inputs,
|
|
40
|
+
path: functionPath,
|
|
41
|
+
schedule,
|
|
42
|
+
} = await memoizedBuild({
|
|
39
43
|
cache,
|
|
40
44
|
cacheKey: `zisi-${entryPath}`,
|
|
41
45
|
command: () => zipFunction(entryPath, targetDirectory, zipOptions),
|
|
@@ -56,7 +60,22 @@ const buildFunction = async ({ cache, config, directory, func, hasTypeModule, pr
|
|
|
56
60
|
|
|
57
61
|
clearFunctionsCache(targetDirectory)
|
|
58
62
|
|
|
59
|
-
return { buildPath, srcFiles }
|
|
63
|
+
return { buildPath, srcFiles, schedule }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {object} params
|
|
68
|
+
* @param {unknown} params.config
|
|
69
|
+
* @param {string} params.mainFile
|
|
70
|
+
* @param {string} params.projectRoot
|
|
71
|
+
*/
|
|
72
|
+
const parseForSchedule = async ({ config, mainFile, projectRoot }) => {
|
|
73
|
+
const listedFunction = await listFunction(mainFile, {
|
|
74
|
+
config: netlifyConfigToZisiConfig({ config, projectRoot }),
|
|
75
|
+
parseISC: true,
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return listedFunction && listedFunction.schedule
|
|
60
79
|
}
|
|
61
80
|
|
|
62
81
|
// Clears the cache for any files inside the directory from which functions are
|
|
@@ -79,10 +98,11 @@ const getTargetDirectory = async ({ errorExit }) => {
|
|
|
79
98
|
return targetDirectory
|
|
80
99
|
}
|
|
81
100
|
|
|
101
|
+
const netlifyConfigToZisiConfig = ({ config, projectRoot }) =>
|
|
102
|
+
addFunctionsConfigDefaults(normalizeFunctionsConfig({ functionsConfig: config.functions, projectRoot }))
|
|
103
|
+
|
|
82
104
|
module.exports = async ({ config, directory, errorExit, func, projectRoot }) => {
|
|
83
|
-
const functionsConfig =
|
|
84
|
-
normalizeFunctionsConfig({ functionsConfig: config.functions, projectRoot }),
|
|
85
|
-
)
|
|
105
|
+
const functionsConfig = netlifyConfigToZisiConfig({ config, projectRoot })
|
|
86
106
|
|
|
87
107
|
const packageJson = await readPkgUp(func.mainFile)
|
|
88
108
|
const hasTypeModule = packageJson && packageJson.packageJson.type === 'module'
|
|
@@ -115,3 +135,5 @@ module.exports = async ({ config, directory, errorExit, func, projectRoot }) =>
|
|
|
115
135
|
target: targetDirectory,
|
|
116
136
|
}
|
|
117
137
|
}
|
|
138
|
+
|
|
139
|
+
module.exports.parseForSchedule = parseForSchedule
|
|
@@ -46,8 +46,9 @@ const getBuildFunction = async ({ config, directory, errorExit, func, projectRoo
|
|
|
46
46
|
// main file otherwise.
|
|
47
47
|
const functionDirectory = dirname(func.mainFile)
|
|
48
48
|
const srcFiles = functionDirectory === directory ? [func.mainFile] : [functionDirectory]
|
|
49
|
+
const schedule = await detectZisiBuilder.parseForSchedule({ mainFile: func.mainFile, config, projectRoot })
|
|
49
50
|
|
|
50
|
-
return () => ({ srcFiles })
|
|
51
|
+
return () => ({ schedule, srcFiles })
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
const invokeFunction = async ({ context, event, func, timeout }) => {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const ansi2html = require('ansi2html')
|
|
2
|
+
|
|
3
|
+
const { CLOCKWORK_USERAGENT } = require('../../utils')
|
|
4
|
+
|
|
5
|
+
const { formatLambdaError } = require('./utils')
|
|
6
|
+
|
|
7
|
+
const buildHelpResponse = ({ error, headers, path, result }) => {
|
|
8
|
+
const acceptsHtml = headers.accept && headers.accept.includes('text/html')
|
|
9
|
+
|
|
10
|
+
const paragraph = (text) => {
|
|
11
|
+
text = text.trim()
|
|
12
|
+
|
|
13
|
+
if (acceptsHtml) {
|
|
14
|
+
return ansi2html(`<p>${text}</p>`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
text = text
|
|
18
|
+
.replace(/<pre><code>/gm, '```\n')
|
|
19
|
+
.replace(/<\/code><\/pre>/gm, '\n```')
|
|
20
|
+
.replace(/<code>/gm, '`')
|
|
21
|
+
.replace(/<\/code>/gm, '`')
|
|
22
|
+
|
|
23
|
+
return `${text}\n\n`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isSimulatedRequest = headers['user-agent'] === CLOCKWORK_USERAGENT
|
|
27
|
+
|
|
28
|
+
let message = ''
|
|
29
|
+
|
|
30
|
+
if (!isSimulatedRequest) {
|
|
31
|
+
message += paragraph(`
|
|
32
|
+
You performed an HTTP request to <code>${path}</code>, which is a scheduled function.
|
|
33
|
+
You can do this to test your functions locally, but it won't work in production.
|
|
34
|
+
`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (error) {
|
|
38
|
+
message += paragraph(`
|
|
39
|
+
There was an error during execution of your scheduled function:
|
|
40
|
+
|
|
41
|
+
<pre><code>${formatLambdaError(error)}</code></pre>`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (result) {
|
|
45
|
+
// lambda emulator adds level field, which isn't user-provided
|
|
46
|
+
const returnValue = { ...result }
|
|
47
|
+
delete returnValue.level
|
|
48
|
+
|
|
49
|
+
const { statusCode } = returnValue
|
|
50
|
+
if (statusCode >= 500) {
|
|
51
|
+
message += paragraph(`
|
|
52
|
+
Your function returned a status code of <code>${statusCode}</code>.
|
|
53
|
+
At the moment, Netlify does nothing about that. In the future, there might be a retry mechanism based on this.
|
|
54
|
+
`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const allowedKeys = new Set(['statusCode'])
|
|
58
|
+
const returnedKeys = Object.keys(returnValue)
|
|
59
|
+
const ignoredKeys = returnedKeys.filter((key) => !allowedKeys.has(key))
|
|
60
|
+
|
|
61
|
+
if (ignoredKeys.length !== 0) {
|
|
62
|
+
message += paragraph(
|
|
63
|
+
`Your function returned ${ignoredKeys
|
|
64
|
+
.map((key) => `<code>${key}</code>`)
|
|
65
|
+
.join(', ')}. Is this an accident? It won't be interpreted by Netlify.`,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const statusCode = error ? 500 : 200
|
|
71
|
+
return acceptsHtml
|
|
72
|
+
? {
|
|
73
|
+
statusCode,
|
|
74
|
+
contentType: 'text/html',
|
|
75
|
+
message: `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">\n
|
|
76
|
+
${message}`,
|
|
77
|
+
}
|
|
78
|
+
: {
|
|
79
|
+
statusCode,
|
|
80
|
+
contentType: 'text/plain',
|
|
81
|
+
message,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const handleScheduledFunction = ({ error, request, response, result }) => {
|
|
86
|
+
const { contentType, message, statusCode } = buildHelpResponse({
|
|
87
|
+
error,
|
|
88
|
+
headers: request.headers,
|
|
89
|
+
path: request.path,
|
|
90
|
+
result,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
response.status(statusCode)
|
|
94
|
+
response.set('Content-Type', contentType)
|
|
95
|
+
response.send(message)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { handleScheduledFunction, buildHelpResponse }
|
|
@@ -6,6 +6,7 @@ const { NETLIFYDEVERR, NETLIFYDEVLOG, error: errorExit, getInternalFunctionsDir,
|
|
|
6
6
|
const { handleBackgroundFunction, handleBackgroundFunctionResult } = require('./background')
|
|
7
7
|
const { createFormSubmissionHandler } = require('./form-submissions-handler')
|
|
8
8
|
const { FunctionsRegistry } = require('./registry')
|
|
9
|
+
const { handleScheduledFunction } = require('./scheduled')
|
|
9
10
|
const { handleSynchronousFunction } = require('./synchronous')
|
|
10
11
|
const { shouldBase64Encode } = require('./utils')
|
|
11
12
|
|
|
@@ -105,6 +106,15 @@ const createHandler = function ({ functionsRegistry }) {
|
|
|
105
106
|
const { error } = await func.invoke(event, clientContext)
|
|
106
107
|
|
|
107
108
|
handleBackgroundFunctionResult(functionName, error)
|
|
109
|
+
} else if (await func.isScheduled()) {
|
|
110
|
+
const { error, result } = await func.invoke(event, clientContext)
|
|
111
|
+
|
|
112
|
+
handleScheduledFunction({
|
|
113
|
+
error,
|
|
114
|
+
result,
|
|
115
|
+
request,
|
|
116
|
+
response,
|
|
117
|
+
})
|
|
108
118
|
} else {
|
|
109
119
|
const { error, result } = await func.invoke(event, clientContext)
|
|
110
120
|
|
|
@@ -29,7 +29,7 @@ const filterRelativePathItems = (items) => items.filter((part) => part !== '')
|
|
|
29
29
|
* @param {import('../base-command').BaseCommand} command
|
|
30
30
|
* @return {NetlifyGraphConfig} NetlifyGraphConfig
|
|
31
31
|
*/
|
|
32
|
-
const getNetlifyGraphConfig = async ({ command, options }) => {
|
|
32
|
+
const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
33
33
|
const { config, site } = command.netlify
|
|
34
34
|
config.dev = { ...config.dev }
|
|
35
35
|
config.build = { ...config.build }
|
|
@@ -44,11 +44,12 @@ const getNetlifyGraphConfig = async ({ command, options }) => {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** @type {Partial<import('../../utils/types').ServerSettings>} */
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
if (!settings) {
|
|
48
|
+
try {
|
|
49
|
+
settings = await detectServerSettings(devConfig, options, site.root)
|
|
50
|
+
} catch (detectServerSettingsError) {
|
|
51
|
+
error(detectServerSettingsError)
|
|
52
|
+
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
const siteRoot = [path.sep, ...filterRelativePathItems(site.root.split(path.sep))]
|
|
@@ -5,10 +5,10 @@ const getUrlPath = (functionName) => `/.netlify/functions/${functionName}`
|
|
|
5
5
|
|
|
6
6
|
const BACKGROUND = '-background'
|
|
7
7
|
|
|
8
|
-
const addFunctionProps = ({ mainFile, name, runtime }) => {
|
|
8
|
+
const addFunctionProps = ({ mainFile, name, runtime, schedule }) => {
|
|
9
9
|
const urlPath = getUrlPath(name)
|
|
10
10
|
const isBackground = name.endsWith(BACKGROUND)
|
|
11
|
-
return { mainFile, name, runtime, urlPath, isBackground }
|
|
11
|
+
return { mainFile, name, runtime, urlPath, isBackground, schedule }
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const JS = 'js'
|
|
@@ -21,7 +21,9 @@ const getFunctions = async (functionsSrcDir) => {
|
|
|
21
21
|
// performance optimization, load '@netlify/zip-it-and-ship-it' on demand
|
|
22
22
|
// eslint-disable-next-line node/global-require
|
|
23
23
|
const { listFunctions } = require('@netlify/zip-it-and-ship-it')
|
|
24
|
-
const functions = await listFunctions(functionsSrcDir
|
|
24
|
+
const functions = await listFunctions(functionsSrcDir, {
|
|
25
|
+
parseISC: true,
|
|
26
|
+
})
|
|
25
27
|
const functionsWithProps = functions.filter(({ runtime }) => runtime === JS).map((func) => addFunctionProps(func))
|
|
26
28
|
return functionsWithProps
|
|
27
29
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
const constants = require('./constants')
|
|
1
2
|
const edgeHandlers = require('./edge-handlers')
|
|
2
3
|
const functions = require('./functions')
|
|
3
4
|
const getFunctions = require('./get-functions')
|
|
4
5
|
|
|
5
6
|
module.exports = {
|
|
7
|
+
...constants,
|
|
6
8
|
...functions,
|
|
7
9
|
...edgeHandlers,
|
|
8
10
|
...getFunctions,
|