netlify-cli 8.0.13 → 8.1.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +12 -13
  2. package/bin/run +38 -2
  3. package/npm-shrinkwrap.json +260 -6244
  4. package/package.json +13 -35
  5. package/src/commands/addons/addons-auth.js +50 -0
  6. package/src/commands/addons/addons-config.js +180 -0
  7. package/src/commands/addons/addons-create.js +131 -0
  8. package/src/commands/addons/addons-delete.js +60 -0
  9. package/src/commands/addons/addons-list.js +62 -0
  10. package/src/commands/addons/addons.js +44 -0
  11. package/src/commands/addons/index.js +3 -24
  12. package/src/commands/api/api.js +75 -0
  13. package/src/commands/api/index.js +5 -0
  14. package/src/commands/base-command.js +509 -0
  15. package/src/commands/build/build.js +58 -0
  16. package/src/commands/build/index.js +3 -61
  17. package/src/commands/completion/completion.js +36 -0
  18. package/src/commands/completion/index.js +5 -0
  19. package/src/commands/{deploy.js → deploy/deploy.js} +295 -275
  20. package/src/commands/deploy/index.js +5 -0
  21. package/src/commands/dev/dev-exec.js +35 -0
  22. package/src/commands/dev/dev-trace.js +47 -0
  23. package/src/commands/dev/dev.js +340 -0
  24. package/src/commands/dev/index.js +3 -335
  25. package/src/commands/env/env-get.js +51 -0
  26. package/src/commands/env/env-import.js +93 -0
  27. package/src/commands/env/env-list.js +63 -0
  28. package/src/commands/env/env-set.js +67 -0
  29. package/src/commands/env/env-unset.js +66 -0
  30. package/src/commands/env/env.js +42 -0
  31. package/src/commands/env/index.js +3 -23
  32. package/src/commands/functions/functions-build.js +59 -0
  33. package/src/commands/functions/{create.js → functions-create.js} +130 -94
  34. package/src/commands/functions/functions-invoke.js +273 -0
  35. package/src/commands/functions/functions-list.js +106 -0
  36. package/src/commands/functions/functions-serve.js +63 -0
  37. package/src/commands/functions/functions.js +47 -0
  38. package/src/commands/functions/index.js +3 -45
  39. package/src/commands/index.js +7 -0
  40. package/src/commands/init/index.js +6 -0
  41. package/src/commands/{init.js → init/init.js} +79 -68
  42. package/src/commands/link/index.js +6 -0
  43. package/src/{utils/link/link-by-prompt.js → commands/link/link.js} +141 -14
  44. package/src/commands/lm/index.js +3 -19
  45. package/src/commands/lm/lm-info.js +42 -0
  46. package/src/commands/lm/lm-install.js +33 -0
  47. package/src/commands/lm/lm-setup.js +106 -0
  48. package/src/commands/lm/lm-uninstall.js +25 -0
  49. package/src/commands/lm/lm.js +34 -0
  50. package/src/commands/login/index.js +6 -0
  51. package/src/commands/login/login.js +55 -0
  52. package/src/commands/logout/index.js +5 -0
  53. package/src/commands/logout/logout.js +43 -0
  54. package/src/commands/main.js +188 -0
  55. package/src/commands/open/index.js +3 -39
  56. package/src/commands/open/open-admin.js +60 -0
  57. package/src/commands/open/open-site.js +53 -0
  58. package/src/commands/open/open.js +38 -0
  59. package/src/commands/sites/index.js +5 -20
  60. package/src/commands/sites/sites-create.js +187 -0
  61. package/src/commands/sites/sites-delete.js +104 -0
  62. package/src/commands/sites/sites-list.js +89 -0
  63. package/src/commands/sites/sites.js +32 -0
  64. package/src/commands/status/index.js +3 -118
  65. package/src/commands/status/status-hooks.js +69 -0
  66. package/src/commands/status/status.js +124 -0
  67. package/src/commands/switch/index.js +5 -0
  68. package/src/commands/switch/switch.js +50 -0
  69. package/src/commands/unlink/index.js +5 -0
  70. package/src/commands/unlink/unlink.js +48 -0
  71. package/src/commands/watch/index.js +5 -0
  72. package/src/commands/watch/watch.js +121 -0
  73. package/src/lib/build.js +21 -7
  74. package/src/lib/exec-fetcher.js +5 -3
  75. package/src/lib/fs.js +54 -36
  76. package/src/lib/functions/background.js +1 -1
  77. package/src/lib/functions/form-submissions-handler.js +2 -1
  78. package/src/lib/functions/local-proxy.js +2 -1
  79. package/src/lib/functions/netlify-function.js +4 -1
  80. package/src/lib/functions/registry.js +4 -6
  81. package/src/lib/functions/runtimes/go/index.js +2 -1
  82. package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +6 -4
  83. package/src/lib/functions/runtimes/js/builders/zisi.js +3 -3
  84. package/src/lib/functions/runtimes/rust/index.js +4 -3
  85. package/src/lib/functions/server.js +2 -3
  86. package/src/lib/functions/synchronous.js +2 -1
  87. package/src/lib/functions/utils.js +2 -3
  88. package/src/lib/functions/watcher.js +1 -0
  89. package/src/lib/http-agent.js +5 -5
  90. package/src/lib/log.js +2 -1
  91. package/src/lib/spinner.js +22 -0
  92. package/src/utils/addons/diffs/index.js +1 -0
  93. package/src/utils/addons/diffs/options.js +3 -1
  94. package/src/utils/addons/prepare.js +13 -6
  95. package/src/utils/addons/prompts.js +2 -1
  96. package/src/utils/addons/render.js +3 -1
  97. package/src/utils/command-helpers.js +116 -43
  98. package/src/utils/create-stream-promise.js +5 -5
  99. package/src/utils/deferred.js +1 -0
  100. package/src/utils/deploy/deploy-site.js +1 -1
  101. package/src/utils/deploy/index.js +4 -0
  102. package/src/utils/detect-server-settings.js +10 -12
  103. package/src/utils/dev.js +18 -10
  104. package/src/utils/dot-env.js +4 -2
  105. package/src/utils/{edge-handlers.js → functions/edge-handlers.js} +8 -7
  106. package/src/utils/functions/functions.js +36 -0
  107. package/src/utils/{get-functions.js → functions/get-functions.js} +2 -1
  108. package/src/utils/functions/index.js +8 -26
  109. package/src/utils/get-global-config.js +3 -2
  110. package/src/utils/get-repo-data.js +1 -0
  111. package/src/utils/gh-auth.js +1 -0
  112. package/src/utils/gitignore.js +7 -5
  113. package/src/utils/headers.js +1 -2
  114. package/src/utils/index.js +42 -0
  115. package/src/utils/init/config-github.js +12 -5
  116. package/src/utils/init/config-manual.js +9 -2
  117. package/src/utils/init/config.js +13 -7
  118. package/src/utils/init/frameworks.js +1 -0
  119. package/src/utils/init/node-version.js +4 -2
  120. package/src/utils/init/plugins.js +2 -4
  121. package/src/utils/init/utils.js +10 -6
  122. package/src/utils/live-tunnel.js +3 -4
  123. package/src/utils/lm/install.js +10 -15
  124. package/src/utils/lm/requirements.js +3 -1
  125. package/src/utils/lm/steps.js +1 -1
  126. package/src/utils/lm/ui.js +7 -3
  127. package/src/utils/open-browser.js +8 -2
  128. package/src/utils/parse-raw-flags.js +4 -4
  129. package/src/utils/proxy.js +6 -5
  130. package/src/utils/read-repo-url.js +1 -0
  131. package/src/utils/redirects.js +3 -5
  132. package/src/utils/rules-proxy.js +2 -1
  133. package/src/utils/state-config.js +1 -1
  134. package/src/utils/telemetry/index.js +2 -113
  135. package/src/utils/telemetry/request.js +3 -1
  136. package/src/utils/telemetry/telemetry.js +117 -0
  137. package/src/utils/telemetry/validation.js +13 -12
  138. package/src/utils/traffic-mesh.js +3 -3
  139. package/oclif.manifest.json +0 -1
  140. package/src/commands/addons/auth.js +0 -42
  141. package/src/commands/addons/config.js +0 -177
  142. package/src/commands/addons/create.js +0 -127
  143. package/src/commands/addons/delete.js +0 -69
  144. package/src/commands/addons/list.js +0 -54
  145. package/src/commands/api.js +0 -84
  146. package/src/commands/dev/exec.js +0 -32
  147. package/src/commands/dev/trace.js +0 -61
  148. package/src/commands/env/get.js +0 -44
  149. package/src/commands/env/import.js +0 -90
  150. package/src/commands/env/list.js +0 -49
  151. package/src/commands/env/set.js +0 -64
  152. package/src/commands/env/unset.js +0 -58
  153. package/src/commands/functions/build.js +0 -60
  154. package/src/commands/functions/invoke.js +0 -277
  155. package/src/commands/functions/list.js +0 -102
  156. package/src/commands/functions/serve.js +0 -70
  157. package/src/commands/link.js +0 -133
  158. package/src/commands/lm/info.js +0 -36
  159. package/src/commands/lm/install.js +0 -30
  160. package/src/commands/lm/setup.js +0 -107
  161. package/src/commands/lm/uninstall.js +0 -17
  162. package/src/commands/login.js +0 -54
  163. package/src/commands/logout.js +0 -37
  164. package/src/commands/open/admin.js +0 -51
  165. package/src/commands/open/site.js +0 -43
  166. package/src/commands/sites/create.js +0 -191
  167. package/src/commands/sites/delete.js +0 -116
  168. package/src/commands/sites/list.js +0 -84
  169. package/src/commands/status/hooks.js +0 -60
  170. package/src/commands/switch.js +0 -44
  171. package/src/commands/unlink.js +0 -38
  172. package/src/commands/watch.js +0 -115
  173. package/src/hooks/init.js +0 -46
  174. package/src/index.js +0 -25
  175. package/src/lib/help.js +0 -26
  176. package/src/utils/chalk.js +0 -16
  177. package/src/utils/check-command-inputs.js +0 -21
  178. package/src/utils/command.js +0 -261
  179. package/src/utils/detect-functions-builder.js +0 -25
  180. package/src/utils/difference.js +0 -4
  181. package/src/utils/header.js +0 -18
  182. package/src/utils/logo.js +0 -11
  183. package/src/utils/show-help.js +0 -5
  184. package/src/utils/telemetry/tracked-command.js +0 -51
@@ -0,0 +1,273 @@
1
+ // @ts-check
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const process = require('process')
5
+
6
+ const inquirer = require('inquirer')
7
+ const fetch = require('node-fetch')
8
+
9
+ const { BACKGROUND, NETLIFYDEVWARN, chalk, error, exit, getFunctions } = require('../../utils')
10
+
11
+ // https://www.netlify.com/docs/functions/#event-triggered-functions
12
+ const events = [
13
+ 'deploy-building',
14
+ 'deploy-succeeded',
15
+ 'deploy-failed',
16
+ 'deploy-locked',
17
+ 'deploy-unlocked',
18
+ 'split-test-activated',
19
+ 'split-test-deactivated',
20
+ 'split-test-modified',
21
+ 'submission-created',
22
+ 'identity-validate',
23
+ 'identity-signup',
24
+ 'identity-login',
25
+ ]
26
+ const eventTriggeredFunctions = new Set([...events, ...events.map((name) => `${name}${BACKGROUND}`)])
27
+
28
+ const DEFAULT_PORT = 8888
29
+
30
+ // https://stackoverflow.com/questions/3710204/how-to-check-if-a-string-is-a-valid-json-string-in-javascript-without-using-try
31
+ const tryParseJSON = function (jsonString) {
32
+ try {
33
+ const parsedValue = JSON.parse(jsonString)
34
+
35
+ // Handle non-exception-throwing cases:
36
+ // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
37
+ // but... JSON.parse(null) returns null, and typeof null === "object",
38
+ // so we must check for that, too. Thankfully, null is falsey, so this suffices:
39
+ if (parsedValue && typeof parsedValue === 'object') {
40
+ return parsedValue
41
+ }
42
+ } catch {}
43
+
44
+ return false
45
+ }
46
+
47
+ const formatQstring = function (querystring) {
48
+ if (querystring) {
49
+ return `?${querystring}`
50
+ }
51
+ return ''
52
+ }
53
+
54
+ /** process payloads from flag */
55
+ const processPayloadFromFlag = function (payloadString) {
56
+ if (payloadString) {
57
+ // case 1: jsonstring
58
+ let payload = tryParseJSON(payloadString)
59
+ if (payload) return payload
60
+ // case 2: jsonpath
61
+ const payloadpath = path.join(process.cwd(), payloadString)
62
+ const pathexists = fs.existsSync(payloadpath)
63
+ if (pathexists) {
64
+ try {
65
+ // there is code execution potential here
66
+ // eslint-disable-next-line node/global-require, import/no-dynamic-require
67
+ payload = require(payloadpath)
68
+ return payload
69
+ } catch (error_) {
70
+ console.error(error_)
71
+ }
72
+ }
73
+ // case 3: invalid string, invalid path
74
+ return false
75
+ }
76
+ }
77
+
78
+ /**
79
+ * prompt for a name if name not supplied
80
+ * also used in functions:create
81
+ * @param {*} functions
82
+ * @param {import('commander').OptionValues} options
83
+ * @param {string} [argumentName] The name that might be provided as argument (optional argument)
84
+ * @returns {Promise<string>}
85
+ */
86
+ const getNameFromArgs = async function (functions, options, argumentName) {
87
+ const functionToTrigger = getFunctionToTrigger(options, argumentName)
88
+ const functionNames = functions.map(({ name }) => name)
89
+
90
+ if (functionToTrigger) {
91
+ if (functionNames.includes(functionToTrigger)) {
92
+ return functionToTrigger
93
+ }
94
+
95
+ console.warn(
96
+ `Function name ${chalk.yellow(
97
+ functionToTrigger,
98
+ )} supplied but no matching function found in your functions folder, forcing you to pick a valid one...`,
99
+ )
100
+ }
101
+
102
+ const { trigger } = await inquirer.prompt([
103
+ {
104
+ type: 'list',
105
+ message: 'Pick a function to trigger',
106
+ name: 'trigger',
107
+ choices: functionNames,
108
+ },
109
+ ])
110
+ return trigger
111
+ }
112
+
113
+ /**
114
+ * get the function name out of the argument or options
115
+ * @param {import('commander').OptionValues} options
116
+ * @param {string} [argumentName] The name that might be provided as argument (optional argument)
117
+ * @returns {string}
118
+ */
119
+ const getFunctionToTrigger = function (options, argumentName) {
120
+ if (options.name) {
121
+ if (argumentName) {
122
+ console.error('function name specified in both flag and arg format, pick one')
123
+ exit(1)
124
+ }
125
+
126
+ return options.name
127
+ }
128
+
129
+ return argumentName
130
+ }
131
+
132
+ /**
133
+ * The functions:invoke command
134
+ * @param {string} nameArgument
135
+ * @param {import('commander').OptionValues} options
136
+ * @param {import('../base-command').BaseCommand} command
137
+ */
138
+ const functionsInvoke = async (nameArgument, options, command) => {
139
+ const { config } = command.netlify
140
+
141
+ const functionsDir = options.functions || (config.dev && config.dev.functions) || config.functionsDirectory
142
+ if (typeof functionsDir === 'undefined') {
143
+ error('functions directory is undefined, did you forget to set it in netlify.toml?')
144
+ }
145
+
146
+ if (!options.port)
147
+ console.warn(`${NETLIFYDEVWARN} "port" flag was not specified. Attempting to connect to localhost:8888 by default`)
148
+ const port = options.port || DEFAULT_PORT
149
+
150
+ const functions = await getFunctions(functionsDir)
151
+ const functionToTrigger = await getNameFromArgs(functions, options, nameArgument)
152
+
153
+ let headers = {}
154
+ let body = {}
155
+
156
+ if (eventTriggeredFunctions.has(functionToTrigger)) {
157
+ /** handle event triggered fns */
158
+ // https://www.netlify.com/docs/functions/#event-triggered-functions
159
+ const [name, event] = functionToTrigger.split('-')
160
+ if (name === 'identity') {
161
+ // https://www.netlify.com/docs/functions/#identity-event-functions
162
+ body.event = event
163
+ body.user = {
164
+ id: '1111a1a1-a11a-1111-aa11-aaa11111a11a',
165
+ aud: '',
166
+ role: '',
167
+ email: 'foo@trust-this-company.com',
168
+ app_metadata: {
169
+ provider: 'email',
170
+ },
171
+ user_metadata: {
172
+ full_name: 'Test Person',
173
+ },
174
+ created_at: new Date(Date.now()).toISOString(),
175
+ update_at: new Date(Date.now()).toISOString(),
176
+ }
177
+ } else {
178
+ // non identity functions seem to have a different shape
179
+ // https://www.netlify.com/docs/functions/#event-function-payloads
180
+ body.payload = {
181
+ TODO: 'mock up payload data better',
182
+ }
183
+ body.site = {
184
+ TODO: 'mock up site data better',
185
+ }
186
+ }
187
+ } else {
188
+ // NOT an event triggered function, but may still want to simulate authentication locally
189
+ let isAuthenticated = false
190
+ if (typeof options.identity === 'undefined') {
191
+ const { isAuthed } = await inquirer.prompt([
192
+ {
193
+ type: 'confirm',
194
+ name: 'isAuthed',
195
+ message: `Invoke with emulated Netlify Identity authentication headers? (pass --identity/--no-identity to override)`,
196
+ default: true,
197
+ },
198
+ ])
199
+ isAuthenticated = isAuthed
200
+ } else {
201
+ isAuthenticated = options.identity
202
+ }
203
+ if (isAuthenticated) {
204
+ headers = {
205
+ authorization:
206
+ 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb3VyY2UiOiJuZXRsaWZ5IGZ1bmN0aW9uczp0cmlnZ2VyIiwidGVzdERhdGEiOiJORVRMSUZZX0RFVl9MT0NBTExZX0VNVUxBVEVEX0pXVCJ9.Xb6vOFrfLUZmyUkXBbCvU4bM7q8tPilF0F03Wupap_c',
207
+ }
208
+ // you can decode this https://jwt.io/
209
+ // {
210
+ // "source": "netlify functions:trigger",
211
+ // "testData": "NETLIFY_DEV_LOCALLY_EMULATED_JWT"
212
+ // }
213
+ }
214
+ }
215
+ const payload = processPayloadFromFlag(options.payload)
216
+ body = { ...body, ...payload }
217
+
218
+ try {
219
+ const response = await fetch(
220
+ `http://localhost:${port}/.netlify/functions/${functionToTrigger}${formatQstring(options.querystring)}`,
221
+ {
222
+ method: 'post',
223
+ headers,
224
+ body: JSON.stringify(body),
225
+ },
226
+ )
227
+ const data = await response.text()
228
+ console.log(data)
229
+ } catch (error_) {
230
+ error(`Ran into an error invoking your function: ${error_.message}`)
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Creates the `netlify functions:invoke` command
236
+ * @param {import('../base-command').BaseCommand} program
237
+ * @returns
238
+ */
239
+ const createFunctionsInvokeCommand = (program) =>
240
+ program
241
+ .command('functions:invoke')
242
+ .alias('function:trigger')
243
+ .argument('[name]', 'function name to invoke')
244
+ .description(
245
+ `Trigger a function while in netlify dev with simulated data, good for testing function calls including Netlify's Event Triggered Functions`,
246
+ )
247
+ .option('-n, --name <name>', 'function name to invoke')
248
+ .option('-f, --functions <dir>', 'Specify a functions folder to parse, overriding netlify.toml')
249
+ .option('-q, --querystring <query>', 'Querystring to add to your function invocation')
250
+ .option('-p, --payload <data>', 'Supply POST payload in stringified json, or a path to a json file')
251
+ // TODO: refactor to not need the `undefined` state by removing the --identity flag (value `identity` will be then always defined to true or false)
252
+ .option(
253
+ '--identity',
254
+ 'simulate Netlify Identity authentication JWT. pass --identity to affirm unauthenticated request',
255
+ )
256
+ .option(
257
+ '--no-identity',
258
+ 'simulate Netlify Identity authentication JWT. pass --no-identity to affirm unauthenticated request',
259
+ )
260
+ .option('--port <port>', 'Port where netlify dev is accessible. e.g. 8888', (value) => Number.parseInt(value))
261
+ .addExamples([
262
+ 'netlify functions:invoke',
263
+ 'netlify functions:invoke myfunction',
264
+ 'netlify functions:invoke --name myfunction',
265
+ 'netlify functions:invoke --name myfunction --identity',
266
+ 'netlify functions:invoke --name myfunction --no-identity',
267
+ `netlify functions:invoke myfunction --payload '{"foo": 1}'`,
268
+ 'netlify functions:invoke myfunction --querystring "foo=1',
269
+ 'netlify functions:invoke myfunction --payload "./pathTo.json"',
270
+ ])
271
+ .action(functionsInvoke)
272
+
273
+ module.exports = { createFunctionsInvokeCommand }
@@ -0,0 +1,106 @@
1
+ // @ts-check
2
+
3
+ const AsciiTable = require('ascii-table')
4
+
5
+ const {
6
+ error,
7
+ exit,
8
+
9
+ getFunctions,
10
+ getFunctionsDir,
11
+ log,
12
+ logJson,
13
+ warn,
14
+ } = require('../../utils')
15
+
16
+ const normalizeFunction = function (deployedFunctions, { name, urlPath: url }) {
17
+ const isDeployed = deployedFunctions.some((deployedFunction) => deployedFunction.n === name)
18
+ return { name, url, isDeployed }
19
+ }
20
+
21
+ /**
22
+ * The functions:list command
23
+ * @param {import('commander').OptionValues} options
24
+ * @param {import('../base-command').BaseCommand} command
25
+ */
26
+ const functionsList = async (options, command) => {
27
+ const { api, config, site } = command.netlify
28
+
29
+ // get deployed site details
30
+ // copied from `netlify status`
31
+ const siteId = site.id
32
+ if (!siteId) {
33
+ warn('Did you run `netlify link` yet?')
34
+ error(`You don't appear to be in a folder that is linked to a site`)
35
+ }
36
+ let siteData
37
+ try {
38
+ siteData = await api.getSite({ siteId })
39
+ } catch (error_) {
40
+ // unauthorized
41
+ if (error_.status === 401) {
42
+ warn(`Log in with a different account or re-link to a site you have permission for`)
43
+ error(`Not authorized to view the currently linked site (${siteId})`)
44
+ }
45
+ // missing
46
+ if (error_.status === 404) {
47
+ error(`The site this folder is linked to can't be found`)
48
+ }
49
+ error(error_)
50
+ }
51
+ const deploy = siteData.published_deploy || {}
52
+ const deployedFunctions = deploy.available_functions || []
53
+
54
+ const functionsDir = getFunctionsDir({ options, config })
55
+
56
+ if (typeof functionsDir === 'undefined') {
57
+ log('Functions directory is undefined')
58
+ log('Please verify functions.directory is set in your Netlify configuration file (netlify.toml/yml/json)')
59
+ log('See https://docs.netlify.com/configure-builds/file-based-configuration/ for more information')
60
+ exit(1)
61
+ }
62
+
63
+ const functions = await getFunctions(functionsDir)
64
+ const normalizedFunctions = functions.map(normalizeFunction.bind(null, deployedFunctions))
65
+
66
+ if (normalizedFunctions.length === 0) {
67
+ log(`No functions found in ${functionsDir}`)
68
+ exit()
69
+ }
70
+
71
+ if (options.json) {
72
+ logJson(normalizedFunctions)
73
+ exit()
74
+ }
75
+
76
+ // Make table
77
+ log(`Based on local functions folder ${functionsDir}, these are the functions detected`)
78
+ const table = new AsciiTable(`Netlify Functions (in local functions folder)`)
79
+ table.setHeading('Name', 'URL', 'deployed')
80
+ normalizedFunctions.forEach(({ isDeployed, name, url }) => {
81
+ table.addRow(name, url, isDeployed ? 'yes' : 'no')
82
+ })
83
+ log(table.toString())
84
+ }
85
+
86
+ /**
87
+ * Creates the `netlify functions:list` command
88
+ * @param {import('../base-command').BaseCommand} program
89
+ * @returns
90
+ */
91
+ const createFunctionsListCommand = (program) =>
92
+ program
93
+ .command('functions:list')
94
+ .alias('function:list')
95
+ .description(
96
+ `List functions that exist locally
97
+ Helpful for making sure that you have formatted your functions correctly
98
+
99
+ NOT the same as listing the functions that have been deployed. For that info you need to go to your Netlify deploy log.`,
100
+ )
101
+ .option('-n, --name <name>', 'name to print')
102
+ .option('-f, --functions <dir>', 'Specify a functions directory to list')
103
+ .option('--json', 'Output function data as JSON')
104
+ .action(functionsList)
105
+
106
+ module.exports = { createFunctionsListCommand }
@@ -0,0 +1,63 @@
1
+ // @ts-check
2
+
3
+ const { join } = require('path')
4
+
5
+ const { startFunctionsServer } = require('../../lib/functions/server')
6
+ const { acquirePort, getFunctionsDir, getSiteInformation, injectEnvVariables } = require('../../utils')
7
+
8
+ const DEFAULT_PORT = 9999
9
+
10
+ /**
11
+ * The functions:serve command
12
+ * @param {import('commander').OptionValues} options
13
+ * @param {import('../base-command').BaseCommand} command
14
+ */
15
+ const functionsServe = async (options, command) => {
16
+ const { api, config, site, siteInfo } = command.netlify
17
+
18
+ const functionsDir = getFunctionsDir({ options, config }, join('netlify', 'functions'))
19
+
20
+ await injectEnvVariables({ env: command.netlify.cachedConfig.env, site })
21
+
22
+ const { capabilities, siteUrl, timeouts } = await getSiteInformation({
23
+ offline: options.offline,
24
+ api,
25
+ site,
26
+ siteInfo,
27
+ })
28
+
29
+ const functionsPort = await acquirePort({
30
+ configuredPort: options.port || (config.dev && config.dev.functionsPort),
31
+ defaultPort: DEFAULT_PORT,
32
+ errorMessage: 'Could not acquire configured functions port',
33
+ })
34
+
35
+ await startFunctionsServer({
36
+ config,
37
+ settings: { functions: functionsDir, functionsPort },
38
+ site,
39
+ siteUrl,
40
+ capabilities,
41
+ timeouts,
42
+ functionsPrefix: '/.netlify/functions/',
43
+ buildersPrefix: '/.netlify/builders/',
44
+ })
45
+ }
46
+
47
+ /**
48
+ * Creates the `netlify functions:serve` command
49
+ * @param {import('../base-command').BaseCommand} program
50
+ * @returns
51
+ */
52
+ const createFunctionsServeCommand = (program) =>
53
+ program
54
+ .command('functions:serve')
55
+ .alias('function:serve')
56
+ .description('(Beta) Serve functions locally')
57
+ .option('-f, --functions <dir>', 'Specify a functions directory to serve')
58
+ .option('-p, --port <port>', 'Specify a port for the functions server', (value) => Number.parseInt(value))
59
+ .option('-o, --offline', 'disables any features that require network access')
60
+ .addHelpText('after', 'Helpful for debugging functions.')
61
+ .action(functionsServe)
62
+
63
+ module.exports = { createFunctionsServeCommand }
@@ -0,0 +1,47 @@
1
+ // @ts-check
2
+ const { chalk } = require('../../utils')
3
+
4
+ const { createFunctionsBuildCommand } = require('./functions-build')
5
+ const { createFunctionsCreateCommand } = require('./functions-create')
6
+ const { createFunctionsInvokeCommand } = require('./functions-invoke')
7
+ const { createFunctionsListCommand } = require('./functions-list')
8
+ const { createFunctionsServeCommand } = require('./functions-serve')
9
+
10
+ /**
11
+ * The functions command
12
+ * @param {import('commander').OptionValues} options
13
+ * @param {import('../base-command').BaseCommand} command
14
+ */
15
+ const functions = (options, command) => {
16
+ command.help()
17
+ }
18
+
19
+ /**
20
+ * Creates the `netlify functions` command
21
+ * @param {import('../base-command').BaseCommand} program
22
+ * @returns
23
+ */
24
+ const createFunctionsCommand = (program) => {
25
+ createFunctionsBuildCommand(program)
26
+ createFunctionsCreateCommand(program)
27
+ createFunctionsInvokeCommand(program)
28
+ createFunctionsListCommand(program)
29
+ createFunctionsServeCommand(program)
30
+
31
+ const name = chalk.greenBright('`functions`')
32
+
33
+ return program
34
+ .command('functions')
35
+ .alias('function')
36
+ .description(
37
+ `Manage netlify functions
38
+ The ${name} command will help you manage the functions in this site`,
39
+ )
40
+ .addExamples([
41
+ 'netlify functions:create --name function-xyz',
42
+ 'netlify functions:build --name function-abc --timeout 30s',
43
+ ])
44
+ .action(functions)
45
+ }
46
+
47
+ module.exports = { createFunctionsCommand }
@@ -1,47 +1,5 @@
1
- const { execSync } = require('child_process')
1
+ const { createFunctionsCommand } = require('./functions')
2
2
 
3
- const chalk = require('chalk')
4
-
5
- const { TrackedCommand } = require('../../utils/telemetry/tracked-command')
6
-
7
- const showHelp = function (command) {
8
- execSync(`netlify ${command} --help`, { stdio: [0, 1, 2] })
9
- }
10
-
11
- const isEmptyCommand = function (flags, args) {
12
- if (!hasFlags(flags) && !hasArgs(args)) {
13
- return true
14
- }
15
- return false
3
+ module.exports = {
4
+ createFunctionsCommand,
16
5
  }
17
-
18
- const hasFlags = function (flags) {
19
- return Object.keys(flags).length
20
- }
21
-
22
- const hasArgs = function (args) {
23
- return Object.keys(args).length
24
- }
25
-
26
- class FunctionsCommand extends TrackedCommand {
27
- run() {
28
- const { args, flags } = this.parse(FunctionsCommand)
29
-
30
- // run help command if no args passed
31
- if (isEmptyCommand(flags, args)) {
32
- showHelp(this.id)
33
- }
34
- }
35
- }
36
-
37
- const name = chalk.greenBright('`functions`')
38
- FunctionsCommand.aliases = ['function']
39
- FunctionsCommand.description = `Manage netlify functions
40
- The ${name} command will help you manage the functions in this site
41
- `
42
- FunctionsCommand.examples = [
43
- 'netlify functions:create --name function-xyz',
44
- 'netlify functions:build --name function-abc --timeout 30s',
45
- ]
46
-
47
- module.exports = FunctionsCommand
@@ -0,0 +1,7 @@
1
+ const baseCommand = require('./base-command')
2
+ const { createMainCommand } = require('./main')
3
+
4
+ module.exports = {
5
+ ...baseCommand,
6
+ createMainCommand,
7
+ }
@@ -0,0 +1,6 @@
1
+ const { createInitCommand, init } = require('./init')
2
+
3
+ module.exports = {
4
+ createInitCommand,
5
+ init,
6
+ }