netlify-cli 15.0.3 → 15.1.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "15.0.3",
4
+ "version": "15.1.1",
5
5
  "author": "Netlify Inc.",
6
6
  "type": "module",
7
7
  "engines": {
@@ -44,14 +44,15 @@
44
44
  "dependencies": {
45
45
  "@bugsnag/js": "7.20.2",
46
46
  "@fastify/static": "6.10.1",
47
- "@netlify/build": "29.11.4",
47
+ "@netlify/build": "29.11.5",
48
48
  "@netlify/build-info": "7.0.2",
49
- "@netlify/config": "20.4.2",
49
+ "@netlify/config": "20.4.3",
50
50
  "@netlify/edge-bundler": "8.14.2",
51
51
  "@netlify/framework-info": "9.8.7",
52
52
  "@netlify/local-functions-proxy": "1.1.1",
53
- "@netlify/zip-it-and-ship-it": "9.5.0",
53
+ "@netlify/zip-it-and-ship-it": "9.6.0",
54
54
  "@octokit/rest": "19.0.8",
55
+ "@skn0tt/lambda-local": "2.0.3",
55
56
  "ansi-escapes": "6.2.0",
56
57
  "ansi-styles": "6.2.1",
57
58
  "ansi-to-html": "0.7.2",
@@ -66,16 +67,16 @@
66
67
  "commander": "10.0.1",
67
68
  "comment-json": "4.2.3",
68
69
  "concordance": "5.0.4",
69
- "configstore": "5.0.1",
70
+ "configstore": "6.0.0",
70
71
  "content-type": "1.0.5",
71
72
  "cookie": "0.5.0",
72
73
  "copy-template-dir": "1.4.0",
73
74
  "cron-parser": "4.8.1",
74
75
  "debug": "4.3.4",
75
76
  "decache": "4.6.1",
76
- "dot-prop": "6.0.1",
77
+ "dot-prop": "7.2.0",
77
78
  "dotenv": "16.0.3",
78
- "env-paths": "2.2.1",
79
+ "env-paths": "3.0.0",
79
80
  "envinfo": "7.8.1",
80
81
  "etag": "1.8.1",
81
82
  "execa": "5.1.1",
@@ -100,11 +101,11 @@
100
101
  "inquirer": "6.5.2",
101
102
  "inquirer-autocomplete-prompt": "1.4.0",
102
103
  "is-docker": "3.0.0",
104
+ "is-stream": "3.0.0",
103
105
  "is-wsl": "2.2.0",
104
106
  "isexe": "2.0.0",
105
107
  "jsonwebtoken": "9.0.0",
106
108
  "jwt-decode": "3.1.2",
107
- "lambda-local": "2.0.3",
108
109
  "listr": "0.14.3",
109
110
  "locate-path": "7.2.0",
110
111
  "lodash": "4.17.21",
@@ -112,13 +113,13 @@
112
113
  "log-update": "5.0.1",
113
114
  "minimist": "1.2.8",
114
115
  "multiparty": "4.2.3",
115
- "netlify": "13.1.6",
116
+ "netlify": "13.1.7",
116
117
  "netlify-headers-parser": "7.1.2",
117
118
  "netlify-redirect-parser": "14.1.2",
118
119
  "netlify-redirector": "0.4.0",
119
120
  "node-fetch": "2.6.11",
120
121
  "node-version-alias": "3.4.1",
121
- "ora": "6.3.0",
122
+ "ora": "6.3.1",
122
123
  "p-filter": "3.0.0",
123
124
  "p-map": "5.5.0",
124
125
  "p-wait-for": "5.0.2",
@@ -129,7 +130,7 @@
129
130
  "prettyjson": "1.2.5",
130
131
  "pump": "3.0.0",
131
132
  "raw-body": "2.5.2",
132
- "read-pkg-up": "7.0.1",
133
+ "read-pkg-up": "9.1.0",
133
134
  "semver": "7.5.1",
134
135
  "source-map-support": "0.5.21",
135
136
  "string-similarity": "4.0.4",
@@ -139,7 +140,7 @@
139
140
  "terminal-link": "3.0.0",
140
141
  "through2-filter": "3.0.0",
141
142
  "through2-map": "3.0.0",
142
- "to-readable-stream": "2.1.0",
143
+ "to-readable-stream": "3.0.0",
143
144
  "toml": "3.0.0",
144
145
  "ulid": "2.3.0",
145
146
  "unixify": "1.0.0",
@@ -6,7 +6,6 @@ import { cwd, env } from 'process'
6
6
  import { runCoreSteps } from '@netlify/build'
7
7
  import { restoreConfig, updateConfig } from '@netlify/config'
8
8
  import { Option } from 'commander'
9
- import { get } from 'dot-prop'
10
9
  import inquirer from 'inquirer'
11
10
  import isObject from 'lodash/isObject.js'
12
11
  import prettyjson from 'prettyjson'
@@ -15,7 +14,7 @@ import { cancelDeploy } from '../../lib/api.mjs'
15
14
  import { getBuildOptions, runBuild } from '../../lib/build.mjs'
16
15
  import { featureFlags as edgeFunctionsFeatureFlags } from '../../lib/edge-functions/consts.mjs'
17
16
  import { normalizeFunctionsConfig } from '../../lib/functions/config.mjs'
18
- import { getLogMessage } from '../../lib/log.mjs'
17
+ import { BACKGROUND_FUNCTIONS_WARNING } from '../../lib/log.mjs'
19
18
  import { startSpinner, stopSpinner } from '../../lib/spinner.mjs'
20
19
  import {
21
20
  chalk,
@@ -74,10 +73,10 @@ const getDeployFolder = async ({ config, options, site, siteData }) => {
74
73
  let deployFolder
75
74
  if (options.dir) {
76
75
  deployFolder = resolve(cwd(), options.dir)
77
- } else if (get(config, 'build.publish')) {
78
- deployFolder = resolve(site.root, get(config, 'build.publish'))
79
- } else if (get(siteData, 'build_settings.dir')) {
80
- deployFolder = resolve(site.root, get(siteData, 'build_settings.dir'))
76
+ } else if (config?.build?.publish) {
77
+ deployFolder = resolve(site.root, config.build.publish)
78
+ } else if (siteData?.build_settings?.dir) {
79
+ deployFolder = resolve(site.root, siteData.build_settings.dir)
81
80
  }
82
81
 
83
82
  if (!deployFolder) {
@@ -138,8 +137,8 @@ const getFunctionsFolder = ({ config, options, site, siteData }) => {
138
137
  functionsFolder = resolve(cwd(), options.functions)
139
138
  } else if (funcConfig) {
140
139
  functionsFolder = resolve(site.root, funcConfig)
141
- } else if (get(siteData, 'build_settings.functions_dir')) {
142
- functionsFolder = resolve(site.root, get(siteData, 'build_settings.functions_dir'))
140
+ } else if (siteData?.build_settings?.functions_dir) {
141
+ functionsFolder = resolve(site.root, siteData.build_settings.functions_dir)
143
142
  }
144
143
  return functionsFolder
145
144
  }
@@ -232,14 +231,12 @@ const hasErrorMessage = (actual, expected) => {
232
231
  return false
233
232
  }
234
233
 
235
- const getJsonErrorMessage = (error_) => get(error_, 'json.message', '')
236
-
237
234
  const reportDeployError = ({ error_, failAndExit }) => {
238
235
  switch (true) {
239
236
  case error_.name === 'JSONHTTPError': {
240
- const message = getJsonErrorMessage(error)
237
+ const message = error_?.json?.message ?? ''
241
238
  if (hasErrorMessage(message, 'Background Functions not allowed by team plan')) {
242
- return failAndExit(`\n${getLogMessage('functions.backgroundNotSupported')}`)
239
+ return failAndExit(`\n${BACKGROUND_FUNCTIONS_WARNING}`)
243
240
  }
244
241
  warn(`JSONHTTPError: ${message} ${error_.status}`)
245
242
  warn(`\n${JSON.stringify(error_, null, ' ')}\n`)
@@ -358,8 +355,8 @@ const runDeploy = async ({
358
355
  }
359
356
 
360
357
  const siteUrl = results.deploy.ssl_url || results.deploy.url
361
- const deployUrl = get(results, 'deploy.deploy_ssl_url') || get(results, 'deploy.deploy_url')
362
- const logsUrl = `${get(results, 'deploy.admin_url')}/deploys/${get(results, 'deploy.id')}`
358
+ const deployUrl = results.deploy.deploy_ssl_url || results.deploy.deploy_url
359
+ const logsUrl = `${results.deploy.admin_url}/deploys/${results.deploy.id}`
363
360
 
364
361
  return {
365
362
  siteId: results.deploy.site_id,
@@ -616,7 +613,7 @@ const deploy = async (options, command) => {
616
613
  scope: 'functions',
617
614
  siteInfo: siteData,
618
615
  })
619
- : get(siteData, 'build_settings.env')
616
+ : siteData?.build_settings?.env
620
617
 
621
618
  const functionsConfig = normalizeFunctionsConfig({
622
619
  functionsConfig: config.functions,
@@ -1,6 +1,5 @@
1
1
  // @ts-check
2
2
  import { Option } from 'commander'
3
- import dotProp from 'dot-prop'
4
3
  import inquirer from 'inquirer'
5
4
  import isEmpty from 'lodash/isEmpty.js'
6
5
 
@@ -17,7 +16,11 @@ const persistState = ({ siteInfo, state }) => {
17
16
  state.set('siteId', siteInfo.id)
18
17
  }
19
18
 
20
- const getRepoUrl = ({ siteInfo }) => dotProp.get(siteInfo, 'build_settings.repo_url')
19
+ /**
20
+ * @param {{} | undefined} siteInfo
21
+ * @returns {string | undefined}
22
+ */
23
+ const getRepoUrl = (siteInfo) => siteInfo?.build_settings?.repo_url
21
24
 
22
25
  const logExistingAndExit = ({ siteInfo }) => {
23
26
  log()
@@ -187,7 +190,7 @@ export const init = async (options, command) => {
187
190
  // Add .netlify to .gitignore file
188
191
  await ensureNetlifyIgnore(repositoryRoot)
189
192
 
190
- const repoUrl = getRepoUrl({ siteInfo })
193
+ const repoUrl = getRepoUrl(siteInfo)
191
194
  if (repoUrl && !options.force) {
192
195
  logExistingAndExit({ siteInfo })
193
196
  }
@@ -205,7 +208,7 @@ export const init = async (options, command) => {
205
208
  log()
206
209
 
207
210
  // Check for existing CI setup
208
- const remoteBuildRepo = getRepoUrl({ siteInfo })
211
+ const remoteBuildRepo = getRepoUrl(siteInfo)
209
212
  if (remoteBuildRepo && !options.force) {
210
213
  logExistingRepoSetupAndExit({ siteName: siteInfo.name, repoUrl: remoteBuildRepo })
211
214
  }
@@ -1,5 +1,4 @@
1
1
  // @ts-check
2
- import { get } from 'dot-prop'
3
2
  import prettyjson from 'prettyjson'
4
3
 
5
4
  import { error, log, warn } from '../../utils/command-helpers.mjs'
@@ -48,8 +47,8 @@ const statusHooks = async (options, command) => {
48
47
  id: hook.id,
49
48
  disabled: hook.disabled,
50
49
  }
51
- if (get(siteData, 'build_settings.repo_url')) {
52
- data.hooks[hook.id].repo_url = get(siteData, 'build_settings.repo_url')
50
+ if (siteData.build_settings?.repo_url) {
51
+ data.hooks[hook.id].repo_url = siteData.build_settings.repo_url
53
52
  }
54
53
  })
55
54
  log(`─────────────────┐
@@ -15,7 +15,7 @@ import {
15
15
  watchDebounced,
16
16
  } from '../../utils/command-helpers.mjs'
17
17
  import { INTERNAL_FUNCTIONS_FOLDER, SERVE_FUNCTIONS_FOLDER } from '../../utils/functions/functions.mjs'
18
- import { getLogMessage } from '../log.mjs'
18
+ import { BACKGROUND_FUNCTIONS_WARNING } from '../log.mjs'
19
19
  import { getPathInProject } from '../settings.mjs'
20
20
 
21
21
  import NetlifyFunction from './netlify-function.mjs'
@@ -140,7 +140,7 @@ export class FunctionsRegistry {
140
140
  }
141
141
 
142
142
  if (func.isBackground && this.isConnected && !this.capabilities.backgroundFunctions) {
143
- warn(getLogMessage('functions.backgroundNotSupported'))
143
+ warn(BACKGROUND_FUNCTIONS_WARNING)
144
144
  }
145
145
 
146
146
  if (!func.hasValidName()) {
@@ -3,7 +3,7 @@ import { createRequire } from 'module'
3
3
  import path from 'path'
4
4
 
5
5
  import decache from 'decache'
6
- import readPkgUp from 'read-pkg-up'
6
+ import { readPackageUp } from 'read-pkg-up'
7
7
  import sourceMapSupport from 'source-map-support'
8
8
 
9
9
  import { NETLIFYDEVERR } from '../../../../../utils/command-helpers.mjs'
@@ -112,7 +112,7 @@ const netlifyConfigToZisiConfig = ({ config, projectRoot }) =>
112
112
  export default async function handler({ config, directory, errorExit, func, projectRoot }) {
113
113
  const functionsConfig = netlifyConfigToZisiConfig({ config, projectRoot })
114
114
 
115
- const packageJson = await readPkgUp(func.mainFile)
115
+ const packageJson = await readPackageUp(func.mainFile)
116
116
  const hasTypeModule = packageJson && packageJson.packageJson.type === 'module'
117
117
 
118
118
  // We must use esbuild for certain file extensions.
@@ -1,6 +1,6 @@
1
1
  import { dirname } from 'path'
2
2
 
3
- import lambdaLocal from 'lambda-local'
3
+ import lambdaLocal from '@skn0tt/lambda-local'
4
4
  import winston from 'winston'
5
5
 
6
6
  import detectNetlifyLambdaBuilder from './builders/netlify-lambda.mjs'
@@ -1,5 +1,4 @@
1
1
  // @ts-check
2
- import { get } from 'dot-prop'
3
2
  import jwtDecode from 'jwt-decode'
4
3
 
5
4
  import { NETLIFYDEVERR, NETLIFYDEVLOG, error as errorExit, log } from '../../utils/command-helpers.mjs'
@@ -94,7 +93,7 @@ export const createHandler = function (options) {
94
93
  {},
95
94
  )
96
95
  const rawQuery = new URLSearchParams(request.query).toString()
97
- const protocol = get(options, 'config.dev.https') ? 'https' : 'http'
96
+ const protocol = options.config?.dev?.https ? 'https' : 'http'
98
97
  const url = new URL(requestPath, `${protocol}://${request.get('host') || 'localhost'}`)
99
98
  url.search = rawQuery
100
99
  const rawUrl = url.toString()
@@ -1,6 +1,8 @@
1
1
  // @ts-check
2
2
  import { Buffer } from 'buffer'
3
3
 
4
+ import { isStream } from 'is-stream'
5
+
4
6
  import { chalk, log, NETLIFYDEVERR } from '../../utils/command-helpers.mjs'
5
7
  import renderErrorTemplate from '../render-error-template.mjs'
6
8
 
@@ -47,6 +49,12 @@ export const handleSynchronousFunction = function ({
47
49
  }
48
50
 
49
51
  if (result.body) {
52
+ if (isStream(result.body)) {
53
+ result.body.pipe(response)
54
+
55
+ return
56
+ }
57
+
50
58
  response.write(result.isBase64Encoded ? Buffer.from(result.body, 'base64') : result.body)
51
59
  }
52
60
  response.end()
@@ -97,8 +105,8 @@ const validateLambdaResponse = (lambdaResponse) => {
97
105
  error: `Your function response must have a numerical statusCode. You gave: $ ${lambdaResponse.statusCode}`,
98
106
  }
99
107
  }
100
- if (lambdaResponse.body && typeof lambdaResponse.body !== 'string') {
101
- return { error: `Your function response must have a string body. You gave: ${lambdaResponse.body}` }
108
+ if (lambdaResponse.body && typeof lambdaResponse.body !== 'string' && !isStream(lambdaResponse.body)) {
109
+ return { error: `Your function response must have a string or a stream body. You gave: ${lambdaResponse.body}` }
102
110
  }
103
111
 
104
112
  return {}
@@ -1,12 +1,12 @@
1
1
  // @ts-check
2
2
  import { chalk, warn } from '../../utils/command-helpers.mjs'
3
- import { getLogMessage } from '../log.mjs'
3
+ import { MISSING_AWS_SDK_WARNING } from '../log.mjs'
4
4
 
5
5
  export const detectAwsSdkError = ({ error }) => {
6
6
  const isAwsSdkError = error && error.errorMessage && error.errorMessage.includes("Cannot find module 'aws-sdk'")
7
7
 
8
8
  if (isAwsSdkError) {
9
- warn(getLogMessage('functions.missingAwsSdk'))
9
+ warn(MISSING_AWS_SDK_WARNING)
10
10
  }
11
11
  }
12
12
 
package/src/lib/log.mjs CHANGED
@@ -1,27 +1,18 @@
1
- import dotProp from 'dot-prop'
2
-
3
1
  import { chalk } from '../utils/command-helpers.mjs'
4
2
 
5
3
  const RED_BACKGROUND = chalk.red('-background')
6
4
  const [PRO, BUSINESS, ENTERPRISE] = ['Pro', 'Business', 'Enterprise'].map((plan) => chalk.magenta(plan))
7
- const BACKGROUND_FUNCTIONS_WARNING = `A serverless function ending in \`${RED_BACKGROUND}\` was detected.
5
+ export const BACKGROUND_FUNCTIONS_WARNING = `A serverless function ending in \`${RED_BACKGROUND}\` was detected.
8
6
  Your team’s current plan doesn’t support Background Functions, which have names ending in \`${RED_BACKGROUND}\`.
9
7
  To be able to deploy this function successfully either:
10
8
  - change the function name to remove \`${RED_BACKGROUND}\` and execute it synchronously
11
9
  - upgrade your team plan to a level that supports Background Functions (${PRO}, ${BUSINESS}, or ${ENTERPRISE})
12
10
  `
13
- const MISSING_AWS_SDK_WARNING = `A function has thrown an error due to a missing dependency: ${chalk.yellow('aws-sdk')}.
11
+ export const MISSING_AWS_SDK_WARNING = `A function has thrown an error due to a missing dependency: ${chalk.yellow(
12
+ 'aws-sdk',
13
+ )}.
14
14
  You should add this module to the project's dependencies, using your package manager of choice:
15
15
 
16
16
  ${chalk.yellow('npm install aws-sdk --save')} or ${chalk.yellow('yarn add aws-sdk')}
17
17
 
18
18
  For more information, see https://ntl.fyi/cli-aws-sdk.`
19
-
20
- const messages = {
21
- functions: {
22
- backgroundNotSupported: BACKGROUND_FUNCTIONS_WARNING,
23
- missingAwsSdk: MISSING_AWS_SDK_WARNING,
24
- },
25
- }
26
-
27
- export const getLogMessage = (key) => dotProp.get(messages, key, 'Missing Log Message Key')
package/src/utils/dev.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  // @ts-check
2
2
  import process from 'process'
3
3
 
4
- import { get } from 'dot-prop'
5
4
  import getPort from 'get-port'
6
5
  import isEmpty from 'lodash/isEmpty.js'
7
6
 
@@ -112,7 +111,7 @@ export const getSiteInformation = async ({ api, offline, site, siteInfo }) => {
112
111
  backgroundFunctions: supportsBackgroundFunctions(account),
113
112
  },
114
113
  timeouts: {
115
- syncFunctions: get(siteInfo, 'functions_config.timeout', SYNCHRONOUS_FUNCTION_TIMEOUT),
114
+ syncFunctions: siteInfo.functions_config?.timeout ?? SYNCHRONOUS_FUNCTION_TIMEOUT,
116
115
  backgroundFunctions: BACKGROUND_FUNCTION_TIMEOUT,
117
116
  },
118
117
  }
@@ -11,7 +11,7 @@ import zlib from 'zlib'
11
11
 
12
12
  import contentType from 'content-type'
13
13
  import cookie from 'cookie'
14
- import { get } from 'dot-prop'
14
+ import { getProperty } from 'dot-prop'
15
15
  import generateETag from 'etag'
16
16
  import getAvailablePort from 'get-port'
17
17
  import httpProxy from 'http-proxy'
@@ -210,7 +210,7 @@ const serveRedirect = async function ({ env, match, options, proxy, req, res, si
210
210
  if ((jwtValue.exp || 0) < Math.round(Date.now() / MILLISEC_TO_SEC)) {
211
211
  console.warn(NETLIFYDEVWARN, 'Expired JWT provided in request', req.url)
212
212
  } else {
213
- const presentedRoles = get(jwtValue, options.jwtRolePath) || []
213
+ const presentedRoles = getProperty(jwtValue, options.jwtRolePath) || []
214
214
  if (!Array.isArray(presentedRoles)) {
215
215
  console.warn(NETLIFYDEVWARN, `Invalid roles value provided in JWT ${options.jwtRolePath}`, presentedRoles)
216
216
  res.writeHead(400)
@@ -2,7 +2,7 @@ import fs from 'fs'
2
2
  import path from 'path'
3
3
  import process from 'process'
4
4
 
5
- import dotProp from 'dot-prop'
5
+ import { deleteProperty, getProperty, hasProperty, setProperty } from 'dot-prop'
6
6
  import { findUpSync } from 'find-up'
7
7
  import writeFileAtomic from 'write-file-atomic'
8
8
 
@@ -75,7 +75,7 @@ export default class StateConfig {
75
75
  // TODO figure out cleaner way of grabbing ENV vars
76
76
  return process.env.NETLIFY_SITE_ID
77
77
  }
78
- return dotProp.get(this.all, key)
78
+ return getProperty(this.all, key)
79
79
  }
80
80
 
81
81
  set(...args) {
@@ -84,22 +84,22 @@ export default class StateConfig {
84
84
 
85
85
  if (args.length === 1) {
86
86
  Object.entries(key).forEach(([keyPart, value]) => {
87
- dotProp.set(config, keyPart, value)
87
+ setProperty(config, keyPart, value)
88
88
  })
89
89
  } else {
90
- dotProp.set(config, key, val)
90
+ setProperty(config, key, val)
91
91
  }
92
92
 
93
93
  this.all = config
94
94
  }
95
95
 
96
96
  has(key) {
97
- return dotProp.has(this.all, key)
97
+ return hasProperty(this.all, key)
98
98
  }
99
99
 
100
100
  delete(key) {
101
101
  const config = this.all
102
- dotProp.delete(config, key)
102
+ deleteProperty(config, key)
103
103
  this.all = config
104
104
  }
105
105