netlify-cli 16.1.0 → 16.2.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/npm-shrinkwrap.json +715 -711
- package/package.json +8 -8
- package/src/commands/dev/dev.mjs +2 -1
- package/src/commands/serve/serve.mjs +3 -1
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/registry.mjs +28 -13
- package/src/lib/functions/netlify-function.mjs +22 -0
- package/src/lib/functions/registry.mjs +10 -0
- package/src/lib/functions/runtimes/js/builders/zisi.mjs +2 -1
- package/src/lib/functions/server.mjs +19 -5
- package/src/utils/headers.mjs +1 -0
- package/src/utils/proxy-server.mjs +3 -0
- package/src/utils/proxy.mjs +52 -8
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.2.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.7.
|
|
47
|
+
"@netlify/build": "29.20.8",
|
|
48
|
+
"@netlify/build-info": "7.7.4",
|
|
49
49
|
"@netlify/config": "20.8.0",
|
|
50
|
-
"@netlify/edge-bundler": "8.
|
|
50
|
+
"@netlify/edge-bundler": "8.19.0",
|
|
51
51
|
"@netlify/local-functions-proxy": "1.1.1",
|
|
52
|
-
"@netlify/serverless-functions-api": "1.
|
|
53
|
-
"@netlify/zip-it-and-ship-it": "9.
|
|
52
|
+
"@netlify/serverless-functions-api": "1.7.3",
|
|
53
|
+
"@netlify/zip-it-and-ship-it": "9.17.0",
|
|
54
54
|
"@octokit/rest": "19.0.13",
|
|
55
55
|
"ansi-escapes": "6.2.0",
|
|
56
56
|
"ansi-styles": "6.2.1",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"isexe": "2.0.0",
|
|
107
107
|
"jsonwebtoken": "9.0.1",
|
|
108
108
|
"jwt-decode": "3.1.2",
|
|
109
|
-
"lambda-local": "2.1.
|
|
109
|
+
"lambda-local": "2.1.2",
|
|
110
110
|
"listr": "0.14.3",
|
|
111
111
|
"locate-path": "7.2.0",
|
|
112
112
|
"lodash": "4.17.21",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"multiparty": "4.2.3",
|
|
117
117
|
"netlify": "13.1.10",
|
|
118
118
|
"netlify-headers-parser": "7.1.2",
|
|
119
|
-
"netlify-redirect-parser": "14.
|
|
119
|
+
"netlify-redirect-parser": "14.2.0",
|
|
120
120
|
"netlify-redirector": "0.4.0",
|
|
121
121
|
"node-fetch": "2.6.12",
|
|
122
122
|
"node-version-alias": "3.4.1",
|
package/src/commands/dev/dev.mjs
CHANGED
|
@@ -161,7 +161,7 @@ const dev = async (options, command) => {
|
|
|
161
161
|
},
|
|
162
162
|
})
|
|
163
163
|
|
|
164
|
-
await startFunctionsServer({
|
|
164
|
+
const functionsRegistry = await startFunctionsServer({
|
|
165
165
|
api,
|
|
166
166
|
command,
|
|
167
167
|
config,
|
|
@@ -217,6 +217,7 @@ const dev = async (options, command) => {
|
|
|
217
217
|
geolocationMode: options.geo,
|
|
218
218
|
geoCountry: options.country,
|
|
219
219
|
accountId,
|
|
220
|
+
functionsRegistry,
|
|
220
221
|
})
|
|
221
222
|
|
|
222
223
|
if (devConfig.autoLaunch !== false) {
|
|
@@ -93,7 +93,7 @@ const serve = async (options, command) => {
|
|
|
93
93
|
options,
|
|
94
94
|
})
|
|
95
95
|
|
|
96
|
-
await startFunctionsServer({
|
|
96
|
+
const functionsRegistry = await startFunctionsServer({
|
|
97
97
|
api,
|
|
98
98
|
command,
|
|
99
99
|
config,
|
|
@@ -132,7 +132,9 @@ const serve = async (options, command) => {
|
|
|
132
132
|
addonsUrls,
|
|
133
133
|
config,
|
|
134
134
|
configPath: configPathOverride,
|
|
135
|
+
debug: options.debug,
|
|
135
136
|
env,
|
|
137
|
+
functionsRegistry,
|
|
136
138
|
geolocationMode: options.geo,
|
|
137
139
|
geoCountry: options.country,
|
|
138
140
|
getUpdatedConfig,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { env } from 'process'
|
|
2
2
|
|
|
3
|
-
const latestBootstrapURL = 'https://
|
|
3
|
+
const latestBootstrapURL = 'https://64e7783fce8cfe0008496c72--edge.netlify.com/bootstrap/index-combined.ts'
|
|
4
4
|
|
|
5
5
|
export const getBootstrapURL = () => env.NETLIFY_EDGE_BOOTSTRAP || latestBootstrapURL
|
|
@@ -318,23 +318,38 @@ export class EdgeFunctionsRegistry {
|
|
|
318
318
|
functions: this.#functions,
|
|
319
319
|
featureFlags,
|
|
320
320
|
})
|
|
321
|
-
const invocationMetadata = {
|
|
322
|
-
function_config: manifest.function_config,
|
|
323
|
-
routes: manifest.routes.map((route) => ({ function: route.function, pattern: route.pattern })),
|
|
324
|
-
}
|
|
325
321
|
const routes = [...manifest.routes, ...manifest.post_cache_routes].map((route) => ({
|
|
326
322
|
...route,
|
|
327
323
|
pattern: new RegExp(route.pattern),
|
|
328
324
|
}))
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
.
|
|
325
|
+
|
|
326
|
+
/** @type string[] */
|
|
327
|
+
const functionNames = []
|
|
328
|
+
|
|
329
|
+
/** @type number[] */
|
|
330
|
+
const routeIndexes = []
|
|
331
|
+
|
|
332
|
+
routes.forEach((route, index) => {
|
|
333
|
+
if (!route.pattern.test(urlPath)) {
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const isExcluded = manifest.function_config[route.function]?.excluded_patterns?.some((pattern) =>
|
|
338
|
+
new RegExp(pattern).test(urlPath),
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
if (isExcluded) {
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
functionNames.push(route.function)
|
|
346
|
+
routeIndexes.push(index)
|
|
347
|
+
})
|
|
348
|
+
const invocationMetadata = {
|
|
349
|
+
function_config: manifest.function_config,
|
|
350
|
+
req_routes: routeIndexes,
|
|
351
|
+
routes: manifest.routes.map((route) => ({ function: route.function, path: route.path, pattern: route.pattern })),
|
|
352
|
+
}
|
|
338
353
|
const orphanedDeclarations = this.#matchURLPathAgainstOrphanedDeclarations(urlPath)
|
|
339
354
|
|
|
340
355
|
return { functionNames, invocationMetadata, orphanedDeclarations }
|
|
@@ -158,6 +158,28 @@ export default class NetlifyFunction {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
async matchURLPath(rawPath) {
|
|
162
|
+
await this.buildQueue
|
|
163
|
+
|
|
164
|
+
const path = (rawPath.endsWith('/') ? rawPath.slice(0, -1) : rawPath).toLowerCase()
|
|
165
|
+
const { routes = [] } = this.buildData
|
|
166
|
+
const isMatch = routes.some(({ expression, literal }) => {
|
|
167
|
+
if (literal !== undefined) {
|
|
168
|
+
return path === literal
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (expression !== undefined) {
|
|
172
|
+
const regex = new RegExp(expression)
|
|
173
|
+
|
|
174
|
+
return regex.test(path)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return false
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
return isMatch
|
|
181
|
+
}
|
|
182
|
+
|
|
161
183
|
get url() {
|
|
162
184
|
// This line fixes the issue here https://github.com/netlify/cli/issues/4116
|
|
163
185
|
// Not sure why `settings.port` was used here nor does a valid reference exist.
|
|
@@ -122,6 +122,16 @@ export class FunctionsRegistry {
|
|
|
122
122
|
return this.functions.get(name)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
async getFunctionForURLPath(urlPath) {
|
|
126
|
+
for (const func of this.functions.values()) {
|
|
127
|
+
const isMatch = await func.matchURLPath(urlPath)
|
|
128
|
+
|
|
129
|
+
if (isMatch) {
|
|
130
|
+
return func
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
125
135
|
async registerFunction(name, funcBeforeHook) {
|
|
126
136
|
const { runtime } = funcBeforeHook
|
|
127
137
|
|
|
@@ -58,6 +58,7 @@ const buildFunction = async ({
|
|
|
58
58
|
includedFiles,
|
|
59
59
|
inputs,
|
|
60
60
|
path: functionPath,
|
|
61
|
+
routes,
|
|
61
62
|
runtimeAPIVersion,
|
|
62
63
|
schedule,
|
|
63
64
|
} = await memoizedBuild({
|
|
@@ -81,7 +82,7 @@ const buildFunction = async ({
|
|
|
81
82
|
|
|
82
83
|
clearFunctionsCache(targetDirectory)
|
|
83
84
|
|
|
84
|
-
return { buildPath, includedFiles, runtimeAPIVersion, srcFiles, schedule }
|
|
85
|
+
return { buildPath, includedFiles, routes, runtimeAPIVersion, srcFiles, schedule }
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
/**
|
|
@@ -7,6 +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
11
|
import { headers as efHeaders } from '../edge-functions/headers.mjs'
|
|
11
12
|
import { getGeoLocation } from '../geo-location.mjs'
|
|
12
13
|
|
|
@@ -55,9 +56,20 @@ export const createHandler = function (options) {
|
|
|
55
56
|
const { functionsRegistry } = options
|
|
56
57
|
|
|
57
58
|
return async function handler(request, response) {
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
// If this header is set, it means we've already matched a function and we
|
|
60
|
+
// can just grab its name directly. We delete the header from the request
|
|
61
|
+
// because we don't want to expose it to user code.
|
|
62
|
+
let functionName = request.header(NFFunctionName)
|
|
63
|
+
delete request.headers[NFFunctionName]
|
|
64
|
+
|
|
65
|
+
// If we didn't match a function with a custom route, let's try to match
|
|
66
|
+
// using the fixed URL format.
|
|
67
|
+
if (!functionName) {
|
|
68
|
+
const cleanPath = request.path.replace(/^\/.netlify\/(functions|builders)/, '')
|
|
69
|
+
|
|
70
|
+
functionName = cleanPath.split('/').find(Boolean)
|
|
71
|
+
}
|
|
72
|
+
|
|
61
73
|
const func = functionsRegistry.get(functionName)
|
|
62
74
|
|
|
63
75
|
if (func === undefined) {
|
|
@@ -231,7 +243,7 @@ const getFunctionsServer = (options) => {
|
|
|
231
243
|
* @param {*} options.site
|
|
232
244
|
* @param {string} options.siteUrl
|
|
233
245
|
* @param {*} options.timeouts
|
|
234
|
-
* @returns
|
|
246
|
+
* @returns {Promise<import('./registry.mjs').FunctionsRegistry | undefined>}
|
|
235
247
|
*/
|
|
236
248
|
export const startFunctionsServer = async (options) => {
|
|
237
249
|
const { capabilities, command, config, debug, loadDistFunctions, settings, site, siteUrl, timeouts } = options
|
|
@@ -272,9 +284,11 @@ export const startFunctionsServer = async (options) => {
|
|
|
272
284
|
|
|
273
285
|
await functionsRegistry.scan(functionsDirectories)
|
|
274
286
|
|
|
275
|
-
const server =
|
|
287
|
+
const server = getFunctionsServer(Object.assign(options, { functionsRegistry }))
|
|
276
288
|
|
|
277
289
|
await startWebServer({ server, settings, debug })
|
|
290
|
+
|
|
291
|
+
return functionsRegistry
|
|
278
292
|
}
|
|
279
293
|
|
|
280
294
|
/**
|
package/src/utils/headers.mjs
CHANGED
|
@@ -52,6 +52,7 @@ export const generateInspectSettings = (edgeInspect, edgeInspectBrk) => {
|
|
|
52
52
|
* @param {*} params.siteInfo
|
|
53
53
|
* @param {string} params.projectDir
|
|
54
54
|
* @param {import('./state-config.mjs').default} params.state
|
|
55
|
+
* @param {import('../lib/functions/registry.mjs').FunctionsRegistry=} params.functionsRegistry
|
|
55
56
|
* @returns
|
|
56
57
|
*/
|
|
57
58
|
export const startProxyServer = async ({
|
|
@@ -61,6 +62,7 @@ export const startProxyServer = async ({
|
|
|
61
62
|
configPath,
|
|
62
63
|
debug,
|
|
63
64
|
env,
|
|
65
|
+
functionsRegistry,
|
|
64
66
|
geoCountry,
|
|
65
67
|
geolocationMode,
|
|
66
68
|
getUpdatedConfig,
|
|
@@ -78,6 +80,7 @@ export const startProxyServer = async ({
|
|
|
78
80
|
configPath: configPath || site.configPath,
|
|
79
81
|
debug,
|
|
80
82
|
env,
|
|
83
|
+
functionsRegistry,
|
|
81
84
|
geolocationMode,
|
|
82
85
|
geoCountry,
|
|
83
86
|
getUpdatedConfig,
|
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, NFRequestID } from './headers.mjs'
|
|
34
|
+
import { headersForPath, parseHeaders, NFFunctionName, NFRequestID } 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'
|
|
@@ -181,7 +181,7 @@ const alternativePathsFor = function (url) {
|
|
|
181
181
|
return paths
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
const serveRedirect = async function ({ env, match, options, proxy, req, res, siteInfo }) {
|
|
184
|
+
const serveRedirect = async function ({ env, functionsRegistry, match, options, proxy, req, res, siteInfo }) {
|
|
185
185
|
if (!match) return proxy.web(req, res, options)
|
|
186
186
|
|
|
187
187
|
options = options || req.proxyOptions || {}
|
|
@@ -214,6 +214,7 @@ const serveRedirect = async function ({ env, match, options, proxy, req, res, si
|
|
|
214
214
|
if (isFunction(options.functionsPort, req.url)) {
|
|
215
215
|
return proxy.web(req, res, { target: options.functionsServer })
|
|
216
216
|
}
|
|
217
|
+
|
|
217
218
|
const urlForAddons = getAddonUrl(options.addonsUrls, req)
|
|
218
219
|
if (urlForAddons) {
|
|
219
220
|
return handleAddonUrl({ req, res, addonUrl: urlForAddons })
|
|
@@ -327,22 +328,28 @@ const serveRedirect = async function ({ env, match, options, proxy, req, res, si
|
|
|
327
328
|
return proxy.web(req, res, { target: options.functionsServer })
|
|
328
329
|
}
|
|
329
330
|
|
|
331
|
+
const functionWithCustomRoute = functionsRegistry && (await functionsRegistry.getFunctionForURLPath(destURL))
|
|
330
332
|
const destStaticFile = await getStatic(dest.pathname, options.publicFolder)
|
|
331
333
|
let statusValue
|
|
332
|
-
if (
|
|
334
|
+
if (
|
|
335
|
+
match.force ||
|
|
336
|
+
(!staticFile && ((!options.framework && destStaticFile) || isInternal(destURL) || functionWithCustomRoute))
|
|
337
|
+
) {
|
|
333
338
|
req.url = destStaticFile ? destStaticFile + dest.search : destURL
|
|
334
339
|
const { status } = match
|
|
335
340
|
statusValue = status
|
|
336
341
|
console.log(`${NETLIFYDEVLOG} Rewrote URL to`, req.url)
|
|
337
342
|
}
|
|
338
343
|
|
|
339
|
-
if (isFunction(options.functionsPort, req.url)) {
|
|
344
|
+
if (isFunction(options.functionsPort, req.url) || functionWithCustomRoute) {
|
|
345
|
+
const functionHeaders = functionWithCustomRoute ? { [NFFunctionName]: functionWithCustomRoute.name } : {}
|
|
340
346
|
const url = reqToURL(req, originalURL)
|
|
341
347
|
req.headers['x-netlify-original-pathname'] = url.pathname
|
|
342
348
|
req.headers['x-netlify-original-search'] = url.search
|
|
343
349
|
|
|
344
|
-
return proxy.web(req, res, { target: options.functionsServer })
|
|
350
|
+
return proxy.web(req, res, { headers: functionHeaders, target: options.functionsServer })
|
|
345
351
|
}
|
|
352
|
+
|
|
346
353
|
const addonUrl = getAddonUrl(options.addonsUrls, req)
|
|
347
354
|
if (addonUrl) {
|
|
348
355
|
return handleAddonUrl({ req, res, addonUrl })
|
|
@@ -434,12 +441,22 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
434
441
|
}
|
|
435
442
|
|
|
436
443
|
if (proxyRes.statusCode === 404 || proxyRes.statusCode === 403) {
|
|
444
|
+
// If a request for `/path` has failed, we'll a few variations like
|
|
445
|
+
// `/path/index.html` to mimic the CDN behavior.
|
|
437
446
|
if (req.alternativePaths && req.alternativePaths.length !== 0) {
|
|
438
447
|
req.url = req.alternativePaths.shift()
|
|
439
448
|
return proxy.web(req, res, req.proxyOptions)
|
|
440
449
|
}
|
|
450
|
+
|
|
451
|
+
// The request has failed but we might still have a matching redirect
|
|
452
|
+
// rule (without `force`) that should kick in. This is how we mimic the
|
|
453
|
+
// file shadowing behavior from the CDN.
|
|
441
454
|
if (req.proxyOptions && req.proxyOptions.match) {
|
|
442
455
|
return serveRedirect({
|
|
456
|
+
// We don't want to match functions at this point because any redirects
|
|
457
|
+
// to functions will have already been processed, so we don't supply a
|
|
458
|
+
// functions registry to `serveRedirect`.
|
|
459
|
+
functionsRegistry: null,
|
|
443
460
|
req,
|
|
444
461
|
res,
|
|
445
462
|
proxy: handlers,
|
|
@@ -453,7 +470,19 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
453
470
|
|
|
454
471
|
if (req.proxyOptions.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) {
|
|
455
472
|
req.url = proxyRes.headers.location
|
|
456
|
-
return serveRedirect({
|
|
473
|
+
return serveRedirect({
|
|
474
|
+
// We don't want to match functions at this point because any redirects
|
|
475
|
+
// to functions will have already been processed, so we don't supply a
|
|
476
|
+
// functions registry to `serveRedirect`.
|
|
477
|
+
functionsRegistry: null,
|
|
478
|
+
req,
|
|
479
|
+
res,
|
|
480
|
+
proxy: handlers,
|
|
481
|
+
match: null,
|
|
482
|
+
options: req.proxyOptions,
|
|
483
|
+
siteInfo,
|
|
484
|
+
env,
|
|
485
|
+
})
|
|
457
486
|
}
|
|
458
487
|
|
|
459
488
|
const responseData = []
|
|
@@ -551,7 +580,7 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
551
580
|
}
|
|
552
581
|
|
|
553
582
|
const onRequest = async (
|
|
554
|
-
{ addonsUrls, edgeFunctionsProxy, env, functionsServer, proxy, rewriter, settings, siteInfo },
|
|
583
|
+
{ addonsUrls, edgeFunctionsProxy, env, functionsRegistry, functionsServer, proxy, rewriter, settings, siteInfo },
|
|
555
584
|
req,
|
|
556
585
|
res,
|
|
557
586
|
) => {
|
|
@@ -565,9 +594,22 @@ const onRequest = async (
|
|
|
565
594
|
return proxy.web(req, res, { target: edgeFunctionsProxyURL })
|
|
566
595
|
}
|
|
567
596
|
|
|
597
|
+
// Does the request match a function on the fixed URL path?
|
|
568
598
|
if (isFunction(settings.functionsPort, req.url)) {
|
|
569
599
|
return proxy.web(req, res, { target: functionsServer })
|
|
570
600
|
}
|
|
601
|
+
|
|
602
|
+
// Does the request match a function on a custom URL path?
|
|
603
|
+
const functionMatch = functionsRegistry ? await functionsRegistry.getFunctionForURLPath(req.url) : null
|
|
604
|
+
|
|
605
|
+
if (functionMatch) {
|
|
606
|
+
// Setting an internal header with the function name so that we don't
|
|
607
|
+
// have to match the URL again in the functions server.
|
|
608
|
+
const headers = { [NFFunctionName]: functionMatch.name }
|
|
609
|
+
|
|
610
|
+
return proxy.web(req, res, { headers, target: functionsServer })
|
|
611
|
+
}
|
|
612
|
+
|
|
571
613
|
const addonUrl = getAddonUrl(addonsUrls, req)
|
|
572
614
|
if (addonUrl) {
|
|
573
615
|
return handleAddonUrl({ req, res, addonUrl })
|
|
@@ -591,7 +633,7 @@ const onRequest = async (
|
|
|
591
633
|
// We don't want to generate an ETag for 3xx redirects.
|
|
592
634
|
req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400
|
|
593
635
|
|
|
594
|
-
return serveRedirect({ req, res, proxy, match, options, siteInfo, env })
|
|
636
|
+
return serveRedirect({ req, res, proxy, match, options, siteInfo, env, functionsRegistry })
|
|
595
637
|
}
|
|
596
638
|
|
|
597
639
|
// The request will be served by the framework server, which means we want to
|
|
@@ -628,6 +670,7 @@ export const startProxy = async function ({
|
|
|
628
670
|
configPath,
|
|
629
671
|
debug,
|
|
630
672
|
env,
|
|
673
|
+
functionsRegistry,
|
|
631
674
|
geoCountry,
|
|
632
675
|
geolocationMode,
|
|
633
676
|
getUpdatedConfig,
|
|
@@ -681,6 +724,7 @@ export const startProxy = async function ({
|
|
|
681
724
|
rewriter,
|
|
682
725
|
settings,
|
|
683
726
|
addonsUrls,
|
|
727
|
+
functionsRegistry,
|
|
684
728
|
functionsServer,
|
|
685
729
|
edgeFunctionsProxy,
|
|
686
730
|
siteInfo,
|