netlify-cli 8.15.0 → 8.15.4
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 +147 -153
- package/package.json +13 -15
- package/src/commands/functions/functions-invoke.js +1 -11
- package/src/functions-templates/javascript/stripe-charge/package-lock.json +7 -7
- package/src/functions-templates/javascript/stripe-subscription/package-lock.json +7 -7
- package/src/functions-templates/rust/hello-world/Cargo.toml +1 -1
- package/src/lib/functions/netlify-function.js +17 -0
- package/src/lib/functions/server.js +23 -2
- package/src/lib/one-graph/cli-client.js +4 -4
- package/src/lib/one-graph/cli-netlify-graph.js +171 -27
- package/src/utils/functions/get-functions.js +9 -1
- package/src/utils/init/utils.js +2 -2
- package/src/utils/rules-proxy.js +8 -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.15.
|
|
4
|
+
"version": "8.15.4",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"Mathias Biilmann <matt@netlify.com> (https://twitter.com/biilmann)",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"format:check:prettier": "cross-env-shell prettier --check $npm_package_config_prettier",
|
|
56
56
|
"format:fix:prettier": "cross-env-shell prettier --write $npm_package_config_prettier",
|
|
57
57
|
"test:dev": "run-s test:init:* test:dev:*",
|
|
58
|
-
"test:ci": "run-s test:ci:*",
|
|
59
58
|
"test:init": "run-s test:init:*",
|
|
60
59
|
"test:init:cli-version": "npm run start -- --version",
|
|
61
60
|
"test:init:cli-help": "npm run start -- --help",
|
|
62
|
-
"test:init:eleventy-deps": "npm ci --prefix tests/eleventy-site --no-audit",
|
|
63
|
-
"test:init:hugo-deps": "npm ci --prefix tests/hugo-site --no-audit",
|
|
61
|
+
"test:init:eleventy-deps": "npm ci --prefix tests/integration/eleventy-site --no-audit",
|
|
62
|
+
"test:init:hugo-deps": "npm ci --prefix tests/integration/hugo-site --no-audit",
|
|
64
63
|
"test:dev:ava": "ava --verbose",
|
|
65
|
-
"test:ci:ava": "c8 -r json ava",
|
|
64
|
+
"test:ci:ava:unit": "c8 -r json ava --no-worker-threads tests/unit/**/*.test.js tools/**/*.test.js",
|
|
65
|
+
"test:ci:ava:integration": "c8 -r json ava --concurrency 1 --no-worker-threads tests/integration/**/*.test.js",
|
|
66
66
|
"test:affected": "node ./tools/affected-test.js",
|
|
67
67
|
"e2e": "node ./tools/e2e/run.mjs",
|
|
68
|
-
"docs": "node ./site/scripts/docs.
|
|
68
|
+
"docs": "node ./site/scripts/docs.mjs",
|
|
69
69
|
"watch": "c8 --reporter=lcov ava --watch",
|
|
70
70
|
"site:build": "run-s site:build:*",
|
|
71
71
|
"site:build:install": "cd site && npm ci --no-audit",
|
|
@@ -77,14 +77,14 @@
|
|
|
77
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
|
-
"@netlify/build": "^26.2.
|
|
80
|
+
"@netlify/build": "^26.2.3",
|
|
81
81
|
"@netlify/config": "^17.0.6",
|
|
82
82
|
"@netlify/framework-info": "^9.0.0",
|
|
83
83
|
"@netlify/local-functions-proxy": "^1.1.1",
|
|
84
84
|
"@netlify/plugin-edge-handlers": "^3.0.4",
|
|
85
|
-
"@netlify/plugins-list": "^6.
|
|
85
|
+
"@netlify/plugins-list": "^6.6.0",
|
|
86
86
|
"@netlify/routing-local-proxy": "^0.34.1",
|
|
87
|
-
"@netlify/zip-it-and-ship-it": "^5.5.
|
|
87
|
+
"@netlify/zip-it-and-ship-it": "^5.5.2",
|
|
88
88
|
"@octokit/rest": "^18.0.0",
|
|
89
89
|
"@sindresorhus/slugify": "^1.1.0",
|
|
90
90
|
"ansi-escapes": "^5.0.0",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"is-wsl": "^2.2.0",
|
|
138
138
|
"isexe": "^2.0.0",
|
|
139
139
|
"jwt-decode": "^3.0.0",
|
|
140
|
-
"lambda-local": "2.0.
|
|
140
|
+
"lambda-local": "2.0.1",
|
|
141
141
|
"listr": "^0.14.3",
|
|
142
142
|
"locate-path": "^6.0.0",
|
|
143
143
|
"lodash": "^4.17.20",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
"multiparty": "^4.2.1",
|
|
149
149
|
"netlify": "^10.1.2",
|
|
150
150
|
"netlify-headers-parser": "^6.0.1",
|
|
151
|
-
"netlify-onegraph-internal": "0.0.
|
|
151
|
+
"netlify-onegraph-internal": "0.0.18",
|
|
152
152
|
"netlify-redirect-parser": "^13.0.1",
|
|
153
153
|
"netlify-redirector": "^0.2.1",
|
|
154
154
|
"node-fetch": "^2.6.0",
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"proxyquire": "^2.1.3",
|
|
204
204
|
"seedrandom": "^3.0.5",
|
|
205
205
|
"serialize-javascript": "^6.0.0",
|
|
206
|
-
"sinon": "^
|
|
206
|
+
"sinon": "^13.0.0",
|
|
207
207
|
"sort-on": "^4.1.0",
|
|
208
208
|
"strip-ansi": "^6.0.0",
|
|
209
209
|
"supertest": "^6.1.6",
|
|
@@ -215,10 +215,8 @@
|
|
|
215
215
|
},
|
|
216
216
|
"ava": {
|
|
217
217
|
"files": [
|
|
218
|
-
"site/**/*.test.js",
|
|
219
|
-
"src/**/*.test.js",
|
|
220
218
|
"tools/**/*.test.js",
|
|
221
|
-
"tests
|
|
219
|
+
"tests/**/*.test.js"
|
|
222
220
|
],
|
|
223
221
|
"cache": true,
|
|
224
222
|
"concurrency": 5,
|
|
@@ -3,7 +3,6 @@ const fs = require('fs')
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const process = require('process')
|
|
5
5
|
|
|
6
|
-
const CronParser = require('cron-parser')
|
|
7
6
|
const inquirer = require('inquirer')
|
|
8
7
|
const fetch = require('node-fetch')
|
|
9
8
|
|
|
@@ -131,13 +130,6 @@ const getFunctionToTrigger = function (options, argumentName) {
|
|
|
131
130
|
return argumentName
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
const getNextRun = function (schedule) {
|
|
135
|
-
const cron = CronParser.parseExpression(schedule, {
|
|
136
|
-
tz: 'Etc/UTC',
|
|
137
|
-
})
|
|
138
|
-
return cron.next().toDate()
|
|
139
|
-
}
|
|
140
|
-
|
|
141
133
|
/**
|
|
142
134
|
* The functions:invoke command
|
|
143
135
|
* @param {string} nameArgument
|
|
@@ -156,7 +148,7 @@ const functionsInvoke = async (nameArgument, options, command) => {
|
|
|
156
148
|
console.warn(`${NETLIFYDEVWARN} "port" flag was not specified. Attempting to connect to localhost:8888 by default`)
|
|
157
149
|
const port = options.port || DEFAULT_PORT
|
|
158
150
|
|
|
159
|
-
const functions = await getFunctions(functionsDir)
|
|
151
|
+
const functions = await getFunctions(functionsDir, config)
|
|
160
152
|
const functionToTrigger = await getNameFromArgs(functions, options, nameArgument)
|
|
161
153
|
const functionObj = functions.find((func) => func.name === functionToTrigger)
|
|
162
154
|
|
|
@@ -164,10 +156,8 @@ const functionsInvoke = async (nameArgument, options, command) => {
|
|
|
164
156
|
let body = {}
|
|
165
157
|
|
|
166
158
|
if (functionObj.schedule) {
|
|
167
|
-
body.next_run = getNextRun(functionObj.schedule)
|
|
168
159
|
headers = {
|
|
169
160
|
'user-agent': CLOCKWORK_USERAGENT,
|
|
170
|
-
'X-NF-Event': 'schedule',
|
|
171
161
|
}
|
|
172
162
|
} else if (eventTriggeredFunctions.has(functionToTrigger)) {
|
|
173
163
|
/** handle event triggered fns */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"stripe": "^8.
|
|
12
|
+
"stripe": "^8.201.0"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"node_modules/@types/node": {
|
|
@@ -105,9 +105,9 @@
|
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
107
|
"node_modules/stripe": {
|
|
108
|
-
"version": "8.
|
|
109
|
-
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.
|
|
110
|
-
"integrity": "sha512-
|
|
108
|
+
"version": "8.201.0",
|
|
109
|
+
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.201.0.tgz",
|
|
110
|
+
"integrity": "sha512-pF0F1DdE9zt0U6Cb0XN+REpdFkUmaqp6C7OEVOCeUpTAafjjJqrdV/WmZd7Y5MwT8XvDAxB5/v3CAXwxAp0XNg==",
|
|
111
111
|
"dependencies": {
|
|
112
112
|
"@types/node": ">=8.1.0",
|
|
113
113
|
"qs": "^6.6.0"
|
|
@@ -184,9 +184,9 @@
|
|
|
184
184
|
}
|
|
185
185
|
},
|
|
186
186
|
"stripe": {
|
|
187
|
-
"version": "8.
|
|
188
|
-
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.
|
|
189
|
-
"integrity": "sha512-
|
|
187
|
+
"version": "8.201.0",
|
|
188
|
+
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.201.0.tgz",
|
|
189
|
+
"integrity": "sha512-pF0F1DdE9zt0U6Cb0XN+REpdFkUmaqp6C7OEVOCeUpTAafjjJqrdV/WmZd7Y5MwT8XvDAxB5/v3CAXwxAp0XNg==",
|
|
190
190
|
"requires": {
|
|
191
191
|
"@types/node": ">=8.1.0",
|
|
192
192
|
"qs": "^6.6.0"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"stripe": "^8.
|
|
12
|
+
"stripe": "^8.201.0"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"node_modules/@types/node": {
|
|
@@ -105,9 +105,9 @@
|
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
107
|
"node_modules/stripe": {
|
|
108
|
-
"version": "8.
|
|
109
|
-
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.
|
|
110
|
-
"integrity": "sha512-
|
|
108
|
+
"version": "8.201.0",
|
|
109
|
+
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.201.0.tgz",
|
|
110
|
+
"integrity": "sha512-pF0F1DdE9zt0U6Cb0XN+REpdFkUmaqp6C7OEVOCeUpTAafjjJqrdV/WmZd7Y5MwT8XvDAxB5/v3CAXwxAp0XNg==",
|
|
111
111
|
"dependencies": {
|
|
112
112
|
"@types/node": ">=8.1.0",
|
|
113
113
|
"qs": "^6.6.0"
|
|
@@ -184,9 +184,9 @@
|
|
|
184
184
|
}
|
|
185
185
|
},
|
|
186
186
|
"stripe": {
|
|
187
|
-
"version": "8.
|
|
188
|
-
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.
|
|
189
|
-
"integrity": "sha512-
|
|
187
|
+
"version": "8.201.0",
|
|
188
|
+
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.201.0.tgz",
|
|
189
|
+
"integrity": "sha512-pF0F1DdE9zt0U6Cb0XN+REpdFkUmaqp6C7OEVOCeUpTAafjjJqrdV/WmZd7Y5MwT8XvDAxB5/v3CAXwxAp0XNg==",
|
|
190
190
|
"requires": {
|
|
191
191
|
"@types/node": ">=8.1.0",
|
|
192
192
|
"qs": "^6.6.0"
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const CronParser = require('cron-parser')
|
|
3
|
+
|
|
2
4
|
const { error: errorExit } = require('../../utils/command-helpers')
|
|
3
5
|
|
|
4
6
|
const BACKGROUND_SUFFIX = '-background'
|
|
@@ -6,6 +8,13 @@ const BACKGROUND_SUFFIX = '-background'
|
|
|
6
8
|
// Returns a new set with all elements of `setA` that don't exist in `setB`.
|
|
7
9
|
const difference = (setA, setB) => new Set([...setA].filter((item) => !setB.has(item)))
|
|
8
10
|
|
|
11
|
+
const getNextRun = function (schedule) {
|
|
12
|
+
const cron = CronParser.parseExpression(schedule, {
|
|
13
|
+
tz: 'Etc/UTC',
|
|
14
|
+
})
|
|
15
|
+
return cron.next().toDate()
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
class NetlifyFunction {
|
|
10
19
|
constructor({
|
|
11
20
|
config,
|
|
@@ -51,6 +60,14 @@ class NetlifyFunction {
|
|
|
51
60
|
return Boolean(this.schedule)
|
|
52
61
|
}
|
|
53
62
|
|
|
63
|
+
async getNextRun() {
|
|
64
|
+
if (!(await this.isScheduled())) {
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return getNextRun(this.schedule)
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
// The `build` method transforms source files into invocable functions. Its
|
|
55
72
|
// return value is an object with:
|
|
56
73
|
//
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
const jwtDecode = require('jwt-decode')
|
|
3
3
|
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
CLOCKWORK_USERAGENT,
|
|
6
|
+
NETLIFYDEVERR,
|
|
7
|
+
NETLIFYDEVLOG,
|
|
8
|
+
error: errorExit,
|
|
9
|
+
getInternalFunctionsDir,
|
|
10
|
+
log,
|
|
11
|
+
} = require('../../utils')
|
|
5
12
|
|
|
6
13
|
const { handleBackgroundFunction, handleBackgroundFunctionResult } = require('./background')
|
|
7
14
|
const { createFormSubmissionHandler } = require('./form-submissions-handler')
|
|
@@ -107,7 +114,21 @@ const createHandler = function ({ functionsRegistry }) {
|
|
|
107
114
|
|
|
108
115
|
handleBackgroundFunctionResult(functionName, error)
|
|
109
116
|
} else if (await func.isScheduled()) {
|
|
110
|
-
const { error, result } = await func.invoke(
|
|
117
|
+
const { error, result } = await func.invoke(
|
|
118
|
+
{
|
|
119
|
+
...event,
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
next_run: await func.getNextRun(),
|
|
122
|
+
}),
|
|
123
|
+
isBase64Encoded: false,
|
|
124
|
+
headers: {
|
|
125
|
+
...event.headers,
|
|
126
|
+
'user-agent': CLOCKWORK_USERAGENT,
|
|
127
|
+
'X-NF-Event': 'schedule',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
clientContext,
|
|
131
|
+
)
|
|
111
132
|
|
|
112
133
|
handleScheduledFunction({
|
|
113
134
|
error,
|
|
@@ -138,9 +138,9 @@ const refetchAndGenerateFromOneGraph = async (input) => {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
const parsedDoc = parse(currentOperationsDoc)
|
|
141
|
-
const
|
|
141
|
+
const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
|
|
142
142
|
|
|
143
|
-
generateFunctionsFile(netlifyGraphConfig, schema, currentOperationsDoc,
|
|
143
|
+
generateFunctionsFile({ netlifyGraphConfig, schema, operationsDoc: currentOperationsDoc, functions, fragments })
|
|
144
144
|
writeGraphQLSchemaFile(netlifyGraphConfig, schema)
|
|
145
145
|
state.set('oneGraphEnabledServices', enabledServices)
|
|
146
146
|
}
|
|
@@ -170,8 +170,8 @@ const updateGraphQLOperationsFile = async (input) => {
|
|
|
170
170
|
const parsedDoc = parse(appOperationsDoc, {
|
|
171
171
|
noLocation: true,
|
|
172
172
|
})
|
|
173
|
-
const
|
|
174
|
-
generateFunctionsFile(netlifyGraphConfig, schema, appOperationsDoc,
|
|
173
|
+
const { fragments, functions } = extractFunctionsFromOperationDoc(parsedDoc)
|
|
174
|
+
generateFunctionsFile({ netlifyGraphConfig, schema, operationsDoc: appOperationsDoc, functions, fragments })
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
const handleCliSessionEvent = async ({ event, netlifyGraphConfig, netlifyToken, schema, siteId }) => {
|
|
@@ -24,6 +24,105 @@ InternalConsole.registerConsole(internalConsole)
|
|
|
24
24
|
*/
|
|
25
25
|
const filterRelativePathItems = (items) => items.filter((part) => part !== '')
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Return the default Netlify Graph configuration for a generic site
|
|
29
|
+
* @param {object} context
|
|
30
|
+
* @param {string[]} context.detectedFunctionsPath
|
|
31
|
+
* @param {string[]} context.siteRoot
|
|
32
|
+
*/
|
|
33
|
+
const makeDefaultNetlifGraphConfig = ({ baseConfig, detectedFunctionsPath }) => {
|
|
34
|
+
const functionsPath = filterRelativePathItems([...detectedFunctionsPath])
|
|
35
|
+
const webhookBasePath = '/.netlify/functions'
|
|
36
|
+
const netlifyGraphPath = [...functionsPath, 'netlifyGraph']
|
|
37
|
+
const netlifyGraphImplementationFilename = [...netlifyGraphPath, `index.${baseConfig.extension}`]
|
|
38
|
+
const netlifyGraphTypeDefinitionsFilename = [...netlifyGraphPath, `index.d.ts`]
|
|
39
|
+
const graphQLOperationsSourceFilename = [...netlifyGraphPath, NetlifyGraph.defaultSourceOperationsFilename]
|
|
40
|
+
const graphQLSchemaFilename = [...netlifyGraphPath, NetlifyGraph.defaultGraphQLSchemaFilename]
|
|
41
|
+
const netlifyGraphRequirePath = [`./netlifyGraph`]
|
|
42
|
+
const moduleType = baseConfig.moduleType || 'esm'
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
functionsPath,
|
|
46
|
+
webhookBasePath,
|
|
47
|
+
netlifyGraphPath,
|
|
48
|
+
netlifyGraphImplementationFilename,
|
|
49
|
+
netlifyGraphTypeDefinitionsFilename,
|
|
50
|
+
graphQLOperationsSourceFilename,
|
|
51
|
+
graphQLSchemaFilename,
|
|
52
|
+
netlifyGraphRequirePath,
|
|
53
|
+
moduleType,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Return the default Netlify Graph configuration for a Nextjs site
|
|
59
|
+
* @param {object} context
|
|
60
|
+
* @param {string[]} context.detectedFunctionsPath
|
|
61
|
+
* @param {string[]} context.siteRoot
|
|
62
|
+
*/
|
|
63
|
+
const makeDefaultNextJsNetlifGraphConfig = ({ baseConfig, siteRoot }) => {
|
|
64
|
+
const functionsPath = filterRelativePathItems([...siteRoot, 'pages', 'api'])
|
|
65
|
+
const webhookBasePath = '/api'
|
|
66
|
+
const netlifyGraphPath = filterRelativePathItems([...siteRoot, 'lib', 'netlifyGraph'])
|
|
67
|
+
const netlifyGraphImplementationFilename = [...netlifyGraphPath, `index.${baseConfig.extension}`]
|
|
68
|
+
const netlifyGraphTypeDefinitionsFilename = [...netlifyGraphPath, `index.d.ts`]
|
|
69
|
+
const graphQLOperationsSourceFilename = [...netlifyGraphPath, NetlifyGraph.defaultSourceOperationsFilename]
|
|
70
|
+
const graphQLSchemaFilename = [...netlifyGraphPath, NetlifyGraph.defaultGraphQLSchemaFilename]
|
|
71
|
+
const netlifyGraphRequirePath = ['..', '..', 'lib', 'netlifyGraph']
|
|
72
|
+
const moduleType = baseConfig.moduleType || 'esm'
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
functionsPath,
|
|
76
|
+
webhookBasePath,
|
|
77
|
+
netlifyGraphPath,
|
|
78
|
+
netlifyGraphImplementationFilename,
|
|
79
|
+
netlifyGraphTypeDefinitionsFilename,
|
|
80
|
+
graphQLOperationsSourceFilename,
|
|
81
|
+
graphQLSchemaFilename,
|
|
82
|
+
netlifyGraphRequirePath,
|
|
83
|
+
moduleType,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Return the default Netlify Graph configuration for a Remix site
|
|
89
|
+
* @param {object} context
|
|
90
|
+
* @param {string[]} context.detectedFunctionsPath
|
|
91
|
+
* @param {string[]} context.siteRoot
|
|
92
|
+
*/
|
|
93
|
+
const makeDefaultRemixNetlifGraphConfig = ({ baseConfig, detectedFunctionsPath, siteRoot }) => {
|
|
94
|
+
const functionsPath = filterRelativePathItems([...detectedFunctionsPath])
|
|
95
|
+
const webhookBasePath = '/webhooks'
|
|
96
|
+
const netlifyGraphPath = filterRelativePathItems([
|
|
97
|
+
...siteRoot,
|
|
98
|
+
...NetlifyGraph.defaultNetlifyGraphConfig.netlifyGraphPath,
|
|
99
|
+
])
|
|
100
|
+
const netlifyGraphImplementationFilename = [...netlifyGraphPath, `index.${baseConfig.extension}`]
|
|
101
|
+
const netlifyGraphTypeDefinitionsFilename = [...netlifyGraphPath, `index.d.ts`]
|
|
102
|
+
const graphQLOperationsSourceFilename = [...netlifyGraphPath, NetlifyGraph.defaultSourceOperationsFilename]
|
|
103
|
+
const graphQLSchemaFilename = [...netlifyGraphPath, NetlifyGraph.defaultGraphQLSchemaFilename]
|
|
104
|
+
const netlifyGraphRequirePath = [`../../netlify/functions/netlifyGraph`]
|
|
105
|
+
const moduleType = 'esm'
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
functionsPath,
|
|
109
|
+
webhookBasePath,
|
|
110
|
+
netlifyGraphPath,
|
|
111
|
+
netlifyGraphImplementationFilename,
|
|
112
|
+
netlifyGraphTypeDefinitionsFilename,
|
|
113
|
+
graphQLOperationsSourceFilename,
|
|
114
|
+
graphQLSchemaFilename,
|
|
115
|
+
netlifyGraphRequirePath,
|
|
116
|
+
moduleType,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const defaultFrameworkLookup = {
|
|
121
|
+
'Next.js': makeDefaultNextJsNetlifGraphConfig,
|
|
122
|
+
Remix: makeDefaultRemixNetlifGraphConfig,
|
|
123
|
+
default: makeDefaultNetlifGraphConfig,
|
|
124
|
+
}
|
|
125
|
+
|
|
27
126
|
/**
|
|
28
127
|
* Return a full NetlifyGraph config with any defaults overridden by netlify.toml
|
|
29
128
|
* @param {import('../base-command').BaseCommand} command
|
|
@@ -48,7 +147,8 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
48
147
|
try {
|
|
49
148
|
settings = await detectServerSettings(devConfig, options, site.root)
|
|
50
149
|
} catch (detectServerSettingsError) {
|
|
51
|
-
|
|
150
|
+
settings = {}
|
|
151
|
+
warn('Error while auto-detecting project settings, Netlify Graph encounter problems', detectServerSettingsError)
|
|
52
152
|
}
|
|
53
153
|
}
|
|
54
154
|
|
|
@@ -58,26 +158,55 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
58
158
|
const autodetectedLanguage = fs.existsSync(tsConfig) ? 'typescript' : 'javascript'
|
|
59
159
|
|
|
60
160
|
const framework = settings.framework || userSpecifiedConfig.framework
|
|
61
|
-
const
|
|
161
|
+
const makeDefaultFrameworkConfig = defaultFrameworkLookup[framework] || defaultFrameworkLookup.default
|
|
162
|
+
|
|
62
163
|
const detectedFunctionsPathString = getFunctionsDir({ config, options })
|
|
63
|
-
const detectedFunctionsPath = detectedFunctionsPathString
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
isNextjs
|
|
67
|
-
? [...siteRoot, 'lib', 'netlifyGraph']
|
|
68
|
-
: [...siteRoot, ...NetlifyGraph.defaultNetlifyGraphConfig.netlifyGraphPath],
|
|
69
|
-
)
|
|
164
|
+
const detectedFunctionsPath = detectedFunctionsPathString
|
|
165
|
+
? [path.sep, ...detectedFunctionsPathString.split(path.sep)]
|
|
166
|
+
: null
|
|
70
167
|
const baseConfig = { ...NetlifyGraph.defaultNetlifyGraphConfig, ...userSpecifiedConfig }
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
168
|
+
const defaultFrameworkConfig = makeDefaultFrameworkConfig({ baseConfig, detectedFunctionsPath, siteRoot })
|
|
169
|
+
|
|
170
|
+
const functionsPath =
|
|
171
|
+
(userSpecifiedConfig.functionsPath && userSpecifiedConfig.functionsPath.split(path.sep)) ||
|
|
172
|
+
defaultFrameworkConfig.functionsPath
|
|
173
|
+
const netlifyGraphPath =
|
|
174
|
+
(userSpecifiedConfig.netlifyGraphPath && userSpecifiedConfig.netlifyGraphPath.split(path.sep)) ||
|
|
175
|
+
defaultFrameworkConfig.netlifyGraphPath
|
|
176
|
+
const netlifyGraphImplementationFilename =
|
|
177
|
+
(userSpecifiedConfig.netlifyGraphImplementationFilename &&
|
|
178
|
+
userSpecifiedConfig.netlifyGraphImplementationFilename.split(path.sep)) ||
|
|
179
|
+
defaultFrameworkConfig.netlifyGraphImplementationFilename
|
|
180
|
+
const netlifyGraphTypeDefinitionsFilename =
|
|
181
|
+
(userSpecifiedConfig.netlifyGraphTypeDefinitionsFilename &&
|
|
182
|
+
userSpecifiedConfig.netlifyGraphTypeDefinitionsFilename.split(path.sep)) ||
|
|
183
|
+
defaultFrameworkConfig.netlifyGraphTypeDefinitionsFilename
|
|
184
|
+
const graphQLOperationsSourceFilename =
|
|
185
|
+
(userSpecifiedConfig.graphQLOperationsSourceFilename &&
|
|
186
|
+
userSpecifiedConfig.graphQLOperationsSourceFilename.split(path.sep)) ||
|
|
187
|
+
defaultFrameworkConfig.graphQLOperationsSourceFilename
|
|
188
|
+
const graphQLSchemaFilename =
|
|
189
|
+
(userSpecifiedConfig.graphQLSchemaFilename && userSpecifiedConfig.graphQLSchemaFilename.split(path.sep)) ||
|
|
190
|
+
defaultFrameworkConfig.graphQLSchemaFilename
|
|
191
|
+
const netlifyGraphRequirePath =
|
|
192
|
+
(userSpecifiedConfig.netlifyGraphRequirePath && userSpecifiedConfig.netlifyGraphRequirePath.split(path.sep)) ||
|
|
193
|
+
defaultFrameworkConfig.netlifyGraphRequirePath
|
|
194
|
+
const moduleType =
|
|
195
|
+
(userSpecifiedConfig.moduleType && userSpecifiedConfig.moduleType.split(path.sep)) ||
|
|
196
|
+
defaultFrameworkConfig.moduleType
|
|
197
|
+
const language =
|
|
198
|
+
(userSpecifiedConfig.language && userSpecifiedConfig.language.split(path.sep)) || autodetectedLanguage
|
|
199
|
+
const webhookBasePath =
|
|
200
|
+
(userSpecifiedConfig.webhookBasePath && userSpecifiedConfig.webhookBasePath.split(path.sep)) ||
|
|
201
|
+
defaultFrameworkConfig.webhookBasePath
|
|
202
|
+
const customGeneratorFile =
|
|
203
|
+
userSpecifiedConfig.customGeneratorFile && userSpecifiedConfig.customGeneratorFile.split(path.sep)
|
|
204
|
+
const runtimeTargetEnv = userSpecifiedConfig.runtimeTargetEnv || defaultFrameworkConfig.runtimeTargetEnv || 'node'
|
|
205
|
+
|
|
78
206
|
const fullConfig = {
|
|
79
207
|
...baseConfig,
|
|
80
208
|
functionsPath,
|
|
209
|
+
webhookBasePath,
|
|
81
210
|
netlifyGraphPath,
|
|
82
211
|
netlifyGraphImplementationFilename,
|
|
83
212
|
netlifyGraphTypeDefinitionsFilename,
|
|
@@ -87,6 +216,8 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
87
216
|
framework,
|
|
88
217
|
language,
|
|
89
218
|
moduleType,
|
|
219
|
+
customGeneratorFile,
|
|
220
|
+
runtimeTargetEnv,
|
|
90
221
|
}
|
|
91
222
|
|
|
92
223
|
return fullConfig
|
|
@@ -97,7 +228,8 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
|
|
|
97
228
|
* @param {NetlifyGraphConfig} netlifyGraphConfig
|
|
98
229
|
*/
|
|
99
230
|
const ensureNetlifyGraphPath = (netlifyGraphConfig) => {
|
|
100
|
-
|
|
231
|
+
const fullPath = path.resolve(...netlifyGraphConfig.netlifyGraphPath)
|
|
232
|
+
fs.mkdirSync(fullPath, { recursive: true })
|
|
101
233
|
}
|
|
102
234
|
|
|
103
235
|
/**
|
|
@@ -105,22 +237,27 @@ const ensureNetlifyGraphPath = (netlifyGraphConfig) => {
|
|
|
105
237
|
* @param {NetlifyGraphConfig} netlifyGraphConfig
|
|
106
238
|
*/
|
|
107
239
|
const ensureFunctionsPath = (netlifyGraphConfig) => {
|
|
108
|
-
|
|
240
|
+
const fullPath = path.resolve(...netlifyGraphConfig.functionsPath)
|
|
241
|
+
fs.mkdirSync(fullPath, { recursive: true })
|
|
109
242
|
}
|
|
110
243
|
|
|
111
244
|
/**
|
|
112
245
|
* Generate a library file with type definitions for a given NetlifyGraphConfig, operationsDoc, and schema, writing them to the filesystem
|
|
113
|
-
* @param {
|
|
114
|
-
* @param {
|
|
115
|
-
* @param {
|
|
116
|
-
* @param {
|
|
246
|
+
* @param {object} context
|
|
247
|
+
* @param {NetlifyGraphConfig} context.netlifyGraphConfig
|
|
248
|
+
* @param {GraphQLSchema} context.schema The schema to use when generating the functions and their types
|
|
249
|
+
* @param {string} context.operationsDoc The GraphQL operations doc to use when generating the functions
|
|
250
|
+
* @param {NetlifyGraph.ParsedFunction} context.functions The parsed queries with metadata to use when generating library functions
|
|
251
|
+
* @param {NetlifyGraph.ParsedFragment} context.fragments The parsed queries with metadata to use when generating library functions
|
|
252
|
+
* @returns {void} Void, effectfully writes the generated library to the filesystem
|
|
117
253
|
*/
|
|
118
|
-
const generateFunctionsFile = (
|
|
254
|
+
const generateFunctionsFile = ({ fragments, functions, netlifyGraphConfig, operationsDoc, schema }) => {
|
|
119
255
|
const { clientSource, typeDefinitionsSource } = NetlifyGraph.generateFunctionsSource(
|
|
120
256
|
netlifyGraphConfig,
|
|
121
257
|
schema,
|
|
122
258
|
operationsDoc,
|
|
123
|
-
|
|
259
|
+
functions,
|
|
260
|
+
fragments,
|
|
124
261
|
)
|
|
125
262
|
|
|
126
263
|
ensureNetlifyGraphPath(netlifyGraphConfig)
|
|
@@ -199,13 +336,15 @@ const generateHandler = (netlifyGraphConfig, schema, operationId, handlerOptions
|
|
|
199
336
|
currentOperationsDoc = NetlifyGraph.defaultExampleOperationsDoc
|
|
200
337
|
}
|
|
201
338
|
|
|
202
|
-
const
|
|
339
|
+
const payload = {
|
|
203
340
|
handlerOptions,
|
|
204
341
|
schema,
|
|
205
342
|
netlifyGraphConfig,
|
|
206
343
|
operationId,
|
|
207
344
|
operationsDoc: currentOperationsDoc,
|
|
208
|
-
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const result = NetlifyGraph.generateHandlerSource(payload)
|
|
209
348
|
|
|
210
349
|
if (!result) {
|
|
211
350
|
warn(`No handler was generated for operationId ${operationId}`)
|
|
@@ -237,6 +376,11 @@ const generateHandler = (netlifyGraphConfig, schema, operationId, handlerOptions
|
|
|
237
376
|
filenameArr = [path.sep, ...netlifyGraphConfig.functionsPath, baseFilename]
|
|
238
377
|
}
|
|
239
378
|
|
|
379
|
+
const parentDir = path.resolve(...filterRelativePathItems(filenameArr.slice(0, -1)))
|
|
380
|
+
|
|
381
|
+
// Make sure the parent directory exists
|
|
382
|
+
fs.mkdirSync(parentDir, { recursive: true })
|
|
383
|
+
|
|
240
384
|
const absoluteFilename = path.resolve(...filenameArr)
|
|
241
385
|
|
|
242
386
|
fs.writeFileSync(absoluteFilename, content)
|
|
@@ -254,7 +398,7 @@ const { buildSchema, parse } = GraphQL
|
|
|
254
398
|
* @returns {string} The url to the Netlify Graph UI for the current session
|
|
255
399
|
*/
|
|
256
400
|
const getGraphEditUrlBySiteName = ({ oneGraphSessionId, siteName }) => {
|
|
257
|
-
const host = 'app.netlify.com'
|
|
401
|
+
const host = process.env.NETLIFY_APP_HOST || 'app.netlify.com'
|
|
258
402
|
// http because app.netlify.com will redirect to https, and localhost will still work for development
|
|
259
403
|
const url = `http://${host}/sites/${siteName}/graph/explorer?cliSessionId=${oneGraphSessionId}`
|
|
260
404
|
|
|
@@ -13,7 +13,14 @@ const addFunctionProps = ({ mainFile, name, runtime, schedule }) => {
|
|
|
13
13
|
|
|
14
14
|
const JS = 'js'
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* @param {Record<string, { schedule?: string }>} functionConfigRecord
|
|
18
|
+
* @returns {Record<string, { schedule?: string }>}
|
|
19
|
+
*/
|
|
20
|
+
const extractSchedule = (functionConfigRecord) =>
|
|
21
|
+
Object.fromEntries(Object.entries(functionConfigRecord).map(([name, { schedule }]) => [name, { schedule }]))
|
|
22
|
+
|
|
23
|
+
const getFunctions = async (functionsSrcDir, config = {}) => {
|
|
17
24
|
if (!(await fileExistsAsync(functionsSrcDir))) {
|
|
18
25
|
return []
|
|
19
26
|
}
|
|
@@ -22,6 +29,7 @@ const getFunctions = async (functionsSrcDir) => {
|
|
|
22
29
|
// eslint-disable-next-line node/global-require
|
|
23
30
|
const { listFunctions } = require('@netlify/zip-it-and-ship-it')
|
|
24
31
|
const functions = await listFunctions(functionsSrcDir, {
|
|
32
|
+
config: config.functions ? extractSchedule(config.functions) : undefined,
|
|
25
33
|
parseISC: true,
|
|
26
34
|
})
|
|
27
35
|
const functionsWithProps = functions.filter(({ runtime }) => runtime === JS).map((func) => addFunctionProps(func))
|
package/src/utils/init/utils.js
CHANGED
|
@@ -123,8 +123,8 @@ const getPromptInputs = async ({
|
|
|
123
123
|
.map(({ name }) => `${name} plugin`)
|
|
124
124
|
.map(formatTitle)
|
|
125
125
|
.join(', ')}${EOL}➡️ OK to install??`,
|
|
126
|
-
choices: infos.map((
|
|
127
|
-
default: infos.map((
|
|
126
|
+
choices: infos.map((info) => ({ name: `${info.name} plugin`, value: info.package })),
|
|
127
|
+
default: infos.map((info) => info.package),
|
|
128
128
|
},
|
|
129
129
|
]
|
|
130
130
|
}
|
package/src/utils/rules-proxy.js
CHANGED
|
@@ -11,14 +11,21 @@ const { fileExistsAsync } = require('../lib/fs')
|
|
|
11
11
|
const { NETLIFYDEVLOG } = require('./command-helpers')
|
|
12
12
|
const { parseRedirects } = require('./redirects')
|
|
13
13
|
|
|
14
|
+
const watchers = []
|
|
15
|
+
|
|
14
16
|
const onChanges = function (files, listener) {
|
|
15
17
|
files.forEach((file) => {
|
|
16
18
|
const watcher = chokidar.watch(file)
|
|
17
19
|
watcher.on('change', listener)
|
|
18
20
|
watcher.on('unlink', listener)
|
|
21
|
+
watchers.push(watcher)
|
|
19
22
|
})
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
const getWatchers = function () {
|
|
26
|
+
return watchers
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
const getLanguage = function (headers) {
|
|
23
30
|
if (headers['accept-language']) {
|
|
24
31
|
return headers['accept-language'].split(',')[0].slice(0, 2)
|
|
@@ -97,4 +104,5 @@ module.exports = {
|
|
|
97
104
|
onChanges,
|
|
98
105
|
getLanguage,
|
|
99
106
|
createRewriter,
|
|
107
|
+
getWatchers,
|
|
100
108
|
}
|