netlify-cli 12.8.0 → 12.9.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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "12.8.0",
3
+ "version": "12.9.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "12.8.0",
9
+ "version": "12.9.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -82,7 +82,7 @@
82
82
  "netlify-headers-parser": "^7.1.1",
83
83
  "netlify-onegraph-internal": "0.10.1",
84
84
  "netlify-redirect-parser": "^14.1.1",
85
- "netlify-redirector": "^0.3.1",
85
+ "netlify-redirector": "^0.4.0",
86
86
  "node-fetch": "^2.6.0",
87
87
  "node-version-alias": "^1.0.1",
88
88
  "ora": "^5.0.0",
@@ -17610,9 +17610,9 @@
17610
17610
  }
17611
17611
  },
17612
17612
  "node_modules/netlify-redirector": {
17613
- "version": "0.3.1",
17614
- "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.3.1.tgz",
17615
- "integrity": "sha512-+8x07Ukx8vgKkGqTDq1GrkuCRR0DqheZ9fF5PXk6VbIChp9Qi8+psmwBV3hjocoyUvUGH7CIHLUk05aVwLN3wA=="
17613
+ "version": "0.4.0",
17614
+ "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.4.0.tgz",
17615
+ "integrity": "sha512-ssD+V9o2DD9VnilOYC+34i07IrlY8XDsh5mN+qLYA4MxCpdALKXFICcz1KzsHZabuIS5XsF1VP/HzDyx5ubJ2g=="
17616
17616
  },
17617
17617
  "node_modules/netlify/node_modules/node-fetch": {
17618
17618
  "version": "3.3.0",
@@ -37423,9 +37423,9 @@
37423
37423
  }
37424
37424
  },
37425
37425
  "netlify-redirector": {
37426
- "version": "0.3.1",
37427
- "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.3.1.tgz",
37428
- "integrity": "sha512-+8x07Ukx8vgKkGqTDq1GrkuCRR0DqheZ9fF5PXk6VbIChp9Qi8+psmwBV3hjocoyUvUGH7CIHLUk05aVwLN3wA=="
37426
+ "version": "0.4.0",
37427
+ "resolved": "https://registry.npmjs.org/netlify-redirector/-/netlify-redirector-0.4.0.tgz",
37428
+ "integrity": "sha512-ssD+V9o2DD9VnilOYC+34i07IrlY8XDsh5mN+qLYA4MxCpdALKXFICcz1KzsHZabuIS5XsF1VP/HzDyx5ubJ2g=="
37429
37429
  },
37430
37430
  "next-tick": {
37431
37431
  "version": "1.1.0",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "12.8.0",
4
+ "version": "12.9.0",
5
5
  "author": "Netlify Inc.",
6
6
  "type": "module",
7
7
  "engines": {
@@ -147,7 +147,7 @@
147
147
  "netlify-headers-parser": "^7.1.1",
148
148
  "netlify-onegraph-internal": "0.10.1",
149
149
  "netlify-redirect-parser": "^14.1.1",
150
- "netlify-redirector": "^0.3.1",
150
+ "netlify-redirector": "^0.4.0",
151
151
  "node-fetch": "^2.6.0",
152
152
  "node-version-alias": "^1.0.1",
153
153
  "ora": "^5.0.0",
@@ -168,7 +168,7 @@ export const createHandler = function (options) {
168
168
  return
169
169
  }
170
170
 
171
- handleSynchronousFunction(error, result, request, response)
171
+ handleSynchronousFunction({ error, functionName: func.name, result, request, response })
172
172
  }
173
173
  }
174
174
  }
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  import { Buffer } from 'buffer'
3
3
 
4
- import { NETLIFYDEVERR } from '../../utils/command-helpers.mjs'
4
+ import { chalk, log, NETLIFYDEVERR } from '../../utils/command-helpers.mjs'
5
5
  import renderErrorTemplate from '../render-error-template.mjs'
6
6
 
7
7
  import { detectAwsSdkError } from './utils.mjs'
@@ -16,20 +16,35 @@ const addHeaders = (headers, response) => {
16
16
  })
17
17
  }
18
18
 
19
- export const handleSynchronousFunction = function (err, result, request, response) {
20
- if (err) {
21
- return handleErr(err, request, response)
19
+ export const handleSynchronousFunction = function ({
20
+ error: invocationError,
21
+ functionName,
22
+ request,
23
+ response,
24
+ result,
25
+ }) {
26
+ if (invocationError) {
27
+ return handleErr(invocationError, request, response)
22
28
  }
23
29
 
24
30
  const { error } = validateLambdaResponse(result)
25
31
  if (error) {
26
- console.log(`${NETLIFYDEVERR} ${error}`)
32
+ log(`${NETLIFYDEVERR} ${error}`)
27
33
  return handleErr(error, request, response)
28
34
  }
29
35
 
30
36
  response.statusCode = result.statusCode
31
- addHeaders(result.headers, response)
32
- addHeaders(result.multiValueHeaders, response)
37
+
38
+ try {
39
+ addHeaders(result.headers, response)
40
+ addHeaders(result.multiValueHeaders, response)
41
+ } catch (headersError) {
42
+ formatError(headersError)
43
+
44
+ log(`${NETLIFYDEVERR} Failed to set header in function ${chalk.yellow(functionName)}: ${headersError.message}`)
45
+
46
+ return handleErr(headersError, request, response)
47
+ }
33
48
 
34
49
  if (result.body) {
35
50
  response.write(result.isBase64Encoded ? Buffer.from(result.body, 'base64') : result.body)
@@ -37,6 +52,12 @@ export const handleSynchronousFunction = function (err, result, request, respons
37
52
  response.end()
38
53
  }
39
54
 
55
+ const formatError = (err) => {
56
+ err.errorType = err.code
57
+ err.errorMessage = err.message
58
+ err.stackTrace = err.trace
59
+ }
60
+
40
61
  const formatLambdaLocalError = (err, acceptsHtml) =>
41
62
  acceptsHtml
42
63
  ? JSON.stringify({
@@ -33,6 +33,7 @@ import { NETLIFYDEVLOG, NETLIFYDEVWARN } from './command-helpers.mjs'
33
33
  import createStreamPromise from './create-stream-promise.mjs'
34
34
  import { headersForPath, parseHeaders } from './headers.mjs'
35
35
  import { createRewriter, onChanges } from './rules-proxy.mjs'
36
+ import { signRedirect } from './sign-redirect.mjs'
36
37
 
37
38
  const decompress = util.promisify(zlib.gunzip)
38
39
  const shouldGenerateETag = Symbol('Internal: response should generate ETag')
@@ -143,7 +144,7 @@ const alternativePathsFor = function (url) {
143
144
  return paths
144
145
  }
145
146
 
146
- const serveRedirect = async function ({ match, options, proxy, req, res }) {
147
+ const serveRedirect = async function ({ match, options, proxy, req, res, siteInfo }) {
147
148
  if (!match) return proxy.web(req, res, options)
148
149
 
149
150
  options = options || req.proxyOptions || {}
@@ -155,6 +156,15 @@ const serveRedirect = async function ({ match, options, proxy, req, res }) {
155
156
  })
156
157
  }
157
158
 
159
+ if (match.signingSecret) {
160
+ req.headers['x-nf-sign'] = signRedirect({
161
+ deployContext: 'dev',
162
+ secret: match.signingSecret,
163
+ siteID: siteInfo.id,
164
+ siteURL: siteInfo.url,
165
+ })
166
+ }
167
+
158
168
  if (isFunction(options.functionsPort, req.url)) {
159
169
  return proxy.web(req, res, { target: options.functionsServer })
160
170
  }
@@ -306,7 +316,7 @@ const reqToURL = function (req, pathname) {
306
316
 
307
317
  const MILLISEC_TO_SEC = 1e3
308
318
 
309
- const initializeProxy = async function ({ configPath, distDir, host, port, projectDir }) {
319
+ const initializeProxy = async function ({ configPath, distDir, host, port, projectDir, siteInfo }) {
310
320
  const proxy = httpProxy.createProxyServer({
311
321
  selfHandleResponse: true,
312
322
  target: {
@@ -370,13 +380,20 @@ const initializeProxy = async function ({ configPath, distDir, host, port, proje
370
380
  return proxy.web(req, res, req.proxyOptions)
371
381
  }
372
382
  if (req.proxyOptions && req.proxyOptions.match) {
373
- return serveRedirect({ req, res, proxy: handlers, match: req.proxyOptions.match, options: req.proxyOptions })
383
+ return serveRedirect({
384
+ req,
385
+ res,
386
+ proxy: handlers,
387
+ match: req.proxyOptions.match,
388
+ options: req.proxyOptions,
389
+ siteInfo,
390
+ })
374
391
  }
375
392
  }
376
393
 
377
394
  if (req.proxyOptions.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) {
378
395
  req.url = proxyRes.headers.location
379
- return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions })
396
+ return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions, siteInfo })
380
397
  }
381
398
 
382
399
  const responseData = []
@@ -472,7 +489,11 @@ const initializeProxy = async function ({ configPath, distDir, host, port, proje
472
489
  return handlers
473
490
  }
474
491
 
475
- const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings }, req, res) => {
492
+ const onRequest = async (
493
+ { addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings, siteInfo },
494
+ req,
495
+ res,
496
+ ) => {
476
497
  req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method)
477
498
  ? null
478
499
  : await createStreamPromise(req, BYTES_LIMIT)
@@ -509,7 +530,7 @@ const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, prox
509
530
  // We don't want to generate an ETag for 3xx redirects.
510
531
  req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400
511
532
 
512
- return serveRedirect({ req, res, proxy, match, options })
533
+ return serveRedirect({ req, res, proxy, match, options, siteInfo })
513
534
  }
514
535
 
515
536
  // The request will be served by the framework server, which means we want to
@@ -570,6 +591,7 @@ export const startProxy = async function ({
570
591
  distDir: settings.dist,
571
592
  projectDir,
572
593
  configPath,
594
+ siteInfo,
573
595
  })
574
596
 
575
597
  const rewriter = await createRewriter({
@@ -588,6 +610,7 @@ export const startProxy = async function ({
588
610
  addonsUrls,
589
611
  functionsServer,
590
612
  edgeFunctionsProxy,
613
+ siteInfo,
591
614
  })
592
615
  const primaryServer = settings.https
593
616
  ? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions)
@@ -36,6 +36,7 @@ const normalizeRedirect = function ({
36
36
  conditions: { country, language, role, ...conditions },
37
37
  from,
38
38
  query,
39
+ signed,
39
40
  ...redirect
40
41
  }) {
41
42
  return {
@@ -48,5 +49,10 @@ const normalizeRedirect = function ({
48
49
  ...(country && { Country: country }),
49
50
  ...(language && { Language: language }),
50
51
  },
52
+ ...(signed && {
53
+ sign: {
54
+ jwt_secret: signed,
55
+ },
56
+ }),
51
57
  }
52
58
  }
@@ -0,0 +1,16 @@
1
+ import jwt from 'jsonwebtoken'
2
+
3
+ // https://docs.netlify.com/routing/redirects/rewrites-proxies/#signed-proxy-redirects
4
+ export const signRedirect = ({ deployContext, secret, siteID, siteURL }) => {
5
+ const claims = {
6
+ deploy_context: deployContext,
7
+ netlify_id: siteID,
8
+ site_url: siteURL,
9
+ }
10
+ const options = {
11
+ expiresIn: '5 minutes',
12
+ issuer: 'netlify',
13
+ }
14
+
15
+ return jwt.sign(claims, secret, options)
16
+ }