netlify-cli 15.7.0 → 15.8.1-rc.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 +5726 -4405
- package/package.json +9 -10
- package/src/commands/base-command.mjs +33 -5
- package/src/commands/dev/dev.mjs +15 -14
- package/src/commands/env/env-set.mjs +50 -10
- package/src/commands/functions/functions-serve.mjs +2 -1
- package/src/commands/serve/serve.mjs +4 -2
- package/src/functions-templates/typescript/hello-world/package-lock.json +6 -6
- package/src/functions-templates/typescript/transform-response/{{name}}.ts +0 -1
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/headers.mjs +1 -0
- package/src/lib/edge-functions/proxy.mjs +9 -0
- package/src/lib/edge-functions/registry.mjs +11 -9
- package/src/lib/functions/runtimes/js/builders/zisi.mjs +2 -12
- package/src/lib/functions/server.mjs +1 -0
- package/src/lib/functions/synchronous.mjs +10 -10
- package/src/lib/spinner.mjs +1 -1
- package/src/utils/command-helpers.mjs +10 -3
- package/src/utils/detect-server-settings.mjs +124 -132
- package/src/utils/dev.mjs +1 -0
- package/src/utils/framework-server.mjs +2 -2
- package/src/utils/init/config-github.mjs +2 -2
- package/src/utils/init/config-manual.mjs +2 -2
- package/src/utils/init/frameworks.mjs +10 -7
- package/src/utils/init/utils.mjs +6 -5
- package/src/utils/proxy-server.mjs +2 -0
- package/src/utils/proxy.mjs +29 -2
- package/src/utils/run-build.mjs +44 -4
- package/src/utils/shell.mjs +13 -2
- package/src/utils/static-server.mjs +4 -0
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { readFile } from 'fs/promises'
|
|
3
3
|
import { EOL } from 'os'
|
|
4
|
-
import path from 'path'
|
|
4
|
+
import path, { join } from 'path'
|
|
5
5
|
import process from 'process'
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
// eslint-disable-next-line import/extensions, n/no-missing-import
|
|
9
|
-
import { NodeFS } from '@netlify/build-info/node'
|
|
10
|
-
import { getFramework, listFrameworks } from '@netlify/framework-info'
|
|
7
|
+
import { getFramework, getSettings } from '@netlify/build-info'
|
|
11
8
|
import fuzzy from 'fuzzy'
|
|
12
9
|
import getPort from 'get-port'
|
|
13
10
|
|
|
14
11
|
import { NETLIFYDEVWARN, chalk, log } from './command-helpers.mjs'
|
|
15
12
|
import { acquirePort } from './dev.mjs'
|
|
16
13
|
import { getInternalFunctionsDir } from './functions/functions.mjs'
|
|
17
|
-
import { reportError } from './telemetry/report-error.mjs'
|
|
18
14
|
|
|
15
|
+
/** @param {string} str */
|
|
19
16
|
const formatProperty = (str) => chalk.magenta(`'${str}'`)
|
|
17
|
+
/** @param {string} str */
|
|
20
18
|
const formatValue = (str) => chalk.green(`'${str}'`)
|
|
21
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} options
|
|
22
|
+
* @param {string} options.keyFile
|
|
23
|
+
* @param {string} options.certFile
|
|
24
|
+
* @returns {Promise<{ key: string, cert: string, keyFilePath: string, certFilePath: string }>}
|
|
25
|
+
*/
|
|
22
26
|
const readHttpsSettings = async (options) => {
|
|
23
27
|
if (typeof options !== 'object' || !options.keyFile || !options.certFile) {
|
|
24
28
|
throw new TypeError(
|
|
@@ -51,6 +55,11 @@ const readHttpsSettings = async (options) => {
|
|
|
51
55
|
return { key, cert, keyFilePath: path.resolve(keyFile), certFilePath: path.resolve(certFile) }
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @param {object} config
|
|
60
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
61
|
+
* @param {keyof import('../commands/dev/types.js').DevConfig} config.property
|
|
62
|
+
*/
|
|
54
63
|
const validateStringProperty = ({ devConfig, property }) => {
|
|
55
64
|
if (devConfig[property] && typeof devConfig[property] !== 'string') {
|
|
56
65
|
const formattedProperty = formatProperty(property)
|
|
@@ -60,6 +69,11 @@ const validateStringProperty = ({ devConfig, property }) => {
|
|
|
60
69
|
}
|
|
61
70
|
}
|
|
62
71
|
|
|
72
|
+
/**
|
|
73
|
+
* @param {object} config
|
|
74
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
75
|
+
* @param {keyof import('../commands/dev/types.js').DevConfig} config.property
|
|
76
|
+
*/
|
|
63
77
|
const validateNumberProperty = ({ devConfig, property }) => {
|
|
64
78
|
if (devConfig[property] && typeof devConfig[property] !== 'number') {
|
|
65
79
|
const formattedProperty = formatProperty(property)
|
|
@@ -69,6 +83,11 @@ const validateNumberProperty = ({ devConfig, property }) => {
|
|
|
69
83
|
}
|
|
70
84
|
}
|
|
71
85
|
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @param {object} config
|
|
89
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
90
|
+
*/
|
|
72
91
|
const validateFrameworkConfig = ({ devConfig }) => {
|
|
73
92
|
validateStringProperty({ devConfig, property: 'command' })
|
|
74
93
|
validateNumberProperty({ devConfig, property: 'port' })
|
|
@@ -83,6 +102,11 @@ const validateFrameworkConfig = ({ devConfig }) => {
|
|
|
83
102
|
}
|
|
84
103
|
}
|
|
85
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @param {object} config
|
|
107
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
108
|
+
* @param {number=} config.detectedPort
|
|
109
|
+
*/
|
|
86
110
|
const validateConfiguredPort = ({ detectedPort, devConfig }) => {
|
|
87
111
|
if (devConfig.port && devConfig.port === detectedPort) {
|
|
88
112
|
const formattedPort = formatProperty('port')
|
|
@@ -102,6 +126,11 @@ const getDefaultDist = () => {
|
|
|
102
126
|
return process.cwd()
|
|
103
127
|
}
|
|
104
128
|
|
|
129
|
+
/**
|
|
130
|
+
* @param {object} config
|
|
131
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
132
|
+
* @returns {Promise<number>}
|
|
133
|
+
*/
|
|
105
134
|
const getStaticServerPort = async ({ devConfig }) => {
|
|
106
135
|
const port = await acquirePort({
|
|
107
136
|
configuredPort: devConfig.staticServerPort,
|
|
@@ -114,10 +143,10 @@ const getStaticServerPort = async ({ devConfig }) => {
|
|
|
114
143
|
|
|
115
144
|
/**
|
|
116
145
|
*
|
|
117
|
-
* @param {object}
|
|
118
|
-
* @param {import('../commands/dev/types.js').DevConfig}
|
|
119
|
-
* @param {import('commander').OptionValues}
|
|
120
|
-
* @param {string}
|
|
146
|
+
* @param {object} config
|
|
147
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
148
|
+
* @param {import('commander').OptionValues} config.options
|
|
149
|
+
* @param {string} config.projectDir
|
|
121
150
|
* @returns {Promise<import('./types.js').BaseServerSettings>}
|
|
122
151
|
*/
|
|
123
152
|
const handleStaticServer = async ({ devConfig, options, projectDir }) => {
|
|
@@ -153,120 +182,84 @@ const handleStaticServer = async ({ devConfig, options, projectDir }) => {
|
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
|
|
185
|
+
// these plugins represent runtimes that are
|
|
186
|
+
// expected to be "automatically" installed. Even though
|
|
187
|
+
// they can be installed on package/toml, we always
|
|
188
|
+
// want them installed in the site settings. When installed
|
|
189
|
+
// there our build will automatically install the latest without
|
|
190
|
+
// user management of the versioning.
|
|
191
|
+
const pluginsToAlwaysInstall = new Set(['@netlify/plugin-nextjs'])
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Retrieve a list of plugins to auto install
|
|
195
|
+
* @param {string[]=} pluginsInstalled
|
|
196
|
+
* @param {string[]=} pluginsRecommended
|
|
197
|
+
* @returns
|
|
198
|
+
*/
|
|
199
|
+
const getPluginsToAutoInstall = (pluginsInstalled = [], pluginsRecommended = []) =>
|
|
200
|
+
pluginsRecommended.reduce(
|
|
201
|
+
(acc, plugin) =>
|
|
202
|
+
pluginsInstalled.includes(plugin) && !pluginsToAlwaysInstall.has(plugin) ? acc : [...acc, plugin],
|
|
203
|
+
// eslint-disable-next-line no-inline-comments
|
|
204
|
+
/** @type {string[]} */ ([]),
|
|
205
|
+
)
|
|
206
|
+
|
|
156
207
|
/**
|
|
157
208
|
* Retrieves the settings from a framework
|
|
158
|
-
* @param {import('
|
|
209
|
+
* @param {import('@netlify/build-info').Settings} settings
|
|
159
210
|
* @returns {import('./types.js').BaseServerSettings}
|
|
160
211
|
*/
|
|
161
|
-
const
|
|
212
|
+
const getSettingsFromDetectedSettings = (settings) => {
|
|
162
213
|
const {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
} =
|
|
214
|
+
devCommand: command,
|
|
215
|
+
dist,
|
|
216
|
+
env,
|
|
217
|
+
framework: { name: frameworkName },
|
|
218
|
+
frameworkPort,
|
|
219
|
+
// eslint-disable-next-line camelcase
|
|
220
|
+
plugins_from_config_file,
|
|
221
|
+
// eslint-disable-next-line camelcase
|
|
222
|
+
plugins_recommended,
|
|
223
|
+
pollingStrategies,
|
|
224
|
+
} = settings
|
|
174
225
|
|
|
175
226
|
return {
|
|
176
227
|
command,
|
|
177
228
|
frameworkPort,
|
|
178
|
-
dist
|
|
229
|
+
dist,
|
|
179
230
|
framework: frameworkName,
|
|
180
231
|
env,
|
|
181
|
-
pollingStrategies
|
|
182
|
-
plugins,
|
|
232
|
+
pollingStrategies,
|
|
233
|
+
plugins: getPluginsToAutoInstall(plugins_from_config_file, plugins_recommended),
|
|
183
234
|
}
|
|
184
235
|
}
|
|
185
236
|
|
|
186
|
-
const hasDevCommand = (framework) => Array.isArray(framework.dev.commands) && framework.dev.commands.length !== 0
|
|
187
|
-
|
|
188
237
|
/**
|
|
189
|
-
*
|
|
190
|
-
* @param {string} projectDir
|
|
238
|
+
* @param {import('@netlify/build-info').Project} project
|
|
191
239
|
*/
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
*
|
|
201
|
-
* @param {import('./types.js').BaseServerSettings | undefined} frameworkSettings
|
|
202
|
-
* @param {import('@netlify/build-info').Settings[]} newSettings
|
|
203
|
-
* @param {Record<string, Record<string, any>>} [metadata]
|
|
204
|
-
*/
|
|
205
|
-
const detectChangesInNewSettings = (frameworkSettings, newSettings, metadata) => {
|
|
206
|
-
/** @type {string[]} */
|
|
207
|
-
const message = ['']
|
|
208
|
-
const [setting] = newSettings
|
|
209
|
-
|
|
210
|
-
if (frameworkSettings?.framework !== setting?.framework) {
|
|
211
|
-
message.push(
|
|
212
|
-
`- Framework does not match:`,
|
|
213
|
-
` [old]: ${frameworkSettings?.framework}`,
|
|
214
|
-
` [new]: ${setting?.framework}`,
|
|
215
|
-
'',
|
|
216
|
-
)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (frameworkSettings?.command !== setting?.devCommand) {
|
|
220
|
-
message.push(
|
|
221
|
-
`- command does not match:`,
|
|
222
|
-
` [old]: ${frameworkSettings?.command}`,
|
|
223
|
-
` [new]: ${setting?.devCommand}`,
|
|
224
|
-
'',
|
|
225
|
-
)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (frameworkSettings?.dist !== setting?.dist) {
|
|
229
|
-
message.push(`- dist does not match:`, ` [old]: ${frameworkSettings?.dist}`, ` [new]: ${setting?.dist}`, '')
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (frameworkSettings?.frameworkPort !== setting?.frameworkPort) {
|
|
233
|
-
message.push(
|
|
234
|
-
`- frameworkPort does not match:`,
|
|
235
|
-
` [old]: ${frameworkSettings?.frameworkPort}`,
|
|
236
|
-
` [new]: ${setting?.frameworkPort}`,
|
|
237
|
-
'',
|
|
238
|
-
)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (message.length !== 0) {
|
|
242
|
-
reportError(
|
|
243
|
-
{
|
|
244
|
-
name: 'NewSettingsDetectionMismatch',
|
|
245
|
-
errorMessage: 'New Settings detection does not match old one',
|
|
246
|
-
message: message.join('\n'),
|
|
247
|
-
},
|
|
248
|
-
{ severity: 'info', metadata },
|
|
240
|
+
const detectFrameworkSettings = async (project) => {
|
|
241
|
+
const projectSettings = await project.getBuildSettings()
|
|
242
|
+
const settings = projectSettings
|
|
243
|
+
.filter((setting) =>
|
|
244
|
+
project.workspace && !project.workspace.isRoot
|
|
245
|
+
? process.cwd().startsWith(join(project.jsWorkspaceRoot, setting.packagePath ?? ''))
|
|
246
|
+
: true,
|
|
249
247
|
)
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const detectFrameworkSettings = async ({ projectDir }) => {
|
|
254
|
-
const projectFrameworks = await listFrameworks({ projectDir })
|
|
255
|
-
const frameworks = projectFrameworks.filter((framework) => hasDevCommand(framework))
|
|
248
|
+
.filter((setting) => setting.devCommand)
|
|
256
249
|
|
|
257
|
-
if (
|
|
258
|
-
return
|
|
250
|
+
if (settings.length === 1) {
|
|
251
|
+
return getSettingsFromDetectedSettings(settings[0])
|
|
259
252
|
}
|
|
260
253
|
|
|
261
|
-
if (
|
|
254
|
+
if (settings.length > 1) {
|
|
262
255
|
// performance optimization, load inquirer on demand
|
|
263
256
|
const { default: inquirer } = await import('inquirer')
|
|
264
257
|
const { default: inquirerAutocompletePrompt } = await import('inquirer-autocomplete-prompt')
|
|
265
258
|
/** multiple matching detectors, make the user choose */
|
|
266
259
|
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
267
|
-
const scriptInquirerOptions = formatSettingsArrForInquirer(
|
|
268
|
-
const {
|
|
269
|
-
name: '
|
|
260
|
+
const scriptInquirerOptions = formatSettingsArrForInquirer(settings)
|
|
261
|
+
const { chosenSettings } = await inquirer.prompt({
|
|
262
|
+
name: 'chosenSettings',
|
|
270
263
|
message: `Multiple possible start commands found`,
|
|
271
264
|
type: 'autocomplete',
|
|
272
265
|
source(_, input) {
|
|
@@ -279,19 +272,24 @@ const detectFrameworkSettings = async ({ projectDir }) => {
|
|
|
279
272
|
})
|
|
280
273
|
log(
|
|
281
274
|
`Add ${formatProperty(
|
|
282
|
-
`framework = "${
|
|
275
|
+
`framework = "${chosenSettings.framework.id}"`,
|
|
283
276
|
)} to the [dev] section of your netlify.toml to avoid this selection prompt next time`,
|
|
284
277
|
)
|
|
285
278
|
|
|
286
|
-
return
|
|
279
|
+
return getSettingsFromDetectedSettings(chosenSettings)
|
|
287
280
|
}
|
|
288
281
|
}
|
|
289
282
|
|
|
283
|
+
/**
|
|
284
|
+
* @param {object} config
|
|
285
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
286
|
+
*/
|
|
290
287
|
const hasCommandAndTargetPort = ({ devConfig }) => devConfig.command && devConfig.targetPort
|
|
291
288
|
|
|
292
289
|
/**
|
|
293
290
|
* Creates settings for the custom framework
|
|
294
|
-
* @param {
|
|
291
|
+
* @param {object} config
|
|
292
|
+
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
295
293
|
* @returns {import('./types.js').BaseServerSettings}
|
|
296
294
|
*/
|
|
297
295
|
const handleCustomFramework = ({ devConfig }) => {
|
|
@@ -311,6 +309,9 @@ const handleCustomFramework = ({ devConfig }) => {
|
|
|
311
309
|
}
|
|
312
310
|
}
|
|
313
311
|
|
|
312
|
+
/**
|
|
313
|
+
* @param {{ devConfig: any, frameworkSettings: import('./types.js').BaseServerSettings }} param0
|
|
314
|
+
*/
|
|
314
315
|
const mergeSettings = async ({ devConfig, frameworkSettings = {} }) => {
|
|
315
316
|
const {
|
|
316
317
|
command: frameworkCommand,
|
|
@@ -338,12 +339,14 @@ const mergeSettings = async ({ devConfig, frameworkSettings = {} }) => {
|
|
|
338
339
|
|
|
339
340
|
/**
|
|
340
341
|
* Handles a forced framework and retrieves the settings for it
|
|
341
|
-
* @param {
|
|
342
|
+
* @param {{ devConfig: any, project: import('@netlify/build-info').Project }} config
|
|
342
343
|
* @returns {Promise<import('./types.js').BaseServerSettings>}
|
|
343
344
|
*/
|
|
344
|
-
const handleForcedFramework = async ({ devConfig,
|
|
345
|
+
const handleForcedFramework = async ({ devConfig, project }) => {
|
|
345
346
|
// this throws if `devConfig.framework` is not a supported framework
|
|
346
|
-
const
|
|
347
|
+
const framework = await getFramework(devConfig.framework, project)
|
|
348
|
+
const settings = await getSettings(framework, project, '')
|
|
349
|
+
const frameworkSettings = getSettingsFromDetectedSettings(settings)
|
|
347
350
|
return mergeSettings({ devConfig, frameworkSettings })
|
|
348
351
|
}
|
|
349
352
|
|
|
@@ -351,11 +354,12 @@ const handleForcedFramework = async ({ devConfig, projectDir }) => {
|
|
|
351
354
|
* Get the server settings based on the flags and the devConfig
|
|
352
355
|
* @param {import('../commands/dev/types.js').DevConfig} devConfig
|
|
353
356
|
* @param {import('commander').OptionValues} options
|
|
357
|
+
* @param {import('@netlify/build-info').Project} project
|
|
354
358
|
* @param {string} projectDir
|
|
355
|
-
* @param {Record<string, Record<string, any>>} [metadata]
|
|
356
359
|
* @returns {Promise<import('./types.js').ServerSettings>}
|
|
357
360
|
*/
|
|
358
|
-
|
|
361
|
+
|
|
362
|
+
const detectServerSettings = async (devConfig, options, project, projectDir) => {
|
|
359
363
|
validateStringProperty({ devConfig, property: 'framework' })
|
|
360
364
|
|
|
361
365
|
/** @type {Partial<import('./types.js').BaseServerSettings>} */
|
|
@@ -368,22 +372,9 @@ const detectServerSettings = async (devConfig, options, projectDir, metadata) =>
|
|
|
368
372
|
// this is the default CLI behavior
|
|
369
373
|
|
|
370
374
|
const runDetection = !hasCommandAndTargetPort({ devConfig })
|
|
371
|
-
const frameworkSettings = runDetection ? await detectFrameworkSettings(
|
|
372
|
-
const newSettings = runDetection ? await detectSettings(projectDir) : undefined
|
|
373
|
-
|
|
374
|
-
// just report differences in the settings
|
|
375
|
-
detectChangesInNewSettings(frameworkSettings, newSettings || [], {
|
|
376
|
-
...metadata,
|
|
377
|
-
settings: {
|
|
378
|
-
projectDir,
|
|
379
|
-
devConfig,
|
|
380
|
-
options,
|
|
381
|
-
old: frameworkSettings,
|
|
382
|
-
settings: newSettings,
|
|
383
|
-
},
|
|
384
|
-
})
|
|
375
|
+
const frameworkSettings = runDetection ? await detectFrameworkSettings(project) : undefined
|
|
385
376
|
|
|
386
|
-
if (frameworkSettings === undefined
|
|
377
|
+
if (frameworkSettings === undefined) {
|
|
387
378
|
log(`${NETLIFYDEVWARN} No app server detected. Using simple static server`)
|
|
388
379
|
settings = await handleStaticServer({ options, devConfig, projectDir })
|
|
389
380
|
} else {
|
|
@@ -399,7 +390,7 @@ const detectServerSettings = async (devConfig, options, projectDir, metadata) =>
|
|
|
399
390
|
} else if (devConfig.framework) {
|
|
400
391
|
validateFrameworkConfig({ devConfig })
|
|
401
392
|
// this is when the user explicitly configures a framework, e.g. `framework = "gatsby"`
|
|
402
|
-
settings = await handleForcedFramework({ devConfig,
|
|
393
|
+
settings = await handleForcedFramework({ devConfig, project })
|
|
403
394
|
}
|
|
404
395
|
|
|
405
396
|
validateConfiguredPort({ devConfig, detectedPort: settings.frameworkPort })
|
|
@@ -435,15 +426,16 @@ const filterSettings = function (scriptInquirerOptions, input) {
|
|
|
435
426
|
return scriptInquirerOptions.filter((t) => filteredSettingNames.has(t.name))
|
|
436
427
|
}
|
|
437
428
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
429
|
+
/**
|
|
430
|
+
* @param {import('@netlify/build-info').Settings[]} settings
|
|
431
|
+
* @returns
|
|
432
|
+
*/
|
|
433
|
+
const formatSettingsArrForInquirer = function (settings) {
|
|
434
|
+
return settings.map((setting) => ({
|
|
435
|
+
name: `[${chalk.yellow(setting.framework.name)}] '${setting.devCommand}'`,
|
|
436
|
+
value: { ...setting, commands: [setting.devCommand] },
|
|
437
|
+
short: `${setting.name}-${setting.devCommand}`,
|
|
438
|
+
}))
|
|
447
439
|
}
|
|
448
440
|
|
|
449
441
|
/**
|
package/src/utils/dev.mjs
CHANGED
|
@@ -107,6 +107,7 @@ export const getSiteInformation = async ({ api, offline, site, siteInfo }) => {
|
|
|
107
107
|
return {
|
|
108
108
|
addonsUrls,
|
|
109
109
|
siteUrl: siteInfo.ssl_url,
|
|
110
|
+
accountId: account.id,
|
|
110
111
|
capabilities: {
|
|
111
112
|
backgroundFunctions: supportsBackgroundFunctions(account),
|
|
112
113
|
},
|
|
@@ -18,7 +18,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
|
|
|
18
18
|
/**
|
|
19
19
|
* Start a static server if the `useStaticServer` is provided or a framework specific server
|
|
20
20
|
* @param {object} config
|
|
21
|
-
* @param {
|
|
21
|
+
* @param {import('./types.js').ServerSettings} config.settings
|
|
22
22
|
* @returns {Promise<StartReturnObject>}
|
|
23
23
|
*/
|
|
24
24
|
export const startFrameworkServer = async function ({ settings }) {
|
|
@@ -46,7 +46,7 @@ export const startFrameworkServer = async function ({ settings }) {
|
|
|
46
46
|
host: 'localhost',
|
|
47
47
|
output: 'silent',
|
|
48
48
|
timeout: FRAMEWORK_PORT_TIMEOUT,
|
|
49
|
-
...(settings.pollingStrategies
|
|
49
|
+
...(settings.pollingStrategies?.includes('HTTP') && { protocol: 'http' }),
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
if (!port.open) {
|
|
@@ -207,7 +207,7 @@ export const configGithub = async ({ command, repoName, repoOwner, siteId }) =>
|
|
|
207
207
|
const { netlify } = command
|
|
208
208
|
const {
|
|
209
209
|
api,
|
|
210
|
-
cachedConfig: { configPath
|
|
210
|
+
cachedConfig: { configPath },
|
|
211
211
|
config,
|
|
212
212
|
globalConfig,
|
|
213
213
|
repositoryRoot,
|
|
@@ -220,7 +220,7 @@ export const configGithub = async ({ command, repoName, repoOwner, siteId }) =>
|
|
|
220
220
|
repositoryRoot,
|
|
221
221
|
siteRoot,
|
|
222
222
|
config,
|
|
223
|
-
|
|
223
|
+
project: command.project,
|
|
224
224
|
})
|
|
225
225
|
await saveNetlifyToml({ repositoryRoot, config, configPath, baseDir, buildCmd, buildDir, functionsDir })
|
|
226
226
|
|
|
@@ -62,7 +62,7 @@ export default async function configManual({ command, repoData, siteId }) {
|
|
|
62
62
|
const { netlify } = command
|
|
63
63
|
const {
|
|
64
64
|
api,
|
|
65
|
-
cachedConfig: { configPath
|
|
65
|
+
cachedConfig: { configPath },
|
|
66
66
|
config,
|
|
67
67
|
repositoryRoot,
|
|
68
68
|
site: { root: siteRoot },
|
|
@@ -72,7 +72,7 @@ export default async function configManual({ command, repoData, siteId }) {
|
|
|
72
72
|
repositoryRoot,
|
|
73
73
|
siteRoot,
|
|
74
74
|
config,
|
|
75
|
-
|
|
75
|
+
project: command.project,
|
|
76
76
|
})
|
|
77
77
|
await saveNetlifyToml({ repositoryRoot, config, configPath, baseDir, buildCmd, buildDir, functionsDir })
|
|
78
78
|
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
// @ts-
|
|
2
|
-
import { listFrameworks } from '@netlify/framework-info'
|
|
1
|
+
// @ts-checkom '@netlify/build-info'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @param {{ project: import("@netlify/build-info").Project }} param0
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export const getFrameworkInfo = async ({ project }) => {
|
|
8
|
+
const frameworks = await project.detectFrameworks()
|
|
6
9
|
// several frameworks can be detected - first one has highest priority
|
|
7
|
-
if (frameworks.length !== 0) {
|
|
10
|
+
if (frameworks && frameworks.length !== 0) {
|
|
8
11
|
const [
|
|
9
12
|
{
|
|
10
|
-
build: {
|
|
13
|
+
build: { command, directory },
|
|
11
14
|
name,
|
|
12
15
|
plugins,
|
|
13
16
|
},
|
|
14
17
|
] = frameworks
|
|
15
18
|
return {
|
|
16
19
|
frameworkName: name,
|
|
17
|
-
frameworkBuildCommand:
|
|
20
|
+
frameworkBuildCommand: command,
|
|
18
21
|
frameworkBuildDir: directory,
|
|
19
22
|
frameworkPlugins: plugins,
|
|
20
23
|
}
|
package/src/utils/init/utils.mjs
CHANGED
|
@@ -11,7 +11,6 @@ import { normalizeBackslash } from '../../lib/path.mjs'
|
|
|
11
11
|
import { chalk, error as failAndExit, log, warn } from '../command-helpers.mjs'
|
|
12
12
|
|
|
13
13
|
import { getFrameworkInfo } from './frameworks.mjs'
|
|
14
|
-
import { detectNodeVersion } from './node-version.mjs'
|
|
15
14
|
import { getRecommendPlugins, getUIPlugins } from './plugins.mjs'
|
|
16
15
|
|
|
17
16
|
const normalizeDir = ({ baseDirectory, defaultValue, dir }) => {
|
|
@@ -83,17 +82,19 @@ const getPromptInputs = ({ defaultBaseDir, defaultBuildCmd, defaultBuildDir }) =
|
|
|
83
82
|
const getBaseDirectory = ({ repositoryRoot, siteRoot }) =>
|
|
84
83
|
path.normalize(repositoryRoot) === path.normalize(siteRoot) ? process.cwd() : siteRoot
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
/**
|
|
86
|
+
* @param {{ config: any, repositoryRoot: any, siteRoot: any, project: import("@netlify/build-info").Project }} param0
|
|
87
|
+
* @returns
|
|
88
|
+
*/
|
|
89
|
+
export const getBuildSettings = async ({ config, project, repositoryRoot, siteRoot }) => {
|
|
87
90
|
const baseDirectory = getBaseDirectory({ repositoryRoot, siteRoot })
|
|
88
|
-
const nodeVersion = await detectNodeVersion({ baseDirectory, env })
|
|
89
91
|
const {
|
|
90
92
|
frameworkBuildCommand,
|
|
91
93
|
frameworkBuildDir,
|
|
92
94
|
frameworkName,
|
|
93
95
|
frameworkPlugins = [],
|
|
94
96
|
} = await getFrameworkInfo({
|
|
95
|
-
|
|
96
|
-
nodeVersion,
|
|
97
|
+
project,
|
|
97
98
|
})
|
|
98
99
|
const { defaultBaseDir, defaultBuildCmd, defaultBuildDir, defaultFunctionsDir, recommendedPlugins } =
|
|
99
100
|
await getDefaultSettings({
|
|
@@ -53,6 +53,7 @@ export const generateInspectSettings = (edgeInspect, edgeInspectBrk) => {
|
|
|
53
53
|
* @returns
|
|
54
54
|
*/
|
|
55
55
|
export const startProxyServer = async ({
|
|
56
|
+
accountId,
|
|
56
57
|
addonsUrls,
|
|
57
58
|
config,
|
|
58
59
|
configPath,
|
|
@@ -83,6 +84,7 @@ export const startProxyServer = async ({
|
|
|
83
84
|
settings,
|
|
84
85
|
state,
|
|
85
86
|
siteInfo,
|
|
87
|
+
accountId,
|
|
86
88
|
})
|
|
87
89
|
if (!url) {
|
|
88
90
|
log(NETLIFYDEVERR, `Unable to start proxy server on port '${settings.port}'`)
|
package/src/utils/proxy.mjs
CHANGED
|
@@ -36,9 +36,29 @@ import { generateRequestID } from './request-id.mjs'
|
|
|
36
36
|
import { createRewriter, onChanges } from './rules-proxy.mjs'
|
|
37
37
|
import { signRedirect } from './sign-redirect.mjs'
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const gunzip = util.promisify(zlib.gunzip)
|
|
40
|
+
const brotliDecompress = util.promisify(zlib.brotliDecompress)
|
|
41
|
+
const deflate = util.promisify(zlib.deflate)
|
|
40
42
|
const shouldGenerateETag = Symbol('Internal: response should generate ETag')
|
|
41
43
|
|
|
44
|
+
/**
|
|
45
|
+
* @param {Buffer} body
|
|
46
|
+
* @param {string | undefined} contentEncoding
|
|
47
|
+
* @returns {Promise<Buffer>}
|
|
48
|
+
*/
|
|
49
|
+
const decompressResponseBody = async function (body, contentEncoding = '') {
|
|
50
|
+
switch (contentEncoding) {
|
|
51
|
+
case 'gzip':
|
|
52
|
+
return await gunzip(body)
|
|
53
|
+
case 'br':
|
|
54
|
+
return await brotliDecompress(body)
|
|
55
|
+
case 'deflate':
|
|
56
|
+
return await deflate(body)
|
|
57
|
+
default:
|
|
58
|
+
return body
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
42
62
|
const formatEdgeFunctionError = (errorBuffer, acceptsHtml) => {
|
|
43
63
|
const {
|
|
44
64
|
error: { message, name, stack },
|
|
@@ -479,7 +499,7 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
479
499
|
|
|
480
500
|
if (isEdgeFunctionsRequest(req) && isUncaughtError) {
|
|
481
501
|
const acceptsHtml = req.headers && req.headers.accept && req.headers.accept.includes('text/html')
|
|
482
|
-
const decompressedBody = await
|
|
502
|
+
const decompressedBody = await decompressResponseBody(responseBody, req.headers['content-encoding'])
|
|
483
503
|
const formattedBody = formatEdgeFunctionError(decompressedBody, acceptsHtml)
|
|
484
504
|
const errorResponse = acceptsHtml
|
|
485
505
|
? await renderErrorTemplate(formattedBody, './templates/function-error.html', 'edge function')
|
|
@@ -487,6 +507,7 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
487
507
|
const contentLength = Buffer.from(errorResponse, 'utf8').byteLength
|
|
488
508
|
|
|
489
509
|
res.setHeader('content-length', contentLength)
|
|
510
|
+
res.statusCode = 500
|
|
490
511
|
res.write(errorResponse)
|
|
491
512
|
return res.end()
|
|
492
513
|
}
|
|
@@ -578,12 +599,17 @@ const onRequest = async (
|
|
|
578
599
|
proxy.web(req, res, options)
|
|
579
600
|
}
|
|
580
601
|
|
|
602
|
+
/**
|
|
603
|
+
* @param {import('./types.js').ServerSettings} settings
|
|
604
|
+
* @returns
|
|
605
|
+
*/
|
|
581
606
|
export const getProxyUrl = function (settings) {
|
|
582
607
|
const scheme = settings.https ? 'https' : 'http'
|
|
583
608
|
return `${scheme}://localhost:${settings.port}`
|
|
584
609
|
}
|
|
585
610
|
|
|
586
611
|
export const startProxy = async function ({
|
|
612
|
+
accountId,
|
|
587
613
|
addonsUrls,
|
|
588
614
|
config,
|
|
589
615
|
configPath,
|
|
@@ -615,6 +641,7 @@ export const startProxy = async function ({
|
|
|
615
641
|
passthroughPort: secondaryServerPort || settings.port,
|
|
616
642
|
projectDir,
|
|
617
643
|
siteInfo,
|
|
644
|
+
accountId,
|
|
618
645
|
state,
|
|
619
646
|
})
|
|
620
647
|
const proxy = await initializeProxy({
|