netlify-cli 12.5.0 → 12.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +5 -0
  2. package/npm-shrinkwrap.json +1075 -634
  3. package/package.json +7 -160
  4. package/src/commands/base-command.mjs +16 -5
  5. package/src/commands/deploy/deploy.mjs +1 -1
  6. package/src/commands/dev/dev.mjs +27 -511
  7. package/src/commands/env/env-list.mjs +1 -0
  8. package/src/commands/functions/functions-create.mjs +35 -25
  9. package/src/commands/functions/functions-serve.mjs +5 -1
  10. package/src/commands/main.mjs +2 -0
  11. package/src/commands/serve/serve.mjs +189 -0
  12. package/src/commands/sites/sites-list.mjs +1 -1
  13. package/src/commands/watch/watch.mjs +1 -1
  14. package/src/functions-templates/go/hello-world/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  15. package/src/functions-templates/javascript/apollo-graphql/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  16. package/src/functions-templates/javascript/apollo-graphql-rest/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  17. package/src/functions-templates/javascript/auth-fetch/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  18. package/src/functions-templates/javascript/create-user/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  19. package/src/functions-templates/javascript/fauna-crud/{.netlify-function-template.cjs → .netlify-function-template.mjs} +3 -2
  20. package/src/functions-templates/javascript/fauna-graphql/{.netlify-function-template.cjs → .netlify-function-template.mjs} +3 -2
  21. package/src/functions-templates/javascript/google-analytics/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  22. package/src/functions-templates/javascript/graphql-gateway/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  23. package/src/functions-templates/javascript/hasura-event-triggered/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  24. package/src/functions-templates/javascript/hello/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  25. package/src/functions-templates/{typescript/hello-world/.netlify-function-template.cjs → javascript/hello-world/.netlify-function-template.mjs} +1 -1
  26. package/src/functions-templates/javascript/identity-signup/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  27. package/src/functions-templates/javascript/image-external/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  28. package/src/functions-templates/javascript/localized-content/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  29. package/src/functions-templates/javascript/node-fetch/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  30. package/src/functions-templates/javascript/oauth-passport/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  31. package/src/functions-templates/javascript/oauth-passport/package.json +1 -1
  32. package/src/functions-templates/javascript/protected-function/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  33. package/src/functions-templates/javascript/sanity-create/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  34. package/src/functions-templates/javascript/sanity-groq/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  35. package/src/functions-templates/javascript/scheduled-function/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  36. package/src/functions-templates/javascript/scheduled-function/package.json +1 -1
  37. package/src/functions-templates/javascript/send-email/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  38. package/src/functions-templates/javascript/serverless-ssr/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  39. package/src/functions-templates/javascript/set-cookie/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  40. package/src/functions-templates/javascript/set-cookies/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  41. package/src/functions-templates/{typescript/set-req-header/.netlify-function-template.cjs → javascript/set-req-header/.netlify-function-template.mjs} +1 -1
  42. package/src/functions-templates/javascript/set-res-header/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  43. package/src/functions-templates/javascript/slack-rate-limit/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  44. package/src/functions-templates/javascript/stripe-charge/{.netlify-function-template.cjs → .netlify-function-template.mjs} +2 -2
  45. package/src/functions-templates/javascript/stripe-subscription/{.netlify-function-template.cjs → .netlify-function-template.mjs} +2 -2
  46. package/src/functions-templates/javascript/submission-created/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  47. package/src/functions-templates/javascript/token-hider/{.netlify-function-template.cjs → .netlify-function-template.mjs} +2 -2
  48. package/src/functions-templates/{typescript/transform-response/.netlify-function-template.cjs → javascript/transform-response/.netlify-function-template.mjs} +1 -1
  49. package/src/functions-templates/javascript/url-shortener/{.netlify-function-template.cjs → .netlify-function-template.mjs} +2 -2
  50. package/src/functions-templates/javascript/using-middleware/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  51. package/src/functions-templates/rust/hello-world/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  52. package/src/functions-templates/typescript/abtest/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  53. package/src/functions-templates/typescript/geolocation/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  54. package/src/functions-templates/typescript/geolocation/{{name}}.ts +1 -1
  55. package/src/functions-templates/{javascript/hello-world/.netlify-function-template.cjs → typescript/hello-world/.netlify-function-template.mjs} +1 -1
  56. package/src/functions-templates/typescript/hello-world/package-lock.json +7 -7
  57. package/src/functions-templates/typescript/hello-world/package.json +1 -1
  58. package/src/functions-templates/typescript/json/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  59. package/src/functions-templates/typescript/json/{{name}}.ts +1 -1
  60. package/src/functions-templates/typescript/log/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  61. package/src/functions-templates/typescript/log/{{name}}.ts +2 -2
  62. package/src/functions-templates/typescript/scheduled-function/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  63. package/src/functions-templates/typescript/scheduled-function/package.json +1 -1
  64. package/src/functions-templates/typescript/set-cookies/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  65. package/src/functions-templates/{javascript/set-req-header/.netlify-function-template.cjs → typescript/set-req-header/.netlify-function-template.mjs} +1 -1
  66. package/src/functions-templates/typescript/set-res-header/{.netlify-function-template.cjs → .netlify-function-template.mjs} +1 -1
  67. package/src/functions-templates/{javascript/transform-response/.netlify-function-template.cjs → typescript/transform-response/.netlify-function-template.mjs} +1 -1
  68. package/src/lib/completion/constants.mjs +1 -1
  69. package/src/lib/edge-functions/deploy.mjs +1 -1
  70. package/src/lib/edge-functions/internal.mjs +1 -1
  71. package/src/lib/edge-functions/proxy.mjs +2 -2
  72. package/src/lib/edge-functions/registry.mjs +2 -5
  73. package/src/lib/{fs.cjs → fs.mjs} +5 -13
  74. package/src/lib/functions/registry.mjs +55 -33
  75. package/src/lib/functions/runtimes/js/builders/netlify-lambda.mjs +1 -1
  76. package/src/lib/functions/runtimes/js/builders/zisi.mjs +3 -2
  77. package/src/lib/functions/runtimes/rust/index.mjs +3 -2
  78. package/src/lib/functions/server.mjs +35 -18
  79. package/src/lib/{settings.cjs → settings.mjs} +6 -8
  80. package/src/lib/{spinner.cjs → spinner.mjs} +5 -7
  81. package/src/utils/banner.mjs +17 -0
  82. package/src/utils/command-helpers.mjs +1 -1
  83. package/src/utils/detect-server-settings.mjs +35 -1
  84. package/src/utils/dev.mjs +8 -5
  85. package/src/utils/dot-env.mjs +1 -1
  86. package/src/utils/framework-server.mjs +66 -0
  87. package/src/utils/functions/functions.mjs +20 -4
  88. package/src/utils/functions/get-functions.mjs +1 -1
  89. package/src/utils/get-global-config.mjs +1 -1
  90. package/src/utils/gitignore.mjs +1 -1
  91. package/src/utils/graph.mjs +170 -0
  92. package/src/utils/init/utils.mjs +1 -1
  93. package/src/utils/live-tunnel.mjs +1 -1
  94. package/src/utils/lm/install.mjs +2 -2
  95. package/src/utils/proxy-server.mjs +90 -0
  96. package/src/utils/proxy.mjs +1 -1
  97. package/src/utils/rules-proxy.mjs +1 -1
  98. package/src/utils/run-build.mjs +129 -0
  99. package/src/utils/shell.mjs +120 -0
  100. package/src/utils/state-config.mjs +1 -1
  101. package/src/utils/static-server.mjs +34 -0
  102. package/src/utils/validation.mjs +15 -0
@@ -1,11 +1,11 @@
1
1
  // @ts-check
2
2
  import cp from 'child_process'
3
3
  import fs from 'fs'
4
- import { mkdir } from 'fs/promises'
4
+ import { mkdir, readdir, unlink } from 'fs/promises'
5
5
  import { createRequire } from 'module'
6
6
  import path, { dirname } from 'path'
7
7
  import process from 'process'
8
- import { fileURLToPath } from 'url'
8
+ import { fileURLToPath, pathToFileURL } from 'url'
9
9
  import { promisify } from 'util'
10
10
 
11
11
  import copyTemplateDirOriginal from 'copy-template-dir'
@@ -16,6 +16,7 @@ import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
16
16
  import fetch from 'node-fetch'
17
17
  import ora from 'ora'
18
18
 
19
+ import { fileExistsAsync } from '../../lib/fs.mjs'
19
20
  import { getAddons, getCurrentAddon, getSiteData } from '../../utils/addons/prepare.mjs'
20
21
  import { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, chalk, error, log } from '../../utils/command-helpers.mjs'
21
22
  import { injectEnvVariables } from '../../utils/dev.mjs'
@@ -90,19 +91,26 @@ const filterRegistry = function (registry, input) {
90
91
  })
91
92
  }
92
93
 
93
- const formatRegistryArrayForInquirer = function (lang, funcType) {
94
- const folderNames = fs.readdirSync(path.join(templatesDir, lang))
95
- const registry = folderNames
96
- // filter out markdown files
97
- .filter((folderName) => !folderName.endsWith('.md'))
94
+ const formatRegistryArrayForInquirer = async function (lang, funcType) {
95
+ const folderNames = await readdir(path.join(templatesDir, lang))
98
96
 
99
- .map((folderName) =>
100
- // eslint-disable-next-line import/no-dynamic-require
101
- require(path.join(templatesDir, lang, folderName, '.netlify-function-template.cjs')),
102
- )
103
- .filter((folderName) => folderName.functionType === funcType)
104
- .sort((folderNameA, folderNameB) => {
105
- const priorityDiff = (folderNameA.priority || DEFAULT_PRIORITY) - (folderNameB.priority || DEFAULT_PRIORITY)
97
+ const imports = await Promise.all(
98
+ folderNames
99
+ // filter out markdown files
100
+ .filter((folderName) => !folderName.endsWith('.md'))
101
+ .map(async (folderName) => {
102
+ const templatePath = path.join(templatesDir, lang, folderName, '.netlify-function-template.mjs')
103
+ // eslint-disable-next-line import/no-dynamic-require
104
+ const template = await import(pathToFileURL(templatePath))
105
+
106
+ return template.default
107
+ }),
108
+ )
109
+
110
+ const registry = imports
111
+ .filter((template) => template.functionType === funcType)
112
+ .sort((templateA, templateB) => {
113
+ const priorityDiff = (templateA.priority || DEFAULT_PRIORITY) - (templateB.priority || DEFAULT_PRIORITY)
106
114
 
107
115
  if (priorityDiff !== 0) {
108
116
  return priorityDiff
@@ -112,7 +120,7 @@ const formatRegistryArrayForInquirer = function (lang, funcType) {
112
120
  // until Node 11, so the original sorting order from `fs.readdirSync`
113
121
  // was not respected. We can simplify this once we drop support for
114
122
  // Node 10.
115
- return folderNameA - folderNameB
123
+ return templateA - templateB
116
124
  })
117
125
  .map((t) => {
118
126
  t.lang = lang
@@ -170,7 +178,7 @@ const pickTemplate = async function ({ language: languageFromFlag }, funcType) {
170
178
  let templatesForLanguage
171
179
 
172
180
  try {
173
- templatesForLanguage = formatRegistryArrayForInquirer(language, funcType)
181
+ templatesForLanguage = await formatRegistryArrayForInquirer(language, funcType)
174
182
  } catch {
175
183
  throw error(`Invalid language: ${language}`)
176
184
  }
@@ -292,14 +300,14 @@ const ensureFunctionDirExists = async function (command) {
292
300
  }
293
301
  }
294
302
 
295
- if (!fs.existsSync(functionsDirHolder)) {
303
+ if (!(await fileExistsAsync(functionsDirHolder))) {
296
304
  log(
297
305
  `${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(
298
306
  functionsDirHolder,
299
307
  )} does not exist yet, creating it...`,
300
308
  )
301
309
 
302
- fs.mkdirSync(functionsDirHolder, { recursive: true })
310
+ await mkdir(functionsDirHolder, { recursive: true })
303
311
 
304
312
  log(`${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(functionsDirHolder)} created`)
305
313
  }
@@ -350,15 +358,17 @@ const downloadFromURL = async function (command, options, argumentName, function
350
358
  })
351
359
 
352
360
  // read, execute, and delete function template file if exists
353
- const fnTemplateFile = path.join(fnFolder, '.netlify-function-template.cjs')
354
- if (fs.existsSync(fnTemplateFile)) {
355
- // eslint-disable-next-line import/no-dynamic-require
356
- const { onComplete, addons = [] } = require(fnTemplateFile)
361
+ const fnTemplateFile = path.join(fnFolder, '.netlify-function-template.mjs')
362
+ if (await fileExistsAsync(fnTemplateFile)) {
363
+ const {
364
+ default: { onComplete, addons = [] },
365
+ // eslint-disable-next-line import/no-dynamic-require
366
+ } = await import(pathToFileURL(fnTemplateFile).href)
357
367
 
358
368
  await installAddons(command, addons, path.resolve(fnFolder))
359
369
  await handleOnComplete({ command, onComplete })
360
370
  // delete
361
- fs.unlinkSync(fnTemplateFile)
371
+ await unlink(fnTemplateFile)
362
372
  }
363
373
  }
364
374
 
@@ -471,7 +481,7 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
471
481
 
472
482
  // These files will not be part of the log message because they'll likely
473
483
  // be removed before the command finishes.
474
- const omittedFromOutput = new Set(['.netlify-function-template.cjs', 'package.json', 'package-lock.json'])
484
+ const omittedFromOutput = new Set(['.netlify-function-template.mjs', 'package.json', 'package-lock.json'])
475
485
  const createdFiles = await copyTemplateDir(pathToTemplate, functionPath, vars)
476
486
  createdFiles.forEach((filePath) => {
477
487
  const filename = path.basename(filePath)
@@ -487,7 +497,7 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
487
497
  })
488
498
 
489
499
  // delete function template file that was copied over by copydir
490
- fs.unlinkSync(path.join(functionPath, '.netlify-function-template.cjs'))
500
+ await unlink(path.join(functionPath, '.netlify-function-template.mjs'))
491
501
 
492
502
  // npm install
493
503
  if (functionPackageJson !== undefined) {
@@ -16,8 +16,11 @@ const functionsServe = async (options, command) => {
16
16
  const { api, config, site, siteInfo } = command.netlify
17
17
 
18
18
  const functionsDir = getFunctionsDir({ options, config }, join('netlify', 'functions'))
19
+ const { env } = command.netlify.cachedConfig
19
20
 
20
- await injectEnvVariables({ devConfig: { ...config.dev }, env: command.netlify.cachedConfig.env, site })
21
+ env.NETLIFY_DEV = { sources: ['internal'], value: 'true' }
22
+
23
+ await injectEnvVariables({ devConfig: { ...config.dev }, env, site })
21
24
 
22
25
  const { capabilities, siteUrl, timeouts } = await getSiteInformation({
23
26
  offline: options.offline,
@@ -34,6 +37,7 @@ const functionsServe = async (options, command) => {
34
37
 
35
38
  await startFunctionsServer({
36
39
  config,
40
+ debug: options.debug,
37
41
  api,
38
42
  settings: { functions: functionsDir, functionsPort },
39
43
  site,
@@ -28,6 +28,7 @@ import { createLoginCommand } from './login/index.mjs'
28
28
  import { createLogoutCommand } from './logout/index.mjs'
29
29
  import { createOpenCommand } from './open/index.mjs'
30
30
  import { createRecipesCommand } from './recipes/index.mjs'
31
+ import { createServeCommand } from './serve/serve.mjs'
31
32
  import { createSitesCommand } from './sites/index.mjs'
32
33
  import { createStatusCommand } from './status/index.mjs'
33
34
  import { createSwitchCommand } from './switch/index.mjs'
@@ -173,6 +174,7 @@ export const createMainCommand = () => {
173
174
  createLoginCommand(program)
174
175
  createLogoutCommand(program)
175
176
  createOpenCommand(program)
177
+ createServeCommand(program)
176
178
  createSitesCommand(program)
177
179
  createStatusCommand(program)
178
180
  createSwitchCommand(program)
@@ -0,0 +1,189 @@
1
+ // @ts-check
2
+ import process from 'process'
3
+
4
+ import { Option } from 'commander'
5
+
6
+ import { promptEditorHelper } from '../../lib/edge-functions/editor-helper.mjs'
7
+ import { startFunctionsServer } from '../../lib/functions/server.mjs'
8
+ import { printBanner } from '../../utils/banner.mjs'
9
+ import {
10
+ chalk,
11
+ exit,
12
+ log,
13
+ NETLIFYDEVERR,
14
+ NETLIFYDEVLOG,
15
+ NETLIFYDEVWARN,
16
+ normalizeConfig,
17
+ } from '../../utils/command-helpers.mjs'
18
+ import detectServerSettings, { getConfigWithPlugins } from '../../utils/detect-server-settings.mjs'
19
+ import { getSiteInformation, injectEnvVariables } from '../../utils/dev.mjs'
20
+ import { getEnvelopeEnv, normalizeContext } from '../../utils/env/index.mjs'
21
+ import { getInternalFunctionsDir } from '../../utils/functions/functions.mjs'
22
+ import { ensureNetlifyIgnore } from '../../utils/gitignore.mjs'
23
+ import openBrowser from '../../utils/open-browser.mjs'
24
+ import { generateInspectSettings, startProxyServer } from '../../utils/proxy-server.mjs'
25
+ import { runBuildTimeline } from '../../utils/run-build.mjs'
26
+ import { getGeoCountryArgParser } from '../../utils/validation.mjs'
27
+
28
+ /**
29
+ * The serve command
30
+ * @param {import('commander').OptionValues} options
31
+ * @param {import('../base-command.mjs').default} command
32
+ */
33
+ const serve = async (options, command) => {
34
+ const { api, cachedConfig, config, repositoryRoot, site, siteInfo, state } = command.netlify
35
+ config.dev = { ...config.dev }
36
+ config.build = { ...config.build }
37
+ /** @type {import('../dev/types').DevConfig} */
38
+ const devConfig = {
39
+ ...(config.functionsDirectory && { functions: config.functionsDirectory }),
40
+ ...(config.build.publish && { publish: config.build.publish }),
41
+ ...config.dev,
42
+ ...options,
43
+ // Override the `framework` value so that we start a static server and not
44
+ // the framework's development server.
45
+ framework: '#static',
46
+ }
47
+
48
+ let { env } = cachedConfig
49
+
50
+ if (!options.offline && siteInfo.use_envelope) {
51
+ env = await getEnvelopeEnv({ api, context: options.context, env, siteInfo })
52
+ log(`${NETLIFYDEVLOG} Injecting environment variable values for ${chalk.yellow('all scopes')}`)
53
+ }
54
+
55
+ await injectEnvVariables({ devConfig, env, site })
56
+ await promptEditorHelper({ chalk, config, log, NETLIFYDEVLOG, repositoryRoot, state })
57
+
58
+ const { addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({
59
+ // inherited from base command --offline
60
+ offline: options.offline,
61
+ api,
62
+ site,
63
+ siteInfo,
64
+ })
65
+
66
+ // Ensure the internal functions directory exists so that the functions
67
+ // server and registry are initialized, and any functions created by
68
+ // Netlify Build are loaded.
69
+ await getInternalFunctionsDir({ base: site.root, ensureExists: true })
70
+
71
+ /** @type {Partial<import('../../utils/types').ServerSettings>} */
72
+ let settings = {}
73
+ try {
74
+ settings = await detectServerSettings(devConfig, options, site.root)
75
+
76
+ cachedConfig.config = getConfigWithPlugins(cachedConfig.config, settings)
77
+ } catch (error_) {
78
+ log(NETLIFYDEVERR, error_.message)
79
+ exit(1)
80
+ }
81
+
82
+ command.setAnalyticsPayload({ projectType: settings.framework || 'custom', live: options.live, graph: options.graph })
83
+
84
+ log(`${NETLIFYDEVLOG} Building site for production`)
85
+ log(
86
+ `${NETLIFYDEVWARN} Changes will not be hot-reloaded, so if you need to rebuild your site you must exit and run 'netlify serve' again`,
87
+ )
88
+
89
+ const { configPath: configPathOverride } = await runBuildTimeline({ cachedConfig, options, settings, site })
90
+
91
+ await startFunctionsServer({
92
+ api,
93
+ command,
94
+ config,
95
+ debug: options.debug,
96
+ loadDistFunctions: true,
97
+ settings,
98
+ site,
99
+ siteInfo,
100
+ siteUrl,
101
+ capabilities,
102
+ timeouts,
103
+ })
104
+
105
+ // Try to add `.netlify` to `.gitignore`.
106
+ try {
107
+ await ensureNetlifyIgnore(repositoryRoot)
108
+ } catch {
109
+ // no-op
110
+ }
111
+
112
+ // TODO: We should consolidate this with the existing config watcher.
113
+ const getUpdatedConfig = async () => {
114
+ const cwd = options.cwd || process.cwd()
115
+ const { config: newConfig } = await command.getConfig({ cwd, offline: true, state })
116
+ const normalizedNewConfig = normalizeConfig(newConfig)
117
+
118
+ return normalizedNewConfig
119
+ }
120
+
121
+ const inspectSettings = generateInspectSettings(options.edgeInspect, options.edgeInspectBrk)
122
+ const url = await startProxyServer({
123
+ addonsUrls,
124
+ config,
125
+ configPath: configPathOverride,
126
+ env,
127
+ geolocationMode: options.geo,
128
+ geoCountry: options.country,
129
+ getUpdatedConfig,
130
+ inspectSettings,
131
+ offline: options.offline,
132
+ settings,
133
+ site,
134
+ siteInfo,
135
+ state,
136
+ })
137
+
138
+ if (devConfig.autoLaunch !== false) {
139
+ await openBrowser({ url, silentBrowserNoneError: true })
140
+ }
141
+
142
+ process.env.URL = url
143
+ process.env.DEPLOY_URL = url
144
+
145
+ printBanner({ url })
146
+ }
147
+
148
+ /**
149
+ * Creates the `netlify serve` command
150
+ * @param {import('../base-command.mjs').default} program
151
+ * @returns
152
+ */
153
+ export const createServeCommand = (program) =>
154
+ program
155
+ .command('serve')
156
+ .description(
157
+ '(Beta) Build the site for production and serve locally. This does not watch the code for changes, so if you need to rebuild your site then you must exit and run `serve` again.',
158
+ )
159
+ .option(
160
+ '--context <context>',
161
+ 'Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
162
+ normalizeContext,
163
+ )
164
+ .option('-p ,--port <port>', 'port of netlify dev', (value) => Number.parseInt(value))
165
+ .option('-d ,--dir <path>', 'dir with static files')
166
+ .option('-f ,--functions <folder>', 'specify a functions folder to serve')
167
+ .option('-o ,--offline', 'disables any features that require network access')
168
+ .option('--functionsPort <port>', 'port of functions server', (value) => Number.parseInt(value))
169
+ .addOption(
170
+ new Option(
171
+ '--geo <mode>',
172
+ 'force geolocation data to be updated, use cached data from the last 24h if found, or use a mock location',
173
+ )
174
+ .choices(['cache', 'mock', 'update'])
175
+ .default('cache'),
176
+ )
177
+ .addOption(
178
+ new Option(
179
+ '--country <geoCountry>',
180
+ 'Two-letter country code (https://ntl.fyi/country-codes) to use as mock geolocation (enables --geo=mock automatically)',
181
+ ).argParser(getGeoCountryArgParser('netlify dev --geo=mock --country=FR')),
182
+ )
183
+ .addOption(
184
+ new Option('--staticServerPort <port>', 'port of the static app server used when no framework is detected')
185
+ .argParser((value) => Number.parseInt(value))
186
+ .hideHelp(),
187
+ )
188
+ .addExamples(['netlify serve', 'BROWSER=none netlify serve # disable browser auto opening'])
189
+ .action(serve)
@@ -1,6 +1,6 @@
1
1
  // @ts-check
2
2
  import { listSites } from '../../lib/api.mjs'
3
- import { startSpinner, stopSpinner } from '../../lib/spinner.cjs'
3
+ import { startSpinner, stopSpinner } from '../../lib/spinner.mjs'
4
4
  import { chalk, log, logJson } from '../../utils/command-helpers.mjs'
5
5
 
6
6
  /**
@@ -2,7 +2,7 @@
2
2
  import pWaitFor from 'p-wait-for'
3
3
  import prettyjson from 'prettyjson'
4
4
 
5
- import { startSpinner, stopSpinner } from '../../lib/spinner.cjs'
5
+ import { startSpinner, stopSpinner } from '../../lib/spinner.mjs'
6
6
  import { chalk, error, log } from '../../utils/command-helpers.mjs'
7
7
  import { init } from '../init/index.mjs'
8
8
 
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'hello-world',
3
3
  priority: 1,
4
4
  description: 'Basic function that shows how to create a handler and return a response',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'apollo-graphql',
3
3
  description: 'GraphQL function using Apollo-Server-Lambda!',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'apollo-graphql-rest',
3
3
  description: 'GraphQL function to wrap REST API using apollo-server-lambda and apollo-datasource-rest!',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'auth-fetch',
3
3
  description: 'Use `node-fetch` library and Netlify Identity to access APIs',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'create-user',
3
3
  description: 'Programmatically create a Netlify Identity user by invoking a function',
4
4
  functionType: 'serverless',
@@ -1,5 +1,6 @@
1
- const execa = require('execa')
2
- module.exports = {
1
+ import execa from 'execa'
2
+
3
+ export default {
3
4
  name: 'fauna-crud',
4
5
  description: 'CRUD function using Fauna DB',
5
6
  functionType: 'serverless',
@@ -1,5 +1,6 @@
1
- const execa = require('execa')
2
- module.exports = {
1
+ import execa from 'execa'
2
+
3
+ export default {
3
4
  name: 'fauna-graphql',
4
5
  description: 'GraphQL Backend using Fauna DB',
5
6
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'google-analytics',
3
3
  description: 'Google Analytics: proxy for GA on your domain to avoid adblock',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'graphql-gateway',
3
3
  description: 'Apollo Server Lambda Gateway stitching schemas from other GraphQL Functions!',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'hasura-event-triggered',
3
3
  description: 'Hasura Cleaning: process a Hasura event and fire off a GraphQL mutation with processed text data',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'hello',
3
3
  description: 'Basic function that shows async/await usage, and response formatting',
4
4
  functionType: 'edge',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'hello-world',
3
3
  priority: 1,
4
4
  description: 'Basic function that shows async/await usage, and response formatting',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'identity-signup',
3
3
  description: 'Identity Signup: Triggered when a new Netlify Identity user confirms. Assigns roles and extra metadata',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'image-external',
3
3
  description: 'Fetches and serves an image from an external site',
4
4
  functionType: 'edge',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'localized-content',
3
3
  description: 'Uses geolocation data to serve localized countent according to country code',
4
4
  functionType: 'edge',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'node-fetch',
3
3
  description: 'Fetch function: uses node-fetch to hit an external API without CORS issues',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'oauth-passport',
3
3
  description: 'oauth-passport: template for Oauth workflow using Passport + Express.js',
4
4
  functionType: 'serverless',
@@ -16,7 +16,7 @@
16
16
  "dependencies": {
17
17
  "cookie-parser": "^1.4.5",
18
18
  "express": "^4.17.1",
19
- "jsonwebtoken": "^8.5.1",
19
+ "jsonwebtoken": "^9.0.0",
20
20
  "passport": "^0.6.0",
21
21
  "passport-github2": "^0.1.12",
22
22
  "passport-jwt": "^4.0.0",
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'protected-function',
3
3
  description: 'Function protected Netlify Identity authentication',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'sanity-create',
3
3
  description: 'Create documents in Sanity.io',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'sanity-groq',
3
3
  description: 'Query a Sanity.io dataset with GROQ',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'scheduled-function',
3
3
  priority: 1,
4
4
  description: 'Basic implementation of a scheduled function in JavaScript.',
@@ -15,6 +15,6 @@
15
15
  "author": "Netlify",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "@netlify/functions": "^1.3.0"
18
+ "@netlify/functions": "^1.4.0"
19
19
  }
20
20
  }
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'send-email',
3
3
  description: "Send Email: Send email with no SMTP server via 'sendmail' pkg",
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'serverless-ssr',
3
3
  description: 'Dynamic serverside rendering via functions',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'set-cookie',
3
3
  description: 'Set a cookie alongside your function',
4
4
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'set-cookies',
3
3
  description: 'Create and manage HTTP cookies',
4
4
  functionType: 'edge',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'set-req-header',
3
3
  description: 'Adds a custom HTTP header to HTTP request.',
4
4
  functionType: 'edge',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'set-res-header',
3
3
  description: 'Adds a custom HTTP header to HTTP response.',
4
4
  functionType: 'edge',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'slack-rate-limit',
3
3
  description: 'Slack Rate-limit: post to Slack, at most once an hour, using Netlify Identity metadata',
4
4
  functionType: 'serverless',
@@ -1,6 +1,6 @@
1
- const chalk = require('chalk')
1
+ import chalk from 'chalk'
2
2
 
3
- module.exports = {
3
+ export default {
4
4
  name: 'stripe-charge',
5
5
  description: 'Stripe Charge: Charge a user with Stripe',
6
6
  functionType: 'serverless',
@@ -1,6 +1,6 @@
1
- const chalk = require('chalk')
1
+ import chalk from 'chalk'
2
2
 
3
- module.exports = {
3
+ export default {
4
4
  name: 'stripe-subscription',
5
5
  description: 'Stripe subscription: Create a subscription with Stripe',
6
6
  functionType: 'serverless',
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  name: 'submission-created',
3
3
  description: 'submission-created: template for event triggered function when a new Netlify Form is submitted',
4
4
  functionType: 'serverless',