netlify-cli 17.3.1 → 17.4.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 (210) hide show
  1. package/README.md +3 -139
  2. package/npm-shrinkwrap.json +82 -82
  3. package/package.json +16 -15
  4. package/src/commands/addons/addons-auth.mjs +27 -30
  5. package/src/commands/addons/addons-config.mjs +145 -154
  6. package/src/commands/addons/addons-create.mjs +94 -108
  7. package/src/commands/addons/addons-delete.mjs +36 -41
  8. package/src/commands/addons/addons-list.mjs +38 -42
  9. package/src/commands/addons/addons.mjs +26 -28
  10. package/src/commands/addons/index.mjs +1 -1
  11. package/src/commands/api/api.mjs +45 -53
  12. package/src/commands/api/index.mjs +1 -1
  13. package/src/commands/base-command.mjs +597 -684
  14. package/src/commands/blobs/blobs-delete.mjs +35 -0
  15. package/src/commands/blobs/blobs-get.mjs +44 -0
  16. package/src/commands/blobs/blobs-list.mjs +48 -0
  17. package/src/commands/blobs/blobs-set.mjs +54 -0
  18. package/src/commands/blobs/blobs.mjs +32 -0
  19. package/src/commands/blobs/index.mjs +1 -0
  20. package/src/commands/build/build.mjs +55 -67
  21. package/src/commands/build/index.mjs +1 -1
  22. package/src/commands/completion/completion.mjs +41 -46
  23. package/src/commands/completion/index.mjs +1 -1
  24. package/src/commands/deploy/deploy.mjs +675 -710
  25. package/src/commands/deploy/index.mjs +1 -1
  26. package/src/commands/dev/dev-exec.mjs +20 -32
  27. package/src/commands/dev/dev.mjs +217 -302
  28. package/src/commands/dev/index.mjs +1 -1
  29. package/src/commands/dev/types.d.ts +30 -0
  30. package/src/commands/env/env-clone.mjs +157 -184
  31. package/src/commands/env/env-get.mjs +49 -68
  32. package/src/commands/env/env-import.mjs +100 -119
  33. package/src/commands/env/env-list.mjs +104 -129
  34. package/src/commands/env/env-set.mjs +160 -185
  35. package/src/commands/env/env-unset.mjs +104 -122
  36. package/src/commands/env/env.mjs +28 -30
  37. package/src/commands/env/index.mjs +1 -1
  38. package/src/commands/functions/functions-build.mjs +29 -41
  39. package/src/commands/functions/functions-create.mjs +533 -601
  40. package/src/commands/functions/functions-invoke.mjs +193 -216
  41. package/src/commands/functions/functions-list.mjs +45 -55
  42. package/src/commands/functions/functions-serve.mjs +51 -61
  43. package/src/commands/functions/functions.mjs +26 -32
  44. package/src/commands/functions/index.mjs +1 -1
  45. package/src/commands/index.mjs +2 -2
  46. package/src/commands/init/index.mjs +1 -1
  47. package/src/commands/init/init.mjs +138 -167
  48. package/src/commands/integration/deploy.mjs +337 -399
  49. package/src/commands/integration/index.mjs +12 -13
  50. package/src/commands/link/index.mjs +1 -1
  51. package/src/commands/link/link.mjs +298 -317
  52. package/src/commands/lm/index.mjs +1 -1
  53. package/src/commands/lm/lm-info.mjs +23 -31
  54. package/src/commands/lm/lm-install.mjs +13 -17
  55. package/src/commands/lm/lm-setup.mjs +80 -84
  56. package/src/commands/lm/lm-uninstall.mjs +7 -12
  57. package/src/commands/lm/lm.mjs +18 -22
  58. package/src/commands/login/index.mjs +1 -1
  59. package/src/commands/login/login.mjs +35 -41
  60. package/src/commands/logout/index.mjs +1 -1
  61. package/src/commands/logout/logout.mjs +25 -31
  62. package/src/commands/main.mjs +166 -201
  63. package/src/commands/open/index.mjs +1 -1
  64. package/src/commands/open/open-admin.mjs +15 -18
  65. package/src/commands/open/open-site.mjs +16 -19
  66. package/src/commands/open/open.mjs +24 -27
  67. package/src/commands/recipes/common.mjs +23 -34
  68. package/src/commands/recipes/index.mjs +1 -1
  69. package/src/commands/recipes/recipes-list.mjs +13 -20
  70. package/src/commands/recipes/recipes.mjs +59 -72
  71. package/src/commands/serve/index.mjs +1 -1
  72. package/src/commands/serve/serve.mjs +142 -189
  73. package/src/commands/sites/index.mjs +2 -2
  74. package/src/commands/sites/sites-create-template.mjs +214 -236
  75. package/src/commands/sites/sites-create.mjs +145 -157
  76. package/src/commands/sites/sites-delete.mjs +75 -81
  77. package/src/commands/sites/sites-list.mjs +63 -66
  78. package/src/commands/sites/sites.mjs +18 -20
  79. package/src/commands/status/index.mjs +1 -1
  80. package/src/commands/status/status-hooks.mjs +32 -34
  81. package/src/commands/status/status.mjs +99 -106
  82. package/src/commands/switch/index.mjs +1 -1
  83. package/src/commands/switch/switch.mjs +32 -37
  84. package/src/commands/types.d.ts +31 -0
  85. package/src/commands/unlink/index.mjs +1 -1
  86. package/src/commands/unlink/unlink.mjs +23 -29
  87. package/src/commands/watch/index.mjs +1 -1
  88. package/src/commands/watch/watch.mjs +91 -105
  89. package/src/functions-templates/javascript/hello/{{name}}.js +2 -3
  90. package/src/lib/account.mjs +4 -5
  91. package/src/lib/api.mjs +22 -20
  92. package/src/lib/blobs/blobs.mjs +36 -45
  93. package/src/lib/build.mjs +82 -85
  94. package/src/lib/completion/constants.mjs +2 -4
  95. package/src/lib/completion/generate-autocompletion.mjs +33 -36
  96. package/src/lib/completion/get-autocompletion.mjs +31 -35
  97. package/src/lib/completion/index.mjs +1 -1
  98. package/src/lib/completion/script.mjs +12 -19
  99. package/src/lib/edge-functions/bootstrap.mjs +3 -5
  100. package/src/lib/edge-functions/consts.mjs +9 -10
  101. package/src/lib/edge-functions/deploy.mjs +28 -34
  102. package/src/lib/edge-functions/editor-helper.mjs +29 -42
  103. package/src/lib/edge-functions/headers.mjs +24 -26
  104. package/src/lib/edge-functions/internal.mjs +38 -44
  105. package/src/lib/edge-functions/proxy.mjs +229 -228
  106. package/src/lib/edge-functions/registry.mjs +473 -574
  107. package/src/lib/exec-fetcher.mjs +115 -122
  108. package/src/lib/fs.mjs +28 -27
  109. package/src/lib/functions/background.mjs +16 -20
  110. package/src/lib/functions/config.mjs +12 -9
  111. package/src/lib/functions/form-submissions-handler.mjs +143 -149
  112. package/src/lib/functions/local-proxy.mjs +40 -44
  113. package/src/lib/functions/memoized-build.mjs +19 -21
  114. package/src/lib/functions/netlify-function.mjs +269 -249
  115. package/src/lib/functions/registry.mjs +509 -568
  116. package/src/lib/functions/runtimes/go/index.mjs +62 -71
  117. package/src/lib/functions/runtimes/index.mjs +8 -15
  118. package/src/lib/functions/runtimes/js/builders/netlify-lambda.mjs +55 -64
  119. package/src/lib/functions/runtimes/js/builders/zisi.mjs +135 -154
  120. package/src/lib/functions/runtimes/js/constants.mjs +1 -1
  121. package/src/lib/functions/runtimes/js/index.mjs +92 -109
  122. package/src/lib/functions/runtimes/js/worker.mjs +43 -45
  123. package/src/lib/functions/runtimes/rust/index.mjs +64 -73
  124. package/src/lib/functions/scheduled.mjs +70 -88
  125. package/src/lib/functions/server.mjs +269 -327
  126. package/src/lib/functions/synchronous.mjs +118 -147
  127. package/src/lib/functions/utils.mjs +38 -46
  128. package/src/lib/geo-location.mjs +69 -81
  129. package/src/lib/http-agent.mjs +87 -90
  130. package/src/lib/images/proxy.mjs +97 -89
  131. package/src/lib/log.mjs +6 -9
  132. package/src/lib/path.mjs +2 -1
  133. package/src/lib/render-error-template.mjs +19 -20
  134. package/src/lib/settings.mjs +17 -19
  135. package/src/lib/spinner.mjs +21 -23
  136. package/src/lib/string.mjs +4 -2
  137. package/src/recipes/vscode/index.mjs +69 -85
  138. package/src/recipes/vscode/settings.mjs +53 -58
  139. package/src/utils/addons/compare.mjs +31 -32
  140. package/src/utils/addons/diffs/index.mjs +16 -17
  141. package/src/utils/addons/diffs/options.mjs +99 -101
  142. package/src/utils/addons/prepare.mjs +100 -97
  143. package/src/utils/addons/prompts.mjs +73 -76
  144. package/src/utils/addons/render.mjs +33 -36
  145. package/src/utils/addons/validation.mjs +19 -15
  146. package/src/utils/banner.mjs +11 -16
  147. package/src/utils/build-info.mjs +65 -66
  148. package/src/utils/command-helpers.mjs +185 -199
  149. package/src/utils/create-deferred.mjs +9 -12
  150. package/src/utils/create-stream-promise.mjs +54 -47
  151. package/src/utils/deploy/constants.mjs +9 -11
  152. package/src/utils/deploy/deploy-site.mjs +162 -182
  153. package/src/utils/deploy/hash-config.mjs +21 -21
  154. package/src/utils/deploy/hash-files.mjs +34 -38
  155. package/src/utils/deploy/hash-fns.mjs +149 -154
  156. package/src/utils/deploy/hasher-segments.mjs +58 -52
  157. package/src/utils/deploy/upload-files.mjs +99 -113
  158. package/src/utils/deploy/util.mjs +85 -91
  159. package/src/utils/detect-server-settings.mjs +236 -268
  160. package/src/utils/dev.mjs +163 -178
  161. package/src/utils/dot-env.mjs +37 -42
  162. package/src/utils/env/index.mjs +148 -148
  163. package/src/utils/execa.mjs +9 -13
  164. package/src/utils/feature-flags.mjs +6 -5
  165. package/src/utils/framework-server.mjs +43 -52
  166. package/src/utils/functions/constants.mjs +1 -1
  167. package/src/utils/functions/functions.mjs +30 -40
  168. package/src/utils/functions/get-functions.mjs +28 -29
  169. package/src/utils/functions/index.mjs +3 -3
  170. package/src/utils/get-global-config.mjs +33 -36
  171. package/src/utils/get-package-json.mjs +14 -15
  172. package/src/utils/get-repo-data.mjs +54 -64
  173. package/src/utils/get-site.mjs +14 -14
  174. package/src/utils/gh-auth.mjs +79 -100
  175. package/src/utils/gitignore.mjs +37 -40
  176. package/src/utils/headers.mjs +33 -35
  177. package/src/utils/hooks/requires-site-info.mjs +26 -22
  178. package/src/utils/init/config-github.mjs +207 -219
  179. package/src/utils/init/config-manual.mjs +83 -100
  180. package/src/utils/init/config.mjs +25 -26
  181. package/src/utils/init/node-version.mjs +23 -30
  182. package/src/utils/init/plugins.mjs +12 -8
  183. package/src/utils/init/utils.mjs +152 -172
  184. package/src/utils/live-tunnel.mjs +118 -141
  185. package/src/utils/lm/install.mjs +220 -259
  186. package/src/utils/lm/requirements.mjs +54 -63
  187. package/src/utils/lm/steps.mjs +31 -31
  188. package/src/utils/lm/ui.mjs +13 -20
  189. package/src/utils/open-browser.mjs +31 -32
  190. package/src/utils/parse-raw-flags.mjs +39 -35
  191. package/src/utils/proxy-server.mjs +84 -71
  192. package/src/utils/proxy.mjs +696 -750
  193. package/src/utils/read-repo-url.mjs +48 -47
  194. package/src/utils/redirects.mjs +49 -49
  195. package/src/utils/request-id.mjs +2 -4
  196. package/src/utils/rules-proxy.mjs +96 -100
  197. package/src/utils/run-build.mjs +109 -132
  198. package/src/utils/shell.mjs +99 -106
  199. package/src/utils/sign-redirect.mjs +14 -14
  200. package/src/utils/sites/utils.mjs +48 -55
  201. package/src/utils/state-config.mjs +101 -101
  202. package/src/utils/static-server.mjs +28 -34
  203. package/src/utils/telemetry/index.mjs +2 -2
  204. package/src/utils/telemetry/report-error.mjs +45 -49
  205. package/src/utils/telemetry/request.mjs +36 -43
  206. package/src/utils/telemetry/telemetry.mjs +90 -105
  207. package/src/utils/telemetry/utils.mjs +5 -6
  208. package/src/utils/telemetry/validation.mjs +55 -53
  209. package/src/utils/types.d.ts +46 -0
  210. package/src/utils/validation.mjs +10 -13
@@ -1,812 +1,758 @@
1
- // @ts-check
2
- import { Buffer } from 'buffer'
3
- import { once } from 'events'
4
- import { readFile } from 'fs/promises'
5
- import http from 'http'
6
- import https from 'https'
7
- import { isIPv6 } from 'net'
8
- import path from 'path'
9
- import util from 'util'
10
- import zlib from 'zlib'
11
-
12
- import contentType from 'content-type'
13
- import cookie from 'cookie'
14
- import { getProperty } from 'dot-prop'
15
- import generateETag from 'etag'
16
- import getAvailablePort from 'get-port'
17
- import httpProxy from 'http-proxy'
18
- import { createProxyMiddleware } from 'http-proxy-middleware'
19
- import jwtDecode from 'jwt-decode'
20
- import { locatePath } from 'locate-path'
21
- import pFilter from 'p-filter'
22
- import toReadableStream from 'to-readable-stream'
23
-
24
- import {
25
- handleProxyRequest,
26
- initializeProxy as initializeEdgeFunctionsProxy,
27
- isEdgeFunctionsRequest,
28
- } from '../lib/edge-functions/proxy.mjs'
29
- import { fileExistsAsync, isFileAsync } from '../lib/fs.mjs'
30
- import { DEFAULT_FUNCTION_URL_EXPRESSION } from '../lib/functions/registry.mjs'
31
- import { initializeProxy as initializeImageProxy, isImageRequest } from '../lib/images/proxy.mjs'
32
- import renderErrorTemplate from '../lib/render-error-template.mjs'
33
-
34
- import { NETLIFYDEVLOG, NETLIFYDEVWARN, log, chalk } from './command-helpers.mjs'
35
- import createStreamPromise from './create-stream-promise.mjs'
36
- import { headersForPath, parseHeaders, NFFunctionName, NFRequestID, NFFunctionRoute } from './headers.mjs'
37
- import { generateRequestID } from './request-id.mjs'
38
- import { createRewriter, onChanges } from './rules-proxy.mjs'
39
- import { signRedirect } from './sign-redirect.mjs'
40
-
41
- const gunzip = util.promisify(zlib.gunzip)
42
- const brotliDecompress = util.promisify(zlib.brotliDecompress)
43
- const deflate = util.promisify(zlib.deflate)
44
- const shouldGenerateETag = Symbol('Internal: response should generate ETag')
45
-
1
+ import { Buffer } from 'buffer';
2
+ import { once } from 'events';
3
+ import { readFile } from 'fs/promises';
4
+ import http from 'http';
5
+ import https from 'https';
6
+ import { isIPv6 } from 'net';
7
+ import path from 'path';
8
+ import util from 'util';
9
+ import zlib from 'zlib';
10
+ // @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'cont... Remove this comment to see the full error message
11
+ import contentType from 'content-type';
12
+ // @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'cook... Remove this comment to see the full error message
13
+ import cookie from 'cookie';
14
+ import { getProperty } from 'dot-prop';
15
+ // @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'etag... Remove this comment to see the full error message
16
+ import generateETag from 'etag';
17
+ import getAvailablePort from 'get-port';
18
+ import httpProxy from 'http-proxy';
19
+ import { createProxyMiddleware } from 'http-proxy-middleware';
20
+ import jwtDecode from 'jwt-decode';
21
+ import { locatePath } from 'locate-path';
22
+ import pFilter from 'p-filter';
23
+ import toReadableStream from 'to-readable-stream';
24
+ import { handleProxyRequest, initializeProxy as initializeEdgeFunctionsProxy, isEdgeFunctionsRequest, } from '../lib/edge-functions/proxy.mjs';
25
+ import { fileExistsAsync, isFileAsync } from '../lib/fs.mjs';
26
+ import { DEFAULT_FUNCTION_URL_EXPRESSION } from '../lib/functions/registry.mjs';
27
+ import { initializeProxy as initializeImageProxy, isImageRequest } from '../lib/images/proxy.mjs';
28
+ import renderErrorTemplate from '../lib/render-error-template.mjs';
29
+ import { NETLIFYDEVLOG, NETLIFYDEVWARN, log, chalk } from './command-helpers.mjs';
30
+ import createStreamPromise from './create-stream-promise.mjs';
31
+ import { headersForPath, parseHeaders, NFFunctionName, NFRequestID, NFFunctionRoute } from './headers.mjs';
32
+ import { generateRequestID } from './request-id.mjs';
33
+ import { createRewriter, onChanges } from './rules-proxy.mjs';
34
+ import { signRedirect } from './sign-redirect.mjs';
35
+ const gunzip = util.promisify(zlib.gunzip);
36
+ const brotliDecompress = util.promisify(zlib.brotliDecompress);
37
+ const deflate = util.promisify(zlib.deflate);
38
+ const shouldGenerateETag = Symbol('Internal: response should generate ETag');
46
39
  /**
47
40
  * @param {Buffer} body
48
41
  * @param {string | undefined} contentEncoding
49
42
  * @returns {Promise<Buffer>}
50
43
  */
44
+ // @ts-expect-error TS(7006) FIXME: Parameter 'body' implicitly has an 'any' type.
51
45
  const decompressResponseBody = async function (body, contentEncoding = '') {
52
- switch (contentEncoding) {
53
- case 'gzip':
54
- return await gunzip(body)
55
- case 'br':
56
- return await brotliDecompress(body)
57
- case 'deflate':
58
- return await deflate(body)
59
- default:
60
- return body
61
- }
62
- }
63
-
46
+ switch (contentEncoding) {
47
+ case 'gzip':
48
+ return await gunzip(body);
49
+ case 'br':
50
+ return await brotliDecompress(body);
51
+ case 'deflate':
52
+ return await deflate(body);
53
+ default:
54
+ return body;
55
+ }
56
+ };
57
+ // @ts-expect-error TS(7006) FIXME: Parameter 'errorBuffer' implicitly has an 'any' ty... Remove this comment to see the full error message
64
58
  const formatEdgeFunctionError = (errorBuffer, acceptsHtml) => {
65
- const {
66
- error: { message, name, stack },
67
- } = JSON.parse(errorBuffer.toString())
68
-
69
- if (!acceptsHtml) {
70
- return `${name}: ${message}\n ${stack}`
71
- }
72
-
73
- return JSON.stringify({
74
- errorType: name,
75
- errorMessage: message,
76
- trace: stack.split('\\n'),
77
- })
78
- }
79
-
59
+ const { error: { message, name, stack }, } = JSON.parse(errorBuffer.toString());
60
+ if (!acceptsHtml) {
61
+ return `${name}: ${message}\n ${stack}`;
62
+ }
63
+ return JSON.stringify({
64
+ errorType: name,
65
+ errorMessage: message,
66
+ trace: stack.split('\\n'),
67
+ });
68
+ };
80
69
  /**
81
70
  * @param {string} url
82
71
  */
72
+ // @ts-expect-error TS(7006) FIXME: Parameter 'url' implicitly has an 'any' type.
83
73
  function isInternal(url) {
84
- return url.startsWith('/.netlify/')
74
+ return url.startsWith('/.netlify/');
85
75
  }
86
-
87
76
  /**
88
77
  * @param {boolean|number|undefined} functionsPort
89
78
  * @param {string} url
90
79
  */
80
+ // @ts-expect-error TS(7006) FIXME: Parameter 'functionsPort' implicitly has an 'any' ... Remove this comment to see the full error message
91
81
  function isFunction(functionsPort, url) {
92
- return functionsPort && url.match(DEFAULT_FUNCTION_URL_EXPRESSION)
82
+ return functionsPort && url.match(DEFAULT_FUNCTION_URL_EXPRESSION);
93
83
  }
94
-
95
84
  /**
96
85
  * @param {Record<string, string>} addonsUrls
97
86
  * @param {http.IncomingMessage} req
98
87
  */
88
+ // @ts-expect-error TS(7006) FIXME: Parameter 'addonsUrls' implicitly has an 'any' typ... Remove this comment to see the full error message
99
89
  function getAddonUrl(addonsUrls, req) {
100
- const matches = req.url?.match(/^\/.netlify\/([^/]+)(\/.*)/)
101
- const addonUrl = matches && addonsUrls[matches[1]]
102
- return addonUrl ? `${addonUrl}${matches[2]}` : null
90
+ const matches = req.url?.match(/^\/.netlify\/([^/]+)(\/.*)/);
91
+ const addonUrl = matches && addonsUrls[matches[1]];
92
+ return addonUrl ? `${addonUrl}${matches[2]}` : null;
103
93
  }
104
-
105
94
  /**
106
95
  * @param {string} pathname
107
96
  * @param {string} publicFolder
108
97
  */
98
+ // @ts-expect-error TS(7006) FIXME: Parameter 'pathname' implicitly has an 'any' type.
109
99
  const getStatic = async function (pathname, publicFolder) {
110
- const alternatives = [pathname, ...alternativePathsFor(pathname)].map((filePath) =>
111
- path.resolve(publicFolder, filePath.slice(1)),
112
- )
113
-
114
- const file = await locatePath(alternatives)
115
- if (file === undefined) {
116
- return false
117
- }
118
-
119
- return `/${path.relative(publicFolder, file)}`
120
- }
121
-
100
+ const alternatives = [pathname, ...alternativePathsFor(pathname)].map((filePath) => path.resolve(publicFolder, filePath.slice(1)));
101
+ const file = await locatePath(alternatives);
102
+ if (file === undefined) {
103
+ return false;
104
+ }
105
+ return `/${path.relative(publicFolder, file)}`;
106
+ };
107
+ // @ts-expect-error TS(7006) FIXME: Parameter 'match' implicitly has an 'any' type.
122
108
  const isExternal = function (match) {
123
- return match.to && match.to.match(/^https?:\/\//)
124
- }
125
-
109
+ return match.to && match.to.match(/^https?:\/\//);
110
+ };
111
+ // @ts-expect-error TS(7031) FIXME: Binding element 'hash' implicitly has an 'any' typ... Remove this comment to see the full error message
126
112
  const stripOrigin = function ({ hash, pathname, search }) {
127
- return `${pathname}${search}${hash}`
128
- }
129
-
113
+ return `${pathname}${search}${hash}`;
114
+ };
115
+ // @ts-expect-error TS(7031) FIXME: Binding element 'dest' implicitly has an 'any' typ... Remove this comment to see the full error message
130
116
  const proxyToExternalUrl = function ({ dest, destURL, req, res }) {
131
- console.log(`${NETLIFYDEVLOG} Proxying to ${dest}`)
132
- const handler = createProxyMiddleware({
133
- target: dest.origin,
134
- changeOrigin: true,
135
- pathRewrite: () => destURL,
136
- ...(Buffer.isBuffer(req.originalBody) && { buffer: toReadableStream(req.originalBody) }),
137
- })
138
- return handler(req, res, () => {})
139
- }
140
-
117
+ console.log(`${NETLIFYDEVLOG} Proxying to ${dest}`);
118
+ const handler = createProxyMiddleware({
119
+ target: dest.origin,
120
+ changeOrigin: true,
121
+ pathRewrite: () => destURL,
122
+ ...(Buffer.isBuffer(req.originalBody) && { buffer: toReadableStream(req.originalBody) }),
123
+ });
124
+ return handler(req, res, () => { });
125
+ };
126
+ // @ts-expect-error TS(7031) FIXME: Binding element 'addonUrl' implicitly has an 'any'... Remove this comment to see the full error message
141
127
  const handleAddonUrl = function ({ addonUrl, req, res }) {
142
- const dest = new URL(addonUrl)
143
- const destURL = stripOrigin(dest)
144
-
145
- return proxyToExternalUrl({ req, res, dest, destURL })
146
- }
147
-
128
+ const dest = new URL(addonUrl);
129
+ const destURL = stripOrigin(dest);
130
+ return proxyToExternalUrl({ req, res, dest, destURL });
131
+ };
132
+ // @ts-expect-error TS(7006) FIXME: Parameter 'match' implicitly has an 'any' type.
148
133
  const isRedirect = function (match) {
149
- return match.status && match.status >= 300 && match.status <= 400
150
- }
151
-
134
+ return match.status && match.status >= 300 && match.status <= 400;
135
+ };
136
+ // @ts-expect-error TS(7006) FIXME: Parameter 'publicFolder' implicitly has an 'any' t... Remove this comment to see the full error message
152
137
  const render404 = async function (publicFolder) {
153
- const maybe404Page = path.resolve(publicFolder, '404.html')
154
- try {
155
- const isFile = await isFileAsync(maybe404Page)
156
- if (isFile) return await readFile(maybe404Page, 'utf-8')
157
- } catch (error) {
158
- console.warn(NETLIFYDEVWARN, 'Error while serving 404.html file', error.message)
159
- }
160
-
161
- return 'Not Found'
162
- }
163
-
138
+ const maybe404Page = path.resolve(publicFolder, '404.html');
139
+ try {
140
+ const isFile = await isFileAsync(maybe404Page);
141
+ if (isFile)
142
+ return await readFile(maybe404Page, 'utf-8');
143
+ }
144
+ catch (error) {
145
+ // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
146
+ console.warn(NETLIFYDEVWARN, 'Error while serving 404.html file', error.message);
147
+ }
148
+ return 'Not Found';
149
+ };
164
150
  // Used as an optimization to avoid dual lookups for missing assets
165
- const assetExtensionRegExp = /\.(html?|png|jpg|js|css|svg|gif|ico|woff|woff2)$/
166
-
151
+ const assetExtensionRegExp = /\.(html?|png|jpg|js|css|svg|gif|ico|woff|woff2)$/;
152
+ // @ts-expect-error TS(7006) FIXME: Parameter 'url' implicitly has an 'any' type.
167
153
  const alternativePathsFor = function (url) {
168
- if (isFunction(true, url)) {
169
- return []
170
- }
171
-
172
- const paths = []
173
- if (url[url.length - 1] === '/') {
174
- const end = url.length - 1
175
- if (url !== '/') {
176
- paths.push(`${url.slice(0, end)}.html`, `${url.slice(0, end)}.htm`)
177
- }
178
- paths.push(`${url}index.html`, `${url}index.htm`)
179
- } else if (!assetExtensionRegExp.test(url)) {
180
- paths.push(`${url}.html`, `${url}.htm`, `${url}/index.html`, `${url}/index.htm`)
181
- }
182
-
183
- return paths
184
- }
185
-
186
- const serveRedirect = async function ({
187
- env,
188
- functionsRegistry,
189
- imageProxy,
190
- match,
191
- options,
192
- proxy,
193
- req,
194
- res,
195
- siteInfo,
196
- }) {
197
- if (!match) return proxy.web(req, res, options)
198
-
199
- options = options || req.proxyOptions || {}
200
- options.match = null
201
-
202
- if (match.proxyHeaders && Object.keys(match.proxyHeaders).length >= 0) {
203
- Object.entries(match.proxyHeaders).forEach(([key, value]) => {
204
- req.headers[key] = value
205
- })
206
- }
207
-
208
- if (match.signingSecret) {
209
- const signingSecretVar = env[match.signingSecret]
210
-
211
- if (signingSecretVar) {
212
- req.headers['x-nf-sign'] = signRedirect({
213
- deployContext: 'dev',
214
- secret: signingSecretVar.value,
215
- siteID: siteInfo.id,
216
- siteURL: siteInfo.url,
217
- })
218
- } else {
219
- log(
220
- NETLIFYDEVWARN,
221
- `Could not sign redirect because environment variable ${chalk.yellow(match.signingSecret)} is not set`,
222
- )
154
+ if (isFunction(true, url)) {
155
+ return [];
223
156
  }
224
- }
225
-
226
- if (isFunction(options.functionsPort, req.url)) {
227
- return proxy.web(req, res, { target: options.functionsServer })
228
- }
229
-
230
- const urlForAddons = getAddonUrl(options.addonsUrls, req)
231
- if (urlForAddons) {
232
- return handleAddonUrl({ req, res, addonUrl: urlForAddons })
233
- }
234
-
235
- const originalURL = req.url
236
- if (match.exceptions && match.exceptions.JWT) {
237
- // Some values of JWT can start with :, so, make sure to normalize them
238
- const expectedRoles = new Set(
239
- match.exceptions.JWT.split(',').map((value) => (value.startsWith(':') ? value.slice(1) : value)),
240
- )
241
-
242
- const cookieValues = cookie.parse(req.headers.cookie || '')
243
- const token = cookieValues.nf_jwt
244
-
245
- // Serve not found by default
246
- req.url = '/.netlify/non-existent-path'
247
-
248
- if (token) {
249
- let jwtValue = {}
250
- try {
251
- jwtValue = jwtDecode(token) || {}
252
- } catch (error) {
253
- console.warn(NETLIFYDEVWARN, 'Error while decoding JWT provided in request', error.message)
254
- res.writeHead(400)
255
- res.end('Invalid JWT provided. Please see logs for more info.')
256
- return
257
- }
258
-
259
- if ((jwtValue.exp || 0) < Math.round(Date.now() / MILLISEC_TO_SEC)) {
260
- console.warn(NETLIFYDEVWARN, 'Expired JWT provided in request', req.url)
261
- } else {
262
- const presentedRoles = getProperty(jwtValue, options.jwtRolePath) || []
263
- if (!Array.isArray(presentedRoles)) {
264
- console.warn(NETLIFYDEVWARN, `Invalid roles value provided in JWT ${options.jwtRolePath}`, presentedRoles)
265
- res.writeHead(400)
266
- res.end('Invalid JWT provided. Please see logs for more info.')
267
- return
268
- }
269
-
270
- // Restore the URL if everything is correct
271
- if (presentedRoles.some((pr) => expectedRoles.has(pr))) {
272
- req.url = originalURL
157
+ const paths = [];
158
+ if (url[url.length - 1] === '/') {
159
+ const end = url.length - 1;
160
+ if (url !== '/') {
161
+ paths.push(`${url.slice(0, end)}.html`, `${url.slice(0, end)}.htm`);
273
162
  }
274
- }
163
+ paths.push(`${url}index.html`, `${url}index.htm`);
275
164
  }
276
- }
277
-
278
- const reqUrl = reqToURL(req, req.url)
279
-
280
- const staticFile = await getStatic(decodeURIComponent(reqUrl.pathname), options.publicFolder)
281
- if (staticFile) {
282
- req.url = encodeURI(staticFile) + reqUrl.search
283
- // if there is an existing static file and it is not a forced redirect, return the file
284
- if (!match.force) {
285
- return proxy.web(req, res, { ...options, staticFile })
165
+ else if (!assetExtensionRegExp.test(url)) {
166
+ paths.push(`${url}.html`, `${url}.htm`, `${url}/index.html`, `${url}/index.htm`);
286
167
  }
287
- }
288
- if (match.force404) {
289
- res.writeHead(404)
290
- res.end(await render404(options.publicFolder))
291
- return
292
- }
293
-
294
- if (match.force || !staticFile || !options.framework || req.method === 'POST') {
295
- // construct destination URL from redirect rule match
296
- const dest = new URL(match.to, `${reqUrl.protocol}//${reqUrl.host}`)
297
-
298
- // We pass through request params if the redirect rule
299
- // doesn't have any query params
300
- if ([...dest.searchParams].length === 0) {
301
- dest.searchParams.forEach((_, key) => {
302
- dest.searchParams.delete(key)
303
- })
304
-
305
- const requestParams = new URLSearchParams(reqUrl.searchParams)
306
- requestParams.forEach((val, key) => {
307
- dest.searchParams.append(key, val)
308
- })
168
+ return paths;
169
+ };
170
+ const serveRedirect = async function ({
171
+ // @ts-expect-error TS(7031) FIXME: Binding element 'env' implicitly has an 'any' type... Remove this comment to see the full error message
172
+ env,
173
+ // @ts-expect-error TS(7031) FIXME: Binding element 'functionsRegistry' implicitly has... Remove this comment to see the full error message
174
+ functionsRegistry,
175
+ // @ts-expect-error TS(7031) FIXME: Binding element 'imageProxy' implicitly has an 'an... Remove this comment to see the full error message
176
+ imageProxy,
177
+ // @ts-expect-error TS(7031) FIXME: Binding element 'match' implicitly has an 'any' ty... Remove this comment to see the full error message
178
+ match,
179
+ // @ts-expect-error TS(7031) FIXME: Binding element 'options' implicitly has an 'any' ... Remove this comment to see the full error message
180
+ options,
181
+ // @ts-expect-error TS(7031) FIXME: Binding element 'proxy' implicitly has an 'any' ty... Remove this comment to see the full error message
182
+ proxy,
183
+ // @ts-expect-error TS(7031) FIXME: Binding element 'req' implicitly has an 'any' type... Remove this comment to see the full error message
184
+ req,
185
+ // @ts-expect-error TS(7031) FIXME: Binding element 'res' implicitly has an 'any' type... Remove this comment to see the full error message
186
+ res,
187
+ // @ts-expect-error TS(7031) FIXME: Binding element 'siteInfo' implicitly has an 'any'... Remove this comment to see the full error message
188
+ siteInfo, }) {
189
+ if (!match)
190
+ return proxy.web(req, res, options);
191
+ options = options || req.proxyOptions || {};
192
+ options.match = null;
193
+ if (match.proxyHeaders && Object.keys(match.proxyHeaders).length >= 0) {
194
+ Object.entries(match.proxyHeaders).forEach(([key, value]) => {
195
+ req.headers[key] = value;
196
+ });
309
197
  }
310
-
311
- let destURL = stripOrigin(dest)
312
-
313
- if (isExternal(match)) {
314
- if (isRedirect(match)) {
315
- // This is a redirect, so we set the complete external URL as destination
316
- destURL = `${dest}`
317
- } else {
318
- return proxyToExternalUrl({ req, res, dest, destURL })
319
- }
198
+ if (match.signingSecret) {
199
+ const signingSecretVar = env[match.signingSecret];
200
+ if (signingSecretVar) {
201
+ req.headers['x-nf-sign'] = signRedirect({
202
+ deployContext: 'dev',
203
+ secret: signingSecretVar.value,
204
+ siteID: siteInfo.id,
205
+ siteURL: siteInfo.url,
206
+ });
207
+ }
208
+ else {
209
+ log(NETLIFYDEVWARN, `Could not sign redirect because environment variable ${chalk.yellow(match.signingSecret)} is not set`);
210
+ }
320
211
  }
321
-
322
- if (isRedirect(match)) {
323
- console.log(`${NETLIFYDEVLOG} Redirecting ${req.url} to ${destURL}`)
324
- res.writeHead(match.status, {
325
- Location: destURL,
326
- 'Cache-Control': 'no-cache',
327
- })
328
- res.end(`Redirecting to ${destURL}`)
329
-
330
- return
212
+ if (isFunction(options.functionsPort, req.url)) {
213
+ return proxy.web(req, res, { target: options.functionsServer });
331
214
  }
332
-
333
- const ct = req.headers['content-type'] ? contentType.parse(req).type : ''
334
- if (
335
- req.method === 'POST' &&
336
- !isInternal(req.url) &&
337
- !isInternal(destURL) &&
338
- (ct.endsWith('/x-www-form-urlencoded') || ct === 'multipart/form-data')
339
- ) {
340
- return proxy.web(req, res, { target: options.functionsServer })
215
+ const urlForAddons = getAddonUrl(options.addonsUrls, req);
216
+ if (urlForAddons) {
217
+ return handleAddonUrl({ req, res, addonUrl: urlForAddons });
341
218
  }
342
-
343
- const matchingFunction = functionsRegistry && (await functionsRegistry.getFunctionForURLPath(destURL, req.method))
344
- const destStaticFile = await getStatic(dest.pathname, options.publicFolder)
345
- let statusValue
346
- if (
347
- match.force ||
348
- (!staticFile && ((!options.framework && destStaticFile) || isInternal(destURL) || matchingFunction))
349
- ) {
350
- req.url = destStaticFile ? destStaticFile + dest.search : destURL
351
- const { status } = match
352
- statusValue = status
353
- console.log(`${NETLIFYDEVLOG} Rewrote URL to`, req.url)
219
+ const originalURL = req.url;
220
+ if (match.exceptions && match.exceptions.JWT) {
221
+ // Some values of JWT can start with :, so, make sure to normalize them
222
+ const expectedRoles = new Set(
223
+ // @ts-expect-error TS(7006) FIXME: Parameter 'value' implicitly has an 'any' type.
224
+ match.exceptions.JWT.split(',').map((value) => (value.startsWith(':') ? value.slice(1) : value)));
225
+ const cookieValues = cookie.parse(req.headers.cookie || '');
226
+ const token = cookieValues.nf_jwt;
227
+ // Serve not found by default
228
+ req.url = '/.netlify/non-existent-path';
229
+ if (token) {
230
+ let jwtValue = {};
231
+ try {
232
+ // @ts-expect-error TS(2349) This expression is not callable
233
+ jwtValue = jwtDecode(token) || {};
234
+ }
235
+ catch (error) {
236
+ // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
237
+ console.warn(NETLIFYDEVWARN, 'Error while decoding JWT provided in request', error.message);
238
+ res.writeHead(400);
239
+ res.end('Invalid JWT provided. Please see logs for more info.');
240
+ return;
241
+ }
242
+ // @ts-expect-error TS(2339) FIXME: Property 'exp' does not exist on type '{}'.
243
+ if ((jwtValue.exp || 0) < Math.round(Date.now() / MILLISEC_TO_SEC)) {
244
+ console.warn(NETLIFYDEVWARN, 'Expired JWT provided in request', req.url);
245
+ }
246
+ else {
247
+ const presentedRoles = getProperty(jwtValue, options.jwtRolePath) || [];
248
+ if (!Array.isArray(presentedRoles)) {
249
+ console.warn(NETLIFYDEVWARN, `Invalid roles value provided in JWT ${options.jwtRolePath}`, presentedRoles);
250
+ res.writeHead(400);
251
+ res.end('Invalid JWT provided. Please see logs for more info.');
252
+ return;
253
+ }
254
+ // Restore the URL if everything is correct
255
+ if (presentedRoles.some((pr) => expectedRoles.has(pr))) {
256
+ req.url = originalURL;
257
+ }
258
+ }
259
+ }
354
260
  }
355
-
356
- if (matchingFunction) {
357
- const functionHeaders = matchingFunction.func
358
- ? {
359
- [NFFunctionName]: matchingFunction.func?.name,
360
- [NFFunctionRoute]: matchingFunction.route,
361
- }
362
- : {}
363
- const url = reqToURL(req, originalURL)
364
- req.headers['x-netlify-original-pathname'] = url.pathname
365
- req.headers['x-netlify-original-search'] = url.search
366
-
367
- return proxy.web(req, res, { headers: functionHeaders, target: options.functionsServer })
261
+ const reqUrl = reqToURL(req, req.url);
262
+ const staticFile = await getStatic(decodeURIComponent(reqUrl.pathname), options.publicFolder);
263
+ if (staticFile) {
264
+ req.url = encodeURI(staticFile) + reqUrl.search;
265
+ // if there is an existing static file and it is not a forced redirect, return the file
266
+ if (!match.force) {
267
+ return proxy.web(req, res, { ...options, staticFile });
268
+ }
368
269
  }
369
- if (isImageRequest(req)) {
370
- return imageProxy(req, res)
270
+ if (match.force404) {
271
+ res.writeHead(404);
272
+ res.end(await render404(options.publicFolder));
273
+ return;
371
274
  }
372
- const addonUrl = getAddonUrl(options.addonsUrls, req)
373
- if (addonUrl) {
374
- return handleAddonUrl({ req, res, addonUrl })
275
+ if (match.force || !staticFile || !options.framework || req.method === 'POST') {
276
+ // construct destination URL from redirect rule match
277
+ const dest = new URL(match.to, `${reqUrl.protocol}//${reqUrl.host}`);
278
+ // We pass through request params if the redirect rule
279
+ // doesn't have any query params
280
+ if ([...dest.searchParams].length === 0) {
281
+ dest.searchParams.forEach((_, key) => {
282
+ dest.searchParams.delete(key);
283
+ });
284
+ const requestParams = new URLSearchParams(reqUrl.searchParams);
285
+ requestParams.forEach((val, key) => {
286
+ dest.searchParams.append(key, val);
287
+ });
288
+ }
289
+ let destURL = stripOrigin(dest);
290
+ if (isExternal(match)) {
291
+ if (isRedirect(match)) {
292
+ // This is a redirect, so we set the complete external URL as destination
293
+ destURL = `${dest}`;
294
+ }
295
+ else {
296
+ return proxyToExternalUrl({ req, res, dest, destURL });
297
+ }
298
+ }
299
+ if (isRedirect(match)) {
300
+ console.log(`${NETLIFYDEVLOG} Redirecting ${req.url} to ${destURL}`);
301
+ res.writeHead(match.status, {
302
+ Location: destURL,
303
+ 'Cache-Control': 'no-cache',
304
+ });
305
+ res.end(`Redirecting to ${destURL}`);
306
+ return;
307
+ }
308
+ const ct = req.headers['content-type'] ? contentType.parse(req).type : '';
309
+ if (req.method === 'POST' &&
310
+ !isInternal(req.url) &&
311
+ !isInternal(destURL) &&
312
+ (ct.endsWith('/x-www-form-urlencoded') || ct === 'multipart/form-data')) {
313
+ return proxy.web(req, res, { target: options.functionsServer });
314
+ }
315
+ const matchingFunction = functionsRegistry && (await functionsRegistry.getFunctionForURLPath(destURL, req.method));
316
+ const destStaticFile = await getStatic(dest.pathname, options.publicFolder);
317
+ let statusValue;
318
+ if (match.force ||
319
+ (!staticFile && ((!options.framework && destStaticFile) || isInternal(destURL) || matchingFunction))) {
320
+ req.url = destStaticFile ? destStaticFile + dest.search : destURL;
321
+ const { status } = match;
322
+ statusValue = status;
323
+ console.log(`${NETLIFYDEVLOG} Rewrote URL to`, req.url);
324
+ }
325
+ if (matchingFunction) {
326
+ const functionHeaders = matchingFunction.func
327
+ ? {
328
+ [NFFunctionName]: matchingFunction.func?.name,
329
+ [NFFunctionRoute]: matchingFunction.route,
330
+ }
331
+ : {};
332
+ const url = reqToURL(req, originalURL);
333
+ req.headers['x-netlify-original-pathname'] = url.pathname;
334
+ req.headers['x-netlify-original-search'] = url.search;
335
+ return proxy.web(req, res, { headers: functionHeaders, target: options.functionsServer });
336
+ }
337
+ if (isImageRequest(req)) {
338
+ return imageProxy(req, res);
339
+ }
340
+ const addonUrl = getAddonUrl(options.addonsUrls, req);
341
+ if (addonUrl) {
342
+ return handleAddonUrl({ req, res, addonUrl });
343
+ }
344
+ return proxy.web(req, res, { ...options, status: statusValue });
375
345
  }
376
-
377
- return proxy.web(req, res, { ...options, status: statusValue })
378
- }
379
-
380
- return proxy.web(req, res, options)
381
- }
382
-
346
+ return proxy.web(req, res, options);
347
+ };
348
+ // @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type.
383
349
  const reqToURL = function (req, pathname) {
384
- return new URL(
385
- pathname,
386
- `${req.protocol || (req.headers.scheme && `${req.headers.scheme}:`) || 'http:'}//${
387
- req.headers.host || req.hostname
388
- }`,
389
- )
390
- }
391
-
392
- const MILLISEC_TO_SEC = 1e3
393
-
350
+ return new URL(pathname, `${req.protocol || (req.headers.scheme && `${req.headers.scheme}:`) || 'http:'}//${req.headers.host || req.hostname}`);
351
+ };
352
+ const MILLISEC_TO_SEC = 1e3;
353
+ // @ts-expect-error TS(7031) FIXME: Binding element 'configPath' implicitly has an 'an... Remove this comment to see the full error message
394
354
  const initializeProxy = async function ({ configPath, distDir, env, host, imageProxy, port, projectDir, siteInfo }) {
395
- const proxy = httpProxy.createProxyServer({
396
- selfHandleResponse: true,
397
- target: {
398
- host,
399
- port,
400
- },
401
- })
402
- const headersFiles = [...new Set([path.resolve(projectDir, '_headers'), path.resolve(distDir, '_headers')])]
403
-
404
- let headers = await parseHeaders({ headersFiles, configPath })
405
-
406
- const watchedHeadersFiles = configPath === undefined ? headersFiles : [...headersFiles, configPath]
407
- onChanges(watchedHeadersFiles, async () => {
408
- const existingHeadersFiles = await pFilter(watchedHeadersFiles, fileExistsAsync)
409
- console.log(
410
- `${NETLIFYDEVLOG} Reloading headers files from`,
411
- existingHeadersFiles.map((headerFile) => path.relative(projectDir, headerFile)),
412
- )
413
- headers = await parseHeaders({ headersFiles, configPath })
414
- })
415
-
416
- proxy.before('web', 'stream', (req) => {
417
- // See https://github.com/http-party/node-http-proxy/issues/1219#issuecomment-511110375
418
- if (req.headers.expect) {
419
- req.__expectHeader = req.headers.expect
420
- delete req.headers.expect
421
- }
422
- })
423
-
424
- proxy.on('error', (_, req, res) => {
425
- res.writeHead(500, {
426
- 'Content-Type': 'text/plain',
427
- })
428
-
429
- const message = isEdgeFunctionsRequest(req)
430
- ? 'There was an error with an Edge Function. Please check the terminal for more details.'
431
- : 'Could not proxy request.'
432
-
433
- res.end(message)
434
- })
435
- proxy.on('proxyReq', (proxyReq, req) => {
436
- const requestID = generateRequestID()
437
-
438
- proxyReq.setHeader(NFRequestID, requestID)
439
- req.headers[NFRequestID] = requestID
440
-
441
- if (isEdgeFunctionsRequest(req)) {
442
- handleProxyRequest(req, proxyReq)
443
- }
444
-
445
- if (req.__expectHeader) {
446
- proxyReq.setHeader('Expect', req.__expectHeader)
447
- }
448
- if (req.originalBody) {
449
- proxyReq.write(req.originalBody)
450
- }
451
- })
452
- proxy.on('proxyRes', (proxyRes, req, res) => {
453
- res.setHeader('server', 'Netlify')
454
-
455
- const requestID = req.headers[NFRequestID]
456
-
457
- if (requestID) {
458
- res.setHeader(NFRequestID, requestID)
355
+ const proxy = httpProxy.createProxyServer({
356
+ selfHandleResponse: true,
357
+ target: {
358
+ host,
359
+ port,
360
+ },
361
+ });
362
+ const headersFiles = [...new Set([path.resolve(projectDir, '_headers'), path.resolve(distDir, '_headers')])];
363
+ let headers = await parseHeaders({ headersFiles, configPath });
364
+ const watchedHeadersFiles = configPath === undefined ? headersFiles : [...headersFiles, configPath];
365
+ onChanges(watchedHeadersFiles, async () => {
366
+ const existingHeadersFiles = await pFilter(watchedHeadersFiles, fileExistsAsync);
367
+ console.log(`${NETLIFYDEVLOG} Reloading headers files from`, existingHeadersFiles.map((headerFile) => path.relative(projectDir, headerFile)));
368
+ headers = await parseHeaders({ headersFiles, configPath });
369
+ });
370
+ // @ts-expect-error TS(2339) FIXME: Property 'before' does not exist on type 'Server'.
371
+ proxy.before('web', 'stream', (req) => {
372
+ // See https://github.com/http-party/node-http-proxy/issues/1219#issuecomment-511110375
373
+ if (req.headers.expect) {
374
+ req.__expectHeader = req.headers.expect;
375
+ delete req.headers.expect;
376
+ }
377
+ });
378
+ proxy.on('error', (_, req, res) => {
379
+ // @ts-expect-error TS(2339) FIXME: Property 'writeHead' does not exist on type 'Socke... Remove this comment to see the full error message
380
+ res.writeHead(500, {
381
+ 'Content-Type': 'text/plain',
382
+ });
383
+ const message = isEdgeFunctionsRequest(req)
384
+ ? 'There was an error with an Edge Function. Please check the terminal for more details.'
385
+ : 'Could not proxy request.';
386
+ res.end(message);
387
+ });
388
+ proxy.on('proxyReq', (proxyReq, req) => {
389
+ const requestID = generateRequestID();
390
+ proxyReq.setHeader(NFRequestID, requestID);
391
+ req.headers[NFRequestID] = requestID;
392
+ if (isEdgeFunctionsRequest(req)) {
393
+ handleProxyRequest(req, proxyReq);
394
+ }
395
+ // @ts-expect-error TS(2339) FIXME: Property '__expectHeader' does not exist on type '... Remove this comment to see the full error message
396
+ if (req.__expectHeader) {
397
+ // @ts-expect-error TS(2339) FIXME: Property '__expectHeader' does not exist on type '... Remove this comment to see the full error message
398
+ proxyReq.setHeader('Expect', req.__expectHeader);
399
+ }
400
+ // @ts-expect-error TS(2339) FIXME: Property 'originalBody' does not exist on type 'In... Remove this comment to see the full error message
401
+ if (req.originalBody) {
402
+ // @ts-expect-error TS(2339) FIXME: Property 'originalBody' does not exist on type 'In... Remove this comment to see the full error message
403
+ proxyReq.write(req.originalBody);
404
+ }
405
+ });
406
+ proxy.on('proxyRes', (proxyRes, req, res) => {
407
+ res.setHeader('server', 'Netlify');
408
+ const requestID = req.headers[NFRequestID];
409
+ if (requestID) {
410
+ res.setHeader(NFRequestID, requestID);
411
+ }
412
+ if (proxyRes.statusCode === 404 || proxyRes.statusCode === 403) {
413
+ // If a request for `/path` has failed, we'll a few variations like
414
+ // `/path/index.html` to mimic the CDN behavior.
415
+ // @ts-expect-error TS(2339) FIXME: Property 'alternativePaths' does not exist on type... Remove this comment to see the full error message
416
+ if (req.alternativePaths && req.alternativePaths.length !== 0) {
417
+ // @ts-expect-error TS(2339) FIXME: Property 'alternativePaths' does not exist on type... Remove this comment to see the full error message
418
+ req.url = req.alternativePaths.shift();
419
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
420
+ return proxy.web(req, res, req.proxyOptions);
421
+ }
422
+ // The request has failed but we might still have a matching redirect
423
+ // rule (without `force`) that should kick in. This is how we mimic the
424
+ // file shadowing behavior from the CDN.
425
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
426
+ if (req.proxyOptions && req.proxyOptions.match) {
427
+ return serveRedirect({
428
+ // We don't want to match functions at this point because any redirects
429
+ // to functions will have already been processed, so we don't supply a
430
+ // functions registry to `serveRedirect`.
431
+ functionsRegistry: null,
432
+ req,
433
+ res,
434
+ proxy: handlers,
435
+ imageProxy,
436
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
437
+ match: req.proxyOptions.match,
438
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
439
+ options: req.proxyOptions,
440
+ siteInfo,
441
+ env,
442
+ });
443
+ }
444
+ }
445
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
446
+ if (req.proxyOptions.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) {
447
+ req.url = proxyRes.headers.location;
448
+ return serveRedirect({
449
+ // We don't want to match functions at this point because any redirects
450
+ // to functions will have already been processed, so we don't supply a
451
+ // functions registry to `serveRedirect`.
452
+ functionsRegistry: null,
453
+ req,
454
+ res,
455
+ proxy: handlers,
456
+ imageProxy,
457
+ match: null,
458
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
459
+ options: req.proxyOptions,
460
+ siteInfo,
461
+ env,
462
+ });
463
+ }
464
+ // @ts-expect-error TS(7034) FIXME: Variable 'responseData' implicitly has type 'any[]... Remove this comment to see the full error message
465
+ const responseData = [];
466
+ // @ts-expect-error TS(2345) FIXME: Argument of type 'string | undefined' is not assig... Remove this comment to see the full error message
467
+ const requestURL = new URL(req.url, `http://${req.headers.host || '127.0.0.1'}`);
468
+ const headersRules = headersForPath(headers, requestURL.pathname);
469
+ // for streamed responses, we can't do etag generation nor error templates.
470
+ // we'll just stream them through!
471
+ const isStreamedResponse = proxyRes.headers['content-length'] === undefined;
472
+ if (isStreamedResponse) {
473
+ Object.entries(headersRules).forEach(([key, val]) => {
474
+ // @ts-expect-error TS(2345) FIXME: Argument of type 'unknown' is not assignable to pa... Remove this comment to see the full error message
475
+ res.setHeader(key, val);
476
+ });
477
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
478
+ res.writeHead(req.proxyOptions.status || proxyRes.statusCode, proxyRes.headers);
479
+ proxyRes.on('data', function onData(data) {
480
+ res.write(data);
481
+ });
482
+ proxyRes.on('end', function onEnd() {
483
+ res.end();
484
+ });
485
+ return;
486
+ }
487
+ proxyRes.on('data', function onData(data) {
488
+ responseData.push(data);
489
+ });
490
+ proxyRes.on('end', async function onEnd() {
491
+ // @ts-expect-error TS(7005) FIXME: Variable 'responseData' implicitly has an 'any[]' ... Remove this comment to see the full error message
492
+ const responseBody = Buffer.concat(responseData);
493
+ // @ts-expect-error TS(2339) FIXME: Property 'proxyOptions' does not exist on type 'In... Remove this comment to see the full error message
494
+ let responseStatus = req.proxyOptions.status || proxyRes.statusCode;
495
+ // `req[shouldGenerateETag]` may contain a function that determines
496
+ // whether the response should have an ETag header.
497
+ if (
498
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
499
+ typeof req[shouldGenerateETag] === 'function' &&
500
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
501
+ req[shouldGenerateETag]({ statusCode: responseStatus }) === true) {
502
+ const etag = generateETag(responseBody, { weak: true });
503
+ if (req.headers['if-none-match'] === etag) {
504
+ responseStatus = 304;
505
+ }
506
+ res.setHeader('etag', etag);
507
+ }
508
+ Object.entries(headersRules).forEach(([key, val]) => {
509
+ // @ts-expect-error TS(2345) FIXME: Argument of type 'unknown' is not assignable to pa... Remove this comment to see the full error message
510
+ res.setHeader(key, val);
511
+ });
512
+ const isUncaughtError = proxyRes.headers['x-nf-uncaught-error'] === '1';
513
+ if (isEdgeFunctionsRequest(req) && isUncaughtError) {
514
+ const acceptsHtml = req.headers && req.headers.accept && req.headers.accept.includes('text/html');
515
+ const decompressedBody = await decompressResponseBody(responseBody, proxyRes.headers['content-encoding']);
516
+ const formattedBody = formatEdgeFunctionError(decompressedBody, acceptsHtml);
517
+ const errorResponse = acceptsHtml
518
+ ? await renderErrorTemplate(formattedBody, './templates/function-error.html', 'edge function')
519
+ : formattedBody;
520
+ const contentLength = Buffer.from(errorResponse, 'utf8').byteLength;
521
+ res.setHeader('content-length', contentLength);
522
+ res.statusCode = 500;
523
+ res.write(errorResponse);
524
+ return res.end();
525
+ }
526
+ res.writeHead(responseStatus, proxyRes.headers);
527
+ if (responseStatus !== 304) {
528
+ res.write(responseBody);
529
+ }
530
+ res.end();
531
+ });
532
+ });
533
+ const handlers = {
534
+ // @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type.
535
+ web: (req, res, options) => {
536
+ const requestURL = new URL(req.url, 'http://127.0.0.1');
537
+ req.proxyOptions = options;
538
+ req.alternativePaths = alternativePathsFor(requestURL.pathname).map((filePath) => filePath + requestURL.search);
539
+ // Ref: https://nodejs.org/api/net.html#net_socket_remoteaddress
540
+ req.headers['x-forwarded-for'] = req.connection.remoteAddress || '';
541
+ return proxy.web(req, res, options);
542
+ },
543
+ // @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type.
544
+ ws: (req, socket, head) => proxy.ws(req, socket, head),
545
+ };
546
+ return handlers;
547
+ };
548
+ const onRequest = async ({
549
+ // @ts-expect-error TS(7031) FIXME: Binding element 'addonsUrls' implicitly has an 'an... Remove this comment to see the full error message
550
+ addonsUrls,
551
+ // @ts-expect-error TS(7031) FIXME: Binding element 'edgeFunctionsProxy' implicitly ha... Remove this comment to see the full error message
552
+ edgeFunctionsProxy,
553
+ // @ts-expect-error TS(7031) FIXME: Binding element 'env' implicitly has an 'any' type... Remove this comment to see the full error message
554
+ env,
555
+ // @ts-expect-error TS(7031) FIXME: Binding element 'functionsRegistry' implicitly has... Remove this comment to see the full error message
556
+ functionsRegistry,
557
+ // @ts-expect-error TS(7031) FIXME: Binding element 'functionsServer' implicitly has a... Remove this comment to see the full error message
558
+ functionsServer,
559
+ // @ts-expect-error TS(7031) FIXME: Binding element 'imageProxy' implicitly has an 'an... Remove this comment to see the full error message
560
+ imageProxy,
561
+ // @ts-expect-error TS(7031) FIXME: Binding element 'proxy' implicitly has an 'any' ty... Remove this comment to see the full error message
562
+ proxy,
563
+ // @ts-expect-error TS(7031) FIXME: Binding element 'rewriter' implicitly has an 'any'... Remove this comment to see the full error message
564
+ rewriter,
565
+ // @ts-expect-error TS(7031) FIXME: Binding element 'settings' implicitly has an 'any'... Remove this comment to see the full error message
566
+ settings,
567
+ // @ts-expect-error TS(7031) FIXME: Binding element 'siteInfo' implicitly has an 'any'... Remove this comment to see the full error message
568
+ siteInfo, },
569
+ // @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type.
570
+ req,
571
+ // @ts-expect-error TS(7006) FIXME: Parameter 'res' implicitly has an 'any' type.
572
+ res) => {
573
+ req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method)
574
+ ? null
575
+ : await createStreamPromise(req, BYTES_LIMIT);
576
+ const edgeFunctionsProxyURL = await edgeFunctionsProxy(req, res);
577
+ if (edgeFunctionsProxyURL !== undefined) {
578
+ return proxy.web(req, res, { target: edgeFunctionsProxyURL });
459
579
  }
460
-
461
- if (proxyRes.statusCode === 404 || proxyRes.statusCode === 403) {
462
- // If a request for `/path` has failed, we'll a few variations like
463
- // `/path/index.html` to mimic the CDN behavior.
464
- if (req.alternativePaths && req.alternativePaths.length !== 0) {
465
- req.url = req.alternativePaths.shift()
466
- return proxy.web(req, res, req.proxyOptions)
467
- }
468
-
469
- // The request has failed but we might still have a matching redirect
470
- // rule (without `force`) that should kick in. This is how we mimic the
471
- // file shadowing behavior from the CDN.
472
- if (req.proxyOptions && req.proxyOptions.match) {
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
- imageProxy,
482
- match: req.proxyOptions.match,
483
- options: req.proxyOptions,
484
- siteInfo,
485
- env,
486
- })
487
- }
580
+ const functionMatch = functionsRegistry && (await functionsRegistry.getFunctionForURLPath(req.url, req.method));
581
+ if (functionMatch) {
582
+ // Setting an internal header with the function name so that we don't
583
+ // have to match the URL again in the functions server.
584
+ /** @type {Record<string, string>} */
585
+ const headers = {};
586
+ if (functionMatch.func) {
587
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
588
+ headers[NFFunctionName] = functionMatch.func.name;
589
+ }
590
+ if (functionMatch.route) {
591
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
592
+ headers[NFFunctionRoute] = functionMatch.route.pattern;
593
+ }
594
+ return proxy.web(req, res, { headers, target: functionsServer });
488
595
  }
489
-
490
- if (req.proxyOptions.staticFile && isRedirect({ status: proxyRes.statusCode }) && proxyRes.headers.location) {
491
- req.url = proxyRes.headers.location
492
- return serveRedirect({
493
- // We don't want to match functions at this point because any redirects
494
- // to functions will have already been processed, so we don't supply a
495
- // functions registry to `serveRedirect`.
496
- functionsRegistry: null,
497
- req,
498
- res,
499
- proxy: handlers,
500
- imageProxy,
501
- match: null,
502
- options: req.proxyOptions,
503
- siteInfo,
504
- env,
505
- })
596
+ const addonUrl = getAddonUrl(addonsUrls, req);
597
+ if (addonUrl) {
598
+ return handleAddonUrl({ req, res, addonUrl });
506
599
  }
507
-
508
- const responseData = []
509
- const requestURL = new URL(req.url, `http://${req.headers.host || '127.0.0.1'}`)
510
- const headersRules = headersForPath(headers, requestURL.pathname)
511
-
512
- // for streamed responses, we can't do etag generation nor error templates.
513
- // we'll just stream them through!
514
- const isStreamedResponse = proxyRes.headers['content-length'] === undefined
515
- if (isStreamedResponse) {
516
- Object.entries(headersRules).forEach(([key, val]) => {
517
- res.setHeader(key, val)
518
- })
519
- res.writeHead(req.proxyOptions.status || proxyRes.statusCode, proxyRes.headers)
520
-
521
- proxyRes.on('data', function onData(data) {
522
- res.write(data)
523
- })
524
-
525
- proxyRes.on('end', function onEnd() {
526
- res.end()
527
- })
528
-
529
- return
600
+ const match = await rewriter(req);
601
+ const options = {
602
+ match,
603
+ addonsUrls,
604
+ target: `http://${isIPv6(settings.frameworkHost) ? `[${settings.frameworkHost}]` : settings.frameworkHost}:${settings.frameworkPort}`,
605
+ publicFolder: settings.dist,
606
+ functionsServer,
607
+ functionsPort: settings.functionsPort,
608
+ jwtRolePath: settings.jwtRolePath,
609
+ framework: settings.framework,
610
+ };
611
+ if (match) {
612
+ // We don't want to generate an ETag for 3xx redirects.
613
+ // @ts-expect-error TS(7031) FIXME: Binding element 'statusCode' implicitly has an 'an... Remove this comment to see the full error message
614
+ req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400;
615
+ return serveRedirect({ req, res, proxy, imageProxy, match, options, siteInfo, env, functionsRegistry });
530
616
  }
531
-
532
- proxyRes.on('data', function onData(data) {
533
- responseData.push(data)
534
- })
535
-
536
- proxyRes.on('end', async function onEnd() {
537
- const responseBody = Buffer.concat(responseData)
538
-
539
- let responseStatus = req.proxyOptions.status || proxyRes.statusCode
540
-
541
- // `req[shouldGenerateETag]` may contain a function that determines
542
- // whether the response should have an ETag header.
543
- if (
544
- typeof req[shouldGenerateETag] === 'function' &&
545
- req[shouldGenerateETag]({ statusCode: responseStatus }) === true
546
- ) {
547
- const etag = generateETag(responseBody, { weak: true })
548
-
549
- if (req.headers['if-none-match'] === etag) {
550
- responseStatus = 304
551
- }
552
-
553
- res.setHeader('etag', etag)
554
- }
555
-
556
- Object.entries(headersRules).forEach(([key, val]) => {
557
- res.setHeader(key, val)
558
- })
559
-
560
- const isUncaughtError = proxyRes.headers['x-nf-uncaught-error'] === '1'
561
-
562
- if (isEdgeFunctionsRequest(req) && isUncaughtError) {
563
- const acceptsHtml = req.headers && req.headers.accept && req.headers.accept.includes('text/html')
564
- const decompressedBody = await decompressResponseBody(responseBody, proxyRes.headers['content-encoding'])
565
- const formattedBody = formatEdgeFunctionError(decompressedBody, acceptsHtml)
566
- const errorResponse = acceptsHtml
567
- ? await renderErrorTemplate(formattedBody, './templates/function-error.html', 'edge function')
568
- : formattedBody
569
- const contentLength = Buffer.from(errorResponse, 'utf8').byteLength
570
-
571
- res.setHeader('content-length', contentLength)
572
- res.statusCode = 500
573
- res.write(errorResponse)
574
- return res.end()
575
- }
576
-
577
- res.writeHead(responseStatus, proxyRes.headers)
578
-
579
- if (responseStatus !== 304) {
580
- res.write(responseBody)
581
- }
582
-
583
- res.end()
584
- })
585
- })
586
-
587
- const handlers = {
588
- web: (req, res, options) => {
589
- const requestURL = new URL(req.url, 'http://127.0.0.1')
590
- req.proxyOptions = options
591
- req.alternativePaths = alternativePathsFor(requestURL.pathname).map((filePath) => filePath + requestURL.search)
592
- // Ref: https://nodejs.org/api/net.html#net_socket_remoteaddress
593
- req.headers['x-forwarded-for'] = req.connection.remoteAddress || ''
594
- return proxy.web(req, res, options)
595
- },
596
- ws: (req, socket, head) => proxy.ws(req, socket, head),
597
- }
598
-
599
- return handlers
600
- }
601
-
602
- const onRequest = async (
603
- {
604
- addonsUrls,
605
- edgeFunctionsProxy,
606
- env,
607
- functionsRegistry,
608
- functionsServer,
609
- imageProxy,
610
- proxy,
611
- rewriter,
612
- settings,
613
- siteInfo,
614
- },
615
- req,
616
- res,
617
- ) => {
618
- req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method)
619
- ? null
620
- : await createStreamPromise(req, BYTES_LIMIT)
621
-
622
- const edgeFunctionsProxyURL = await edgeFunctionsProxy(req, res)
623
-
624
- if (edgeFunctionsProxyURL !== undefined) {
625
- return proxy.web(req, res, { target: edgeFunctionsProxyURL })
626
- }
627
-
628
- const functionMatch = functionsRegistry && (await functionsRegistry.getFunctionForURLPath(req.url, req.method))
629
-
630
- if (functionMatch) {
631
- // Setting an internal header with the function name so that we don't
632
- // have to match the URL again in the functions server.
633
- /** @type {Record<string, string>} */
634
- const headers = {}
635
-
636
- if (functionMatch.func) {
637
- headers[NFFunctionName] = functionMatch.func.name
617
+ // The request will be served by the framework server, which means we want to
618
+ // generate an ETag unless we're rendering an error page. The only way for
619
+ // us to know that is by looking at the status code
620
+ // @ts-expect-error TS(7031) FIXME: Binding element 'statusCode' implicitly has an 'an... Remove this comment to see the full error message
621
+ req[shouldGenerateETag] = ({ statusCode }) => statusCode >= 200 && statusCode < 300;
622
+ const ct = req.headers['content-type'] ? contentType.parse(req).type : '';
623
+ if (functionsServer &&
624
+ req.method === 'POST' &&
625
+ !isInternal(req.url) &&
626
+ (ct.endsWith('/x-www-form-urlencoded') || ct === 'multipart/form-data')) {
627
+ return proxy.web(req, res, { target: functionsServer });
638
628
  }
639
-
640
- if (functionMatch.route) {
641
- headers[NFFunctionRoute] = functionMatch.route.pattern
629
+ if (isImageRequest(req)) {
630
+ return imageProxy(req, res);
642
631
  }
643
-
644
- return proxy.web(req, res, { headers, target: functionsServer })
645
- }
646
-
647
- const addonUrl = getAddonUrl(addonsUrls, req)
648
- if (addonUrl) {
649
- return handleAddonUrl({ req, res, addonUrl })
650
- }
651
-
652
- const match = await rewriter(req)
653
- const options = {
654
- match,
655
- addonsUrls,
656
- target: `http://${isIPv6(settings.frameworkHost) ? `[${settings.frameworkHost}]` : settings.frameworkHost}:${
657
- settings.frameworkPort
658
- }`,
659
- publicFolder: settings.dist,
660
- functionsServer,
661
- functionsPort: settings.functionsPort,
662
- jwtRolePath: settings.jwtRolePath,
663
- framework: settings.framework,
664
- }
665
-
666
- if (match) {
667
- // We don't want to generate an ETag for 3xx redirects.
668
- req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400
669
-
670
- return serveRedirect({ req, res, proxy, imageProxy, match, options, siteInfo, env, functionsRegistry })
671
- }
672
-
673
- // The request will be served by the framework server, which means we want to
674
- // generate an ETag unless we're rendering an error page. The only way for
675
- // us to know that is by looking at the status code
676
- req[shouldGenerateETag] = ({ statusCode }) => statusCode >= 200 && statusCode < 300
677
-
678
- const ct = req.headers['content-type'] ? contentType.parse(req).type : ''
679
- if (
680
- functionsServer &&
681
- req.method === 'POST' &&
682
- !isInternal(req.url) &&
683
- (ct.endsWith('/x-www-form-urlencoded') || ct === 'multipart/form-data')
684
- ) {
685
- return proxy.web(req, res, { target: functionsServer })
686
- }
687
-
688
- if (isImageRequest(req)) {
689
- return imageProxy(req, res)
690
- }
691
-
692
- proxy.web(req, res, options)
693
- }
694
-
632
+ proxy.web(req, res, options);
633
+ };
695
634
  /**
696
635
  * @param {Pick<import('./types.js').ServerSettings, "https" | "port">} settings
697
636
  * @returns
698
637
  */
638
+ // @ts-expect-error TS(7006) FIXME: Parameter 'settings' implicitly has an 'any' type.
699
639
  export const getProxyUrl = function (settings) {
700
- const scheme = settings.https ? 'https' : 'http'
701
- return `${scheme}://localhost:${settings.port}`
702
- }
703
-
704
- export const startProxy = async function ({
705
- accountId,
706
- addonsUrls,
707
- blobsContext,
708
- config,
709
- configPath,
710
- debug,
711
- env,
712
- functionsRegistry,
713
- geoCountry,
714
- geolocationMode,
715
- getUpdatedConfig,
716
- inspectSettings,
717
- offline,
718
- projectDir,
719
- repositoryRoot,
720
- settings,
721
- siteInfo,
722
- state,
723
- }) {
724
- const secondaryServerPort = settings.https ? await getAvailablePort() : null
725
- const functionsServer = settings.functionsPort ? `http://127.0.0.1:${settings.functionsPort}` : null
726
- const edgeFunctionsProxy = await initializeEdgeFunctionsProxy({
727
- blobsContext,
728
- config,
729
- configPath,
730
- debug,
731
- env,
732
- geolocationMode,
733
- geoCountry,
734
- getUpdatedConfig,
735
- inspectSettings,
736
- mainPort: settings.port,
737
- offline,
738
- passthroughPort: secondaryServerPort || settings.port,
739
- settings,
740
- projectDir,
741
- repositoryRoot,
742
- siteInfo,
743
- accountId,
744
- state,
745
- })
746
-
747
- const imageProxy = await initializeImageProxy({
748
- config,
749
- })
750
- const proxy = await initializeProxy({
751
- env,
752
- host: settings.frameworkHost,
753
- port: settings.frameworkPort,
754
- distDir: settings.dist,
755
- projectDir,
756
- configPath,
757
- siteInfo,
758
- imageProxy,
759
- })
760
-
761
- const rewriter = await createRewriter({
762
- distDir: settings.dist,
763
- projectDir,
764
- jwtSecret: settings.jwtSecret,
765
- jwtRoleClaim: settings.jwtRolePath,
766
- configPath,
767
- geoCountry,
768
- })
769
-
770
- const onRequestWithOptions = onRequest.bind(undefined, {
771
- proxy,
772
- rewriter,
773
- settings,
774
- addonsUrls,
775
- functionsRegistry,
776
- functionsServer,
777
- edgeFunctionsProxy,
778
- imageProxy,
779
- siteInfo,
780
- env,
781
- })
782
- const primaryServer = settings.https
783
- ? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions)
784
- : http.createServer(onRequestWithOptions)
785
- const onUpgrade = function onUpgrade(req, socket, head) {
786
- proxy.ws(req, socket, head)
787
- }
788
-
789
- primaryServer.on('upgrade', onUpgrade)
790
- primaryServer.listen({ port: settings.port })
791
-
792
- const eventQueue = [once(primaryServer, 'listening')]
793
-
794
- // If we're running the main server on HTTPS, we need to start a secondary
795
- // server on HTTP for receiving passthrough requests from edge functions.
796
- // This lets us run the Deno server on HTTP and avoid the complications of
797
- // Deno talking to Node on HTTPS with potentially untrusted certificates.
798
- if (secondaryServerPort) {
799
- const secondaryServer = http.createServer(onRequestWithOptions)
800
-
801
- secondaryServer.on('upgrade', onUpgrade)
802
- secondaryServer.listen({ port: secondaryServerPort })
803
-
804
- eventQueue.push(once(secondaryServer, 'listening'))
805
- }
806
-
807
- await Promise.all(eventQueue)
808
-
809
- return getProxyUrl(settings)
810
- }
811
-
812
- const BYTES_LIMIT = 30
640
+ const scheme = settings.https ? 'https' : 'http';
641
+ return `${scheme}://localhost:${settings.port}`;
642
+ };
643
+ export const startProxy = async function ({
644
+ // @ts-expect-error TS(7031) FIXME: Binding element 'accountId' implicitly has an 'any... Remove this comment to see the full error message
645
+ accountId,
646
+ // @ts-expect-error TS(7031) FIXME: Binding element 'addonsUrls' implicitly has an 'an... Remove this comment to see the full error message
647
+ addonsUrls,
648
+ // @ts-expect-error TS(7031) FIXME: Binding element 'blobsContext' implicitly has an '... Remove this comment to see the full error message
649
+ blobsContext,
650
+ // @ts-expect-error TS(7031) FIXME: Binding element 'config' implicitly has an 'any' t... Remove this comment to see the full error message
651
+ config,
652
+ // @ts-expect-error TS(7031) FIXME: Binding element 'configPath' implicitly has an 'an... Remove this comment to see the full error message
653
+ configPath,
654
+ // @ts-expect-error TS(7031) FIXME: Binding element 'debug' implicitly has an 'any' ty... Remove this comment to see the full error message
655
+ debug,
656
+ // @ts-expect-error TS(7031) FIXME: Binding element 'env' implicitly has an 'any' type... Remove this comment to see the full error message
657
+ env,
658
+ // @ts-expect-error TS(7031) FIXME: Binding element 'functionsRegistry' implicitly has... Remove this comment to see the full error message
659
+ functionsRegistry,
660
+ // @ts-expect-error TS(7031) FIXME: Binding element 'geoCountry' implicitly has an 'an... Remove this comment to see the full error message
661
+ geoCountry,
662
+ // @ts-expect-error TS(7031) FIXME: Binding element 'geolocationMode' implicitly has a... Remove this comment to see the full error message
663
+ geolocationMode,
664
+ // @ts-expect-error TS(7031) FIXME: Binding element 'getUpdatedConfig' implicitly has ... Remove this comment to see the full error message
665
+ getUpdatedConfig,
666
+ // @ts-expect-error TS(7031) FIXME: Binding element 'inspectSettings' implicitly has a... Remove this comment to see the full error message
667
+ inspectSettings,
668
+ // @ts-expect-error TS(7031) FIXME: Binding element 'offline' implicitly has an 'any' ... Remove this comment to see the full error message
669
+ offline,
670
+ // @ts-expect-error TS(7031) FIXME: Binding element 'projectDir' implicitly has an 'an... Remove this comment to see the full error message
671
+ projectDir,
672
+ // @ts-expect-error TS(7031) FIXME: Binding element 'repositoryRoot' implicitly has an... Remove this comment to see the full error message
673
+ repositoryRoot,
674
+ // @ts-expect-error TS(7031) FIXME: Binding element 'settings' implicitly has an 'any'... Remove this comment to see the full error message
675
+ settings,
676
+ // @ts-expect-error TS(7031) FIXME: Binding element 'siteInfo' implicitly has an 'any'... Remove this comment to see the full error message
677
+ siteInfo,
678
+ // @ts-expect-error TS(7031) FIXME: Binding element 'state' implicitly has an 'any' ty... Remove this comment to see the full error message
679
+ state, }) {
680
+ const secondaryServerPort = settings.https ? await getAvailablePort() : null;
681
+ const functionsServer = settings.functionsPort ? `http://127.0.0.1:${settings.functionsPort}` : null;
682
+ const edgeFunctionsProxy = await initializeEdgeFunctionsProxy({
683
+ blobsContext,
684
+ config,
685
+ configPath,
686
+ debug,
687
+ env,
688
+ geolocationMode,
689
+ geoCountry,
690
+ getUpdatedConfig,
691
+ inspectSettings,
692
+ mainPort: settings.port,
693
+ offline,
694
+ passthroughPort: secondaryServerPort || settings.port,
695
+ settings,
696
+ projectDir,
697
+ repositoryRoot,
698
+ siteInfo,
699
+ accountId,
700
+ state,
701
+ });
702
+ const imageProxy = await initializeImageProxy({
703
+ config,
704
+ });
705
+ const proxy = await initializeProxy({
706
+ env,
707
+ host: settings.frameworkHost,
708
+ port: settings.frameworkPort,
709
+ distDir: settings.dist,
710
+ projectDir,
711
+ configPath,
712
+ siteInfo,
713
+ imageProxy,
714
+ });
715
+ const rewriter = await createRewriter({
716
+ distDir: settings.dist,
717
+ projectDir,
718
+ jwtSecret: settings.jwtSecret,
719
+ jwtRoleClaim: settings.jwtRolePath,
720
+ configPath,
721
+ geoCountry,
722
+ });
723
+ const onRequestWithOptions = onRequest.bind(undefined, {
724
+ proxy,
725
+ rewriter,
726
+ settings,
727
+ addonsUrls,
728
+ functionsRegistry,
729
+ functionsServer,
730
+ edgeFunctionsProxy,
731
+ imageProxy,
732
+ siteInfo,
733
+ env,
734
+ });
735
+ const primaryServer = settings.https
736
+ ? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions)
737
+ : http.createServer(onRequestWithOptions);
738
+ // @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type.
739
+ const onUpgrade = function onUpgrade(req, socket, head) {
740
+ proxy.ws(req, socket, head);
741
+ };
742
+ primaryServer.on('upgrade', onUpgrade);
743
+ primaryServer.listen({ port: settings.port });
744
+ const eventQueue = [once(primaryServer, 'listening')];
745
+ // If we're running the main server on HTTPS, we need to start a secondary
746
+ // server on HTTP for receiving passthrough requests from edge functions.
747
+ // This lets us run the Deno server on HTTP and avoid the complications of
748
+ // Deno talking to Node on HTTPS with potentially untrusted certificates.
749
+ if (secondaryServerPort) {
750
+ const secondaryServer = http.createServer(onRequestWithOptions);
751
+ secondaryServer.on('upgrade', onUpgrade);
752
+ secondaryServer.listen({ port: secondaryServerPort });
753
+ eventQueue.push(once(secondaryServer, 'listening'));
754
+ }
755
+ await Promise.all(eventQueue);
756
+ return getProxyUrl(settings);
757
+ };
758
+ const BYTES_LIMIT = 30;