netlify-cli 16.2.0 → 16.3.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.
- package/README.md +0 -12
- package/npm-shrinkwrap.json +2211 -668
- package/package.json +5 -5
- package/src/commands/lm/lm-info.mjs +1 -1
- package/src/commands/lm/lm-install.mjs +1 -1
- package/src/commands/lm/lm-setup.mjs +1 -1
- package/src/commands/lm/lm.mjs +4 -2
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/headers.mjs +3 -0
- package/src/lib/edge-functions/proxy.mjs +6 -10
- package/src/lib/edge-functions/registry.mjs +6 -1
- package/src/lib/functions/netlify-function.mjs +12 -4
- package/src/lib/functions/registry.mjs +4 -4
- package/src/lib/functions/server.mjs +5 -2
- package/src/utils/headers.mjs +1 -0
- package/src/utils/proxy.mjs +9 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "16.
|
|
4
|
+
"version": "16.3.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@bugsnag/js": "7.20.2",
|
|
46
46
|
"@fastify/static": "6.10.2",
|
|
47
|
-
"@netlify/build": "29.20.
|
|
48
|
-
"@netlify/build-info": "7.
|
|
49
|
-
"@netlify/config": "20.8.
|
|
47
|
+
"@netlify/build": "29.20.12",
|
|
48
|
+
"@netlify/build-info": "7.8.0",
|
|
49
|
+
"@netlify/config": "20.8.1",
|
|
50
50
|
"@netlify/edge-bundler": "8.19.0",
|
|
51
51
|
"@netlify/local-functions-proxy": "1.1.1",
|
|
52
52
|
"@netlify/serverless-functions-api": "1.7.3",
|
|
53
|
-
"@netlify/zip-it-and-ship-it": "9.17.
|
|
53
|
+
"@netlify/zip-it-and-ship-it": "9.17.3",
|
|
54
54
|
"@octokit/rest": "19.0.13",
|
|
55
55
|
"ansi-escapes": "6.2.0",
|
|
56
56
|
"ansi-styles": "6.2.1",
|
|
@@ -37,4 +37,4 @@ const lmInfo = async () => {
|
|
|
37
37
|
* @returns
|
|
38
38
|
*/
|
|
39
39
|
export const createLmInfoCommand = (program) =>
|
|
40
|
-
program.command('lm:info').description('Show large media requirements information.').action(lmInfo)
|
|
40
|
+
program.command('lm:info', { hidden: true }).description('Show large media requirements information.').action(lmInfo)
|
|
@@ -20,7 +20,7 @@ const lmInstall = async ({ force }) => {
|
|
|
20
20
|
*/
|
|
21
21
|
export const createLmInstallCommand = (program) =>
|
|
22
22
|
program
|
|
23
|
-
.command('lm:install')
|
|
23
|
+
.command('lm:install', { hidden: true })
|
|
24
24
|
.alias('lm:init')
|
|
25
25
|
.description(
|
|
26
26
|
`Configures your computer to use Netlify Large Media
|
|
@@ -97,7 +97,7 @@ const lmSetup = async (options, command) => {
|
|
|
97
97
|
*/
|
|
98
98
|
export const createLmSetupCommand = (program) =>
|
|
99
99
|
program
|
|
100
|
-
.command('lm:setup')
|
|
100
|
+
.command('lm:setup', { hidden: true })
|
|
101
101
|
.description('Configures your site to use Netlify Large Media')
|
|
102
102
|
.option('-s, --skip-install', 'Skip the credentials helper installation check')
|
|
103
103
|
.option('-f, --force-install', 'Force the credentials helper installation')
|
package/src/commands/lm/lm.mjs
CHANGED
|
@@ -25,8 +25,10 @@ export const createLmCommand = (program) => {
|
|
|
25
25
|
createLmUninstallCommand(program)
|
|
26
26
|
|
|
27
27
|
program
|
|
28
|
-
.command('lm')
|
|
29
|
-
.description(
|
|
28
|
+
.command('lm', { hidden: true })
|
|
29
|
+
.description(
|
|
30
|
+
'[Deprecated and will be removed from future versions] Handle Netlify Large Media operations\nThe lm command will help you manage large media for a site',
|
|
31
|
+
)
|
|
30
32
|
.addExamples(['netlify lm:info', 'netlify lm:install', 'netlify lm:setup'])
|
|
31
33
|
.action(lm)
|
|
32
34
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { env } from 'process'
|
|
2
2
|
|
|
3
|
-
const latestBootstrapURL = 'https://
|
|
3
|
+
const latestBootstrapURL = 'https://64f73321fdd56900083fa618--edge.netlify.com/bootstrap/index-combined.ts'
|
|
4
4
|
|
|
5
5
|
export const getBootstrapURL = () => env.NETLIFY_EDGE_BOOTSTRAP || latestBootstrapURL
|
|
@@ -5,10 +5,13 @@ export const headers = {
|
|
|
5
5
|
DeployID: 'x-nf-deploy-id',
|
|
6
6
|
FeatureFlags: 'x-nf-feature-flags',
|
|
7
7
|
ForwardedHost: 'x-forwarded-host',
|
|
8
|
+
ForwardedProtocol: 'x-forwarded-proto',
|
|
8
9
|
Functions: 'x-nf-edge-functions',
|
|
9
10
|
InvocationMetadata: 'x-nf-edge-functions-metadata',
|
|
10
11
|
Geo: 'x-nf-geo',
|
|
11
12
|
Passthrough: 'x-nf-passthrough',
|
|
13
|
+
PassthroughHost: 'x-nf-passthrough-host',
|
|
14
|
+
PassthroughProtocol: 'x-nf-passthrough-proto',
|
|
12
15
|
IP: 'x-nf-client-connection-ip',
|
|
13
16
|
Site: 'X-NF-Site-Info',
|
|
14
17
|
DebugLogging: 'x-nf-debug-logging',
|
|
@@ -78,6 +78,7 @@ export const createAccountInfoHeader = (accountInfo = {}) => {
|
|
|
78
78
|
* @param {boolean=} config.offline
|
|
79
79
|
* @param {*} config.passthroughPort
|
|
80
80
|
* @param {*} config.projectDir
|
|
81
|
+
* @param {*} config.settings
|
|
81
82
|
* @param {*} config.siteInfo
|
|
82
83
|
* @param {*} config.state
|
|
83
84
|
* @returns
|
|
@@ -96,6 +97,7 @@ export const initializeProxy = async ({
|
|
|
96
97
|
offline,
|
|
97
98
|
passthroughPort,
|
|
98
99
|
projectDir,
|
|
100
|
+
settings,
|
|
99
101
|
siteInfo,
|
|
100
102
|
state,
|
|
101
103
|
}) => {
|
|
@@ -146,7 +148,7 @@ export const initializeProxy = async ({
|
|
|
146
148
|
await registry.initialize()
|
|
147
149
|
|
|
148
150
|
const url = new URL(req.url, `http://${LOCAL_HOST}:${mainPort}`)
|
|
149
|
-
const { functionNames, invocationMetadata, orphanedDeclarations } = registry.matchURLPath(url.pathname)
|
|
151
|
+
const { functionNames, invocationMetadata, orphanedDeclarations } = registry.matchURLPath(url.pathname, req.method)
|
|
150
152
|
|
|
151
153
|
// If the request matches a config declaration for an Edge Function without
|
|
152
154
|
// a matching function file, we warn the user.
|
|
@@ -167,28 +169,22 @@ export const initializeProxy = async ({
|
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
const featureFlags = ['edge_functions_bootstrap_failure_mode']
|
|
170
|
-
const forwardedHost = `localhost:${passthroughPort}`
|
|
171
172
|
|
|
172
173
|
req[headersSymbol] = {
|
|
173
174
|
[headers.FeatureFlags]: getFeatureFlagsHeader(featureFlags),
|
|
174
|
-
[headers.
|
|
175
|
+
[headers.ForwardedProtocol]: settings.https ? 'https:' : 'http:',
|
|
175
176
|
[headers.Functions]: functionNames.join(','),
|
|
176
177
|
[headers.InvocationMetadata]: getInvocationMetadataHeader(invocationMetadata),
|
|
177
178
|
[headers.IP]: LOCAL_HOST,
|
|
178
179
|
[headers.Passthrough]: 'passthrough',
|
|
180
|
+
[headers.PassthroughHost]: `localhost:${passthroughPort}`,
|
|
181
|
+
[headers.PassthroughProtocol]: 'http:',
|
|
179
182
|
}
|
|
180
183
|
|
|
181
184
|
if (debug) {
|
|
182
185
|
req[headersSymbol][headers.DebugLogging] = '1'
|
|
183
186
|
}
|
|
184
187
|
|
|
185
|
-
// If we're using a different port for passthrough requests, which is the
|
|
186
|
-
// case when the CLI is running on HTTPS, use it on the Host header so
|
|
187
|
-
// that the request URL inside the edge function is something accessible.
|
|
188
|
-
if (mainPort !== passthroughPort) {
|
|
189
|
-
req[headersSymbol].host = forwardedHost
|
|
190
|
-
}
|
|
191
|
-
|
|
192
188
|
return `http://${LOCAL_HOST}:${isolatePort}`
|
|
193
189
|
}
|
|
194
190
|
}
|
|
@@ -302,8 +302,9 @@ export class EdgeFunctionsRegistry {
|
|
|
302
302
|
|
|
303
303
|
/**
|
|
304
304
|
* @param {string} urlPath
|
|
305
|
+
* @param {string} method
|
|
305
306
|
*/
|
|
306
|
-
matchURLPath(urlPath) {
|
|
307
|
+
matchURLPath(urlPath, method) {
|
|
307
308
|
const declarations = this.#bundler.mergeDeclarations(
|
|
308
309
|
this.#declarationsFromTOML,
|
|
309
310
|
this.#userFunctionConfigs,
|
|
@@ -330,6 +331,10 @@ export class EdgeFunctionsRegistry {
|
|
|
330
331
|
const routeIndexes = []
|
|
331
332
|
|
|
332
333
|
routes.forEach((route, index) => {
|
|
334
|
+
if (route.methods && route.methods.length !== 0 && !route.methods.includes(method)) {
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
|
|
333
338
|
if (!route.pattern.test(urlPath)) {
|
|
334
339
|
return
|
|
335
340
|
}
|
|
@@ -158,12 +158,22 @@ export default class NetlifyFunction {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Matches all routes agains the incoming request. If a match is found, then the matched route is returned.
|
|
163
|
+
* @param {string} rawPath
|
|
164
|
+
* @param {string} method
|
|
165
|
+
* @returns matched route
|
|
166
|
+
*/
|
|
167
|
+
async matchURLPath(rawPath, method) {
|
|
162
168
|
await this.buildQueue
|
|
163
169
|
|
|
164
170
|
const path = (rawPath.endsWith('/') ? rawPath.slice(0, -1) : rawPath).toLowerCase()
|
|
165
171
|
const { routes = [] } = this.buildData
|
|
166
|
-
|
|
172
|
+
return routes.find(({ expression, literal, methods }) => {
|
|
173
|
+
if (methods.length !== 0 && !methods.includes(method)) {
|
|
174
|
+
return false
|
|
175
|
+
}
|
|
176
|
+
|
|
167
177
|
if (literal !== undefined) {
|
|
168
178
|
return path === literal
|
|
169
179
|
}
|
|
@@ -176,8 +186,6 @@ export default class NetlifyFunction {
|
|
|
176
186
|
|
|
177
187
|
return false
|
|
178
188
|
})
|
|
179
|
-
|
|
180
|
-
return isMatch
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
get url() {
|
|
@@ -122,12 +122,12 @@ export class FunctionsRegistry {
|
|
|
122
122
|
return this.functions.get(name)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
async getFunctionForURLPath(urlPath) {
|
|
125
|
+
async getFunctionForURLPath(urlPath, method) {
|
|
126
126
|
for (const func of this.functions.values()) {
|
|
127
|
-
const
|
|
127
|
+
const route = await func.matchURLPath(urlPath, method)
|
|
128
128
|
|
|
129
|
-
if (
|
|
130
|
-
return func
|
|
129
|
+
if (route) {
|
|
130
|
+
return { func, route }
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -7,7 +7,7 @@ import jwtDecode from 'jwt-decode'
|
|
|
7
7
|
|
|
8
8
|
import { NETLIFYDEVERR, NETLIFYDEVLOG, error as errorExit, log } from '../../utils/command-helpers.mjs'
|
|
9
9
|
import { CLOCKWORK_USERAGENT, getFunctionsDistPath, getInternalFunctionsDir } from '../../utils/functions/index.mjs'
|
|
10
|
-
import { NFFunctionName } from '../../utils/headers.mjs'
|
|
10
|
+
import { NFFunctionName, NFFunctionRoute } from '../../utils/headers.mjs'
|
|
11
11
|
import { headers as efHeaders } from '../edge-functions/headers.mjs'
|
|
12
12
|
import { getGeoLocation } from '../geo-location.mjs'
|
|
13
13
|
|
|
@@ -56,11 +56,13 @@ export const createHandler = function (options) {
|
|
|
56
56
|
const { functionsRegistry } = options
|
|
57
57
|
|
|
58
58
|
return async function handler(request, response) {
|
|
59
|
-
// If
|
|
59
|
+
// If these headers are set, it means we've already matched a function and we
|
|
60
60
|
// can just grab its name directly. We delete the header from the request
|
|
61
61
|
// because we don't want to expose it to user code.
|
|
62
62
|
let functionName = request.header(NFFunctionName)
|
|
63
63
|
delete request.headers[NFFunctionName]
|
|
64
|
+
const functionRoute = request.header(NFFunctionRoute)
|
|
65
|
+
delete request.headers[NFFunctionRoute]
|
|
64
66
|
|
|
65
67
|
// If we didn't match a function with a custom route, let's try to match
|
|
66
68
|
// using the fixed URL format.
|
|
@@ -148,6 +150,7 @@ export const createHandler = function (options) {
|
|
|
148
150
|
isBase64Encoded,
|
|
149
151
|
rawUrl,
|
|
150
152
|
rawQuery,
|
|
153
|
+
route: functionRoute,
|
|
151
154
|
}
|
|
152
155
|
|
|
153
156
|
const clientContext = buildClientContext(request.headers) || {}
|
package/src/utils/headers.mjs
CHANGED
package/src/utils/proxy.mjs
CHANGED
|
@@ -31,7 +31,7 @@ import renderErrorTemplate from '../lib/render-error-template.mjs'
|
|
|
31
31
|
|
|
32
32
|
import { NETLIFYDEVLOG, NETLIFYDEVWARN, log, chalk } from './command-helpers.mjs'
|
|
33
33
|
import createStreamPromise from './create-stream-promise.mjs'
|
|
34
|
-
import { headersForPath, parseHeaders, NFFunctionName, NFRequestID } from './headers.mjs'
|
|
34
|
+
import { headersForPath, parseHeaders, NFFunctionName, NFRequestID, NFFunctionRoute } from './headers.mjs'
|
|
35
35
|
import { generateRequestID } from './request-id.mjs'
|
|
36
36
|
import { createRewriter, onChanges } from './rules-proxy.mjs'
|
|
37
37
|
import { signRedirect } from './sign-redirect.mjs'
|
|
@@ -328,7 +328,8 @@ const serveRedirect = async function ({ env, functionsRegistry, match, options,
|
|
|
328
328
|
return proxy.web(req, res, { target: options.functionsServer })
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
const functionWithCustomRoute =
|
|
331
|
+
const functionWithCustomRoute =
|
|
332
|
+
functionsRegistry && (await functionsRegistry.getFunctionForURLPath(destURL, req.method))
|
|
332
333
|
const destStaticFile = await getStatic(dest.pathname, options.publicFolder)
|
|
333
334
|
let statusValue
|
|
334
335
|
if (
|
|
@@ -342,7 +343,9 @@ const serveRedirect = async function ({ env, functionsRegistry, match, options,
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
if (isFunction(options.functionsPort, req.url) || functionWithCustomRoute) {
|
|
345
|
-
const functionHeaders = functionWithCustomRoute
|
|
346
|
+
const functionHeaders = functionWithCustomRoute
|
|
347
|
+
? { [NFFunctionName]: functionWithCustomRoute.func.name, [NFFunctionRoute]: functionWithCustomRoute.route }
|
|
348
|
+
: {}
|
|
346
349
|
const url = reqToURL(req, originalURL)
|
|
347
350
|
req.headers['x-netlify-original-pathname'] = url.pathname
|
|
348
351
|
req.headers['x-netlify-original-search'] = url.search
|
|
@@ -600,12 +603,12 @@ const onRequest = async (
|
|
|
600
603
|
}
|
|
601
604
|
|
|
602
605
|
// Does the request match a function on a custom URL path?
|
|
603
|
-
const functionMatch = functionsRegistry ? await functionsRegistry.getFunctionForURLPath(req.url) : null
|
|
606
|
+
const functionMatch = functionsRegistry ? await functionsRegistry.getFunctionForURLPath(req.url, req.method) : null
|
|
604
607
|
|
|
605
608
|
if (functionMatch) {
|
|
606
609
|
// Setting an internal header with the function name so that we don't
|
|
607
610
|
// have to match the URL again in the functions server.
|
|
608
|
-
const headers = { [NFFunctionName]: functionMatch.name }
|
|
611
|
+
const headers = { [NFFunctionName]: functionMatch.func.name, [NFFunctionRoute]: functionMatch.route.pattern }
|
|
609
612
|
|
|
610
613
|
return proxy.web(req, res, { headers, target: functionsServer })
|
|
611
614
|
}
|
|
@@ -695,6 +698,7 @@ export const startProxy = async function ({
|
|
|
695
698
|
mainPort: settings.port,
|
|
696
699
|
offline,
|
|
697
700
|
passthroughPort: secondaryServerPort || settings.port,
|
|
701
|
+
settings,
|
|
698
702
|
projectDir,
|
|
699
703
|
siteInfo,
|
|
700
704
|
accountId,
|