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
@@ -0,0 +1,129 @@
1
+ // @ts-check
2
+ import { promises as fs } from 'fs'
3
+ import path from 'path'
4
+ import process from 'process'
5
+
6
+ import { INTERNAL_EDGE_FUNCTIONS_FOLDER } from '../lib/edge-functions/consts.mjs'
7
+ import { getPathInProject } from '../lib/settings.mjs'
8
+
9
+ import { error } from './command-helpers.mjs'
10
+ import { startFrameworkServer } from './framework-server.mjs'
11
+ import { INTERNAL_FUNCTIONS_FOLDER } from './functions/index.mjs'
12
+
13
+ const netlifyBuildPromise = import('@netlify/build')
14
+
15
+ // Copies `netlify.toml`, if one is defined, into the `.netlify` internal
16
+ // directory and returns the path to its new location.
17
+ const copyConfig = async ({ configPath, siteRoot }) => {
18
+ const newConfigPath = path.resolve(siteRoot, getPathInProject(['netlify.toml']))
19
+
20
+ try {
21
+ await fs.copyFile(configPath, newConfigPath)
22
+ } catch {
23
+ // no-op
24
+ }
25
+
26
+ return newConfigPath
27
+ }
28
+
29
+ const cleanInternalDirectory = async (basePath) => {
30
+ const ops = [INTERNAL_FUNCTIONS_FOLDER, INTERNAL_EDGE_FUNCTIONS_FOLDER, 'netlify.toml'].map((name) => {
31
+ const fullPath = path.resolve(basePath, getPathInProject([name]))
32
+
33
+ return fs.rm(fullPath, { force: true, recursive: true })
34
+ })
35
+
36
+ await Promise.all(ops)
37
+ }
38
+
39
+ const getBuildOptions = ({
40
+ cachedConfig,
41
+ options: { configPath, context, cwd = process.cwd(), debug, dry, offline, quiet, saveConfig },
42
+ }) => ({
43
+ cachedConfig,
44
+ configPath,
45
+ siteId: cachedConfig.siteInfo.id,
46
+ token: cachedConfig.token,
47
+ dry,
48
+ debug,
49
+ context,
50
+ mode: 'cli',
51
+ telemetry: false,
52
+ buffer: false,
53
+ offline,
54
+ cwd,
55
+ quiet,
56
+ saveConfig,
57
+ })
58
+
59
+ const runNetlifyBuild = async ({ cachedConfig, options, settings, site, timeline = 'build' }) => {
60
+ const { default: buildSite, startDev } = await netlifyBuildPromise
61
+ const sharedOptions = getBuildOptions({
62
+ cachedConfig,
63
+ options,
64
+ })
65
+ const devCommand = async (settingsOverrides = {}) => {
66
+ const { ipVersion } = await startFrameworkServer({
67
+ settings: {
68
+ ...settings,
69
+ ...settingsOverrides,
70
+ },
71
+ })
72
+
73
+ settings.frameworkHost = ipVersion === 6 ? '::1' : '127.0.0.1'
74
+ }
75
+
76
+ if (timeline === 'build') {
77
+ // Start by cleaning the internal directory, as it may have artifacts left
78
+ // by previous builds.
79
+ await cleanInternalDirectory(site.root)
80
+
81
+ // Copy `netlify.toml` into the internal directory. This will be the new
82
+ // location of the config file for the duration of the command.
83
+ const tempConfigPath = await copyConfig({ configPath: cachedConfig.configPath, siteRoot: site.root })
84
+ const buildSiteOptions = {
85
+ ...sharedOptions,
86
+ outputConfigPath: tempConfigPath,
87
+ saveConfig: true,
88
+ }
89
+
90
+ // Run Netlify Build using the main entry point.
91
+ const { success } = await buildSite(buildSiteOptions)
92
+
93
+ if (!success) {
94
+ error('Could not start local server due to a build error')
95
+
96
+ return {}
97
+ }
98
+
99
+ // Start the dev server, forcing the usage of a static server as opposed to
100
+ // the framework server.
101
+ await devCommand({
102
+ command: undefined,
103
+ useStaticServer: true,
104
+ })
105
+
106
+ return { configPath: tempConfigPath }
107
+ }
108
+
109
+ const startDevOptions = {
110
+ ...sharedOptions,
111
+
112
+ // Set `quiet` to suppress non-essential output from Netlify Build unless
113
+ // the `debug` flag is set.
114
+ quiet: !options.debug,
115
+ }
116
+
117
+ // Run Netlify Build using the `startDev` entry point.
118
+ const { error: startDevError, success } = await startDev(devCommand, startDevOptions)
119
+
120
+ if (!success) {
121
+ error(`Could not start local development server\n\n${startDevError.message}\n\n${startDevError.stack}`)
122
+ }
123
+
124
+ return {}
125
+ }
126
+
127
+ export const runDevTimeline = (options) => runNetlifyBuild({ ...options, timeline: 'dev' })
128
+
129
+ export const runBuildTimeline = (options) => runNetlifyBuild({ ...options, timeline: 'build' })
@@ -0,0 +1,120 @@
1
+ // @ts-check
2
+ import process from 'process'
3
+
4
+ import execa from 'execa'
5
+ import stripAnsiCc from 'strip-ansi-control-characters'
6
+
7
+ import { chalk, log, NETLIFYDEVERR, NETLIFYDEVWARN } from './command-helpers.mjs'
8
+ import { processOnExit } from './dev.mjs'
9
+
10
+ /**
11
+ * @type {(() => Promise<void>)[]} - array of functions to run before the process exits
12
+ */
13
+ const cleanupWork = []
14
+
15
+ let cleanupStarted = false
16
+
17
+ /**
18
+ * @param {() => Promise<void>} job
19
+ */
20
+ export const addCleanupJob = (job) => {
21
+ cleanupWork.push(job)
22
+ }
23
+
24
+ /**
25
+ * @param {object} input
26
+ * @param {number=} input.exitCode The exit code to return when exiting the process after cleanup
27
+ */
28
+ const cleanupBeforeExit = async ({ exitCode }) => {
29
+ // If cleanup has started, then wherever started it will be responsible for exiting
30
+ if (!cleanupStarted) {
31
+ cleanupStarted = true
32
+ try {
33
+ await Promise.all(cleanupWork.map((cleanup) => cleanup()))
34
+ } finally {
35
+ process.exit(exitCode)
36
+ }
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Run a command and pipe stdout, stderr and stdin
42
+ * @param {string} command
43
+ * @param {NodeJS.ProcessEnv} env
44
+ * @returns {execa.ExecaChildProcess<string>}
45
+ */
46
+ export const runCommand = (command, env = {}, spinner = null) => {
47
+ const commandProcess = execa.command(command, {
48
+ preferLocal: true,
49
+ // we use reject=false to avoid rejecting synchronously when the command doesn't exist
50
+ reject: false,
51
+ env,
52
+ // windowsHide needs to be false for child process to terminate properly on Windows
53
+ windowsHide: false,
54
+ })
55
+
56
+ // This ensures that an active spinner stays at the bottom of the commandline
57
+ // even though the actual framework command might be outputting stuff
58
+ const pipeDataWithSpinner = (writeStream, chunk) => {
59
+ if (spinner && spinner.isSpinning) {
60
+ spinner.clear()
61
+ spinner.isSilent = true
62
+ }
63
+ writeStream.write(chunk, () => {
64
+ if (spinner && spinner.isSpinning) {
65
+ spinner.isSilent = false
66
+ spinner.render()
67
+ }
68
+ })
69
+ }
70
+
71
+ commandProcess.stdout.pipe(stripAnsiCc.stream()).on('data', pipeDataWithSpinner.bind(null, process.stdout))
72
+ commandProcess.stderr.pipe(stripAnsiCc.stream()).on('data', pipeDataWithSpinner.bind(null, process.stderr))
73
+ process.stdin.pipe(commandProcess.stdin)
74
+
75
+ // we can't try->await->catch since we don't want to block on the framework server which
76
+ // is a long running process
77
+ // eslint-disable-next-line promise/catch-or-return
78
+ commandProcess
79
+ // eslint-disable-next-line promise/prefer-await-to-then
80
+ .then(async () => {
81
+ const result = await commandProcess
82
+ const [commandWithoutArgs] = command.split(' ')
83
+ if (result.failed && isNonExistingCommandError({ command: commandWithoutArgs, error: result })) {
84
+ log(
85
+ NETLIFYDEVERR,
86
+ `Failed running command: ${command}. Please verify ${chalk.magenta(`'${commandWithoutArgs}'`)} exists`,
87
+ )
88
+ } else {
89
+ const errorMessage = result.failed
90
+ ? `${NETLIFYDEVERR} ${result.shortMessage}`
91
+ : `${NETLIFYDEVWARN} "${command}" exited with code ${result.exitCode}`
92
+
93
+ log(`${errorMessage}. Shutting down Netlify Dev server`)
94
+ }
95
+
96
+ return await cleanupBeforeExit({ exitCode: 1 })
97
+ })
98
+ processOnExit(async () => await cleanupBeforeExit({}))
99
+
100
+ return commandProcess
101
+ }
102
+
103
+ const isNonExistingCommandError = ({ command, error: commandError }) => {
104
+ // `ENOENT` is only returned for non Windows systems
105
+ // See https://github.com/sindresorhus/execa/pull/447
106
+ if (commandError.code === 'ENOENT') {
107
+ return true
108
+ }
109
+
110
+ // if the command is a package manager we let it report the error
111
+ if (['yarn', 'npm'].includes(command)) {
112
+ return false
113
+ }
114
+
115
+ // this only works on English versions of Windows
116
+ return (
117
+ typeof commandError.message === 'string' &&
118
+ commandError.message.includes('is not recognized as an internal or external command')
119
+ )
120
+ }
@@ -6,7 +6,7 @@ import dotProp from 'dot-prop'
6
6
  import findUp from 'find-up'
7
7
  import writeFileAtomic from 'write-file-atomic'
8
8
 
9
- import { getPathInProject } from '../lib/settings.cjs'
9
+ import { getPathInProject } from '../lib/settings.mjs'
10
10
 
11
11
  const STATE_PATH = getPathInProject(['state.json'])
12
12
  const permissionError = "You don't have access to this file."
@@ -0,0 +1,34 @@
1
+ // @ts-check
2
+ import path from 'path'
3
+
4
+ import fastifyStatic from '@fastify/static'
5
+ import Fastify from 'fastify'
6
+
7
+ import { log, NETLIFYDEVLOG } from './command-helpers.mjs'
8
+
9
+ export const startStaticServer = async ({ settings }) => {
10
+ const server = Fastify()
11
+ const rootPath = path.resolve(settings.dist)
12
+ server.register(fastifyStatic, {
13
+ root: rootPath,
14
+ etag: false,
15
+ acceptRanges: false,
16
+ lastModified: false,
17
+ })
18
+
19
+ server.setNotFoundHandler((_req, res) => {
20
+ res.code(404).sendFile('404.html', rootPath)
21
+ })
22
+
23
+ server.addHook('onRequest', (req, reply, done) => {
24
+ reply.header('X-Powered-by', 'netlify-dev')
25
+ const validMethods = ['GET', 'HEAD']
26
+ if (!validMethods.includes(req.method)) {
27
+ reply.code(405).send('Method Not Allowed')
28
+ }
29
+ done()
30
+ })
31
+
32
+ await server.listen({ port: settings.frameworkPort })
33
+ log(`\n${NETLIFYDEVLOG} Static server listening to`, settings.frameworkPort)
34
+ }
@@ -0,0 +1,15 @@
1
+ // @ts-check
2
+ import { BANG, chalk } from './command-helpers.mjs'
3
+
4
+ export const getGeoCountryArgParser = (exampleCommand) => (arg) => {
5
+ // Validate that the arg passed is two letters only for country
6
+ // See https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
7
+ if (!/^[a-z]{2}$/i.test(arg)) {
8
+ throw new Error(
9
+ `The geo country code must use a two letter abbreviation.
10
+ ${chalk.red(BANG)} Example:
11
+ ${exampleCommand}`,
12
+ )
13
+ }
14
+ return arg.toUpperCase()
15
+ }