netlify-cli 9.16.7 → 10.1.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 (34) hide show
  1. package/README.md +10 -1
  2. package/npm-shrinkwrap.json +671 -3362
  3. package/package.json +8 -5
  4. package/src/commands/base-command.js +1 -2
  5. package/src/commands/deploy/deploy.js +0 -7
  6. package/src/commands/dev/dev.js +65 -52
  7. package/src/commands/main.js +3 -0
  8. package/src/commands/recipes/common.js +33 -0
  9. package/src/commands/recipes/index.js +8 -0
  10. package/src/commands/recipes/recipes-list.js +34 -0
  11. package/src/commands/recipes/recipes.js +85 -0
  12. package/src/lib/api.js +1 -72
  13. package/src/lib/edge-functions/consts.js +21 -0
  14. package/src/lib/edge-functions/deploy.js +41 -0
  15. package/src/lib/edge-functions/editor-helper.js +41 -0
  16. package/src/lib/edge-functions/headers.js +7 -0
  17. package/src/lib/edge-functions/index.js +7 -0
  18. package/src/lib/edge-functions/internal.js +75 -0
  19. package/src/lib/edge-functions/proxy.js +150 -0
  20. package/src/lib/edge-functions/registry.js +354 -0
  21. package/src/lib/functions/registry.js +1 -1
  22. package/src/lib/geo-location.js +99 -0
  23. package/src/recipes/vscode/index.js +61 -0
  24. package/src/recipes/vscode/settings.js +66 -0
  25. package/src/utils/command-helpers.js +10 -0
  26. package/src/utils/deploy/deploy-site.js +26 -4
  27. package/src/utils/deploy/hash-files.js +12 -7
  28. package/src/utils/deploy/hasher-segments.js +10 -2
  29. package/src/utils/functions/index.js +3 -2
  30. package/src/utils/index.js +0 -2
  31. package/src/utils/proxy.js +99 -12
  32. package/src/commands/dev/dev-trace.js +0 -47
  33. package/src/utils/functions/edge-handlers.js +0 -88
  34. package/src/utils/traffic-mesh.js +0 -219
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "9.16.7",
4
+ "version": "10.1.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Abraham Schilling <AbrahamSchilling@gmail.com> (https://gitlab.com/n4bb12)",
@@ -103,6 +103,7 @@
103
103
  "Sam Holmes <samholmes1337@gmail.com> (https://samholmes.net)",
104
104
  "Sander de Groot (https://degroot.dev)",
105
105
  "Sarah Drasner <sarah.drasner@gmail.com> (https://twitter.com/sarah_edo)",
106
+ "Sarah Etter <sarah@sarahetter.com> (http://www.sarahetter.com)",
106
107
  "Scott Spence <spences10apps@gmail.com> (https://twitter.com/spences10)",
107
108
  "Sean Grove <sean@bushi.do> (https://twitter.com/sgrove)",
108
109
  "Sebastian Smolorz",
@@ -206,13 +207,12 @@
206
207
  "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,yml,json,html}\" \"*.{mjs,cjs,js,yml,json,html}\" \".*.{mjs,cjs,js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!**/*/package-lock.json\" \"!.github/**/*.md\""
207
208
  },
208
209
  "dependencies": {
209
- "@netlify/build": "^26.5.3",
210
- "@netlify/config": "^17.0.20",
210
+ "@netlify/build": "^27.0.1",
211
+ "@netlify/config": "^18.0.0",
212
+ "@netlify/edge-bundler": "^0.12.0",
211
213
  "@netlify/framework-info": "^9.0.2",
212
214
  "@netlify/local-functions-proxy": "^1.1.1",
213
- "@netlify/plugin-edge-handlers": "^3.0.7",
214
215
  "@netlify/plugins-list": "^6.19.0",
215
- "@netlify/routing-local-proxy": "^0.34.1",
216
216
  "@netlify/zip-it-and-ship-it": "^5.9.0",
217
217
  "@octokit/rest": "^18.0.0",
218
218
  "@sindresorhus/slugify": "^1.1.0",
@@ -241,6 +241,7 @@
241
241
  "dotenv": "^16.0.0",
242
242
  "env-paths": "^2.2.0",
243
243
  "envinfo": "^7.3.1",
244
+ "etag": "^1.8.1",
244
245
  "execa": "^5.0.0",
245
246
  "express": "^4.17.1",
246
247
  "express-logging": "^1.1.1",
@@ -310,6 +311,7 @@
310
311
  "through2-map": "^3.0.0",
311
312
  "to-readable-stream": "^2.1.0",
312
313
  "toml": "^3.0.0",
314
+ "unixify": "^1.0.0",
313
315
  "update-notifier": "^5.0.0",
314
316
  "uuid": "^8.0.0",
315
317
  "wait-port": "^0.2.2",
@@ -329,6 +331,7 @@
329
331
  "husky": "^7.0.4",
330
332
  "ini": "^2.0.0",
331
333
  "mock-fs": "^5.1.2",
334
+ "nock": "^13.2.4",
332
335
  "p-timeout": "^4.0.0",
333
336
  "rewiremock": "^3.14.3",
334
337
  "seedrandom": "^3.0.5",
@@ -421,7 +421,6 @@ class BaseCommand extends Command {
421
421
  const cachedConfig = await actionCommand.getConfig({ cwd, state, token, ...apiUrlOpts })
422
422
  const { buildDir, config, configPath, repositoryRoot, siteInfo } = cachedConfig
423
423
  const normalizedConfig = normalizeConfig(config)
424
-
425
424
  const agent = await getAgent({
426
425
  httpProxy: options.httpProxy,
427
426
  certificateFile: options.httpProxyCertificateFilename,
@@ -478,7 +477,7 @@ class BaseCommand extends Command {
478
477
  options.context ||
479
478
  process.env.CONTEXT ||
480
479
  // Dev commands have a default context of `dev`, otherwise we let netlify/config handle default behavior
481
- (['dev', 'dev:exec', 'dev:trace'].includes(this.name()) ? 'dev' : undefined),
480
+ (['dev', 'dev:exec'].includes(this.name()) ? 'dev' : undefined),
482
481
  debug: this.opts().debug,
483
482
  siteId: options.siteId || (typeof options.site === 'string' && options.site) || state.get('siteId'),
484
483
  token,
@@ -20,7 +20,6 @@ const {
20
20
  NETLIFYDEVERR,
21
21
  NETLIFYDEVLOG,
22
22
  chalk,
23
- deployEdgeHandlers,
24
23
  deploySite,
25
24
  error,
26
25
  exit,
@@ -314,12 +313,6 @@ const runDeploy = async ({
314
313
  results = await api.createSiteDeploy({ siteId, title, body: { draft, branch: alias } })
315
314
  deployId = results.id
316
315
 
317
- await deployEdgeHandlers({
318
- site,
319
- deployId,
320
- api,
321
- silent,
322
- })
323
316
  const internalFunctionsFolder = await getInternalFunctionsDir({ base: site.root })
324
317
 
325
318
  // The order of the directories matter: zip-it-and-ship-it will prioritize
@@ -11,6 +11,7 @@ const StaticServer = require('static-server')
11
11
  const stripAnsiCc = require('strip-ansi-control-characters')
12
12
  const waitPort = require('wait-port')
13
13
 
14
+ const { promptEditorHelper } = require('../../lib/edge-functions')
14
15
  const { startFunctionsServer } = require('../../lib/functions/server')
15
16
  const {
16
17
  OneGraphCliClient,
@@ -42,7 +43,6 @@ const {
42
43
  normalizeConfig,
43
44
  openBrowser,
44
45
  processOnExit,
45
- startForwardProxy,
46
46
  startLiveTunnel,
47
47
  startProxy,
48
48
  warn,
@@ -50,7 +50,6 @@ const {
50
50
  } = require('../../utils')
51
51
 
52
52
  const { createDevExecCommand } = require('./dev-exec')
53
- const { createDevTraceCommand } = require('./dev-trace')
54
53
 
55
54
  const startStaticServer = async ({ settings }) => {
56
55
  const server = new StaticServer({
@@ -198,37 +197,44 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
198
197
 
199
198
  /**
200
199
  *
201
- * @param {object} config
202
- * @param {*} config.addonsUrls
203
- * @param {import('commander').OptionValues} config.options
204
- * @param {*} config.settings
205
- * @param {*} config.site
200
+ * @param {object} params
201
+ * @param {*} params.addonsUrls
202
+ * @param {import('../base-command').NetlifyOptions["config"]} params.config
203
+ * @param {() => Promise<object>} params.getUpdatedConfig
204
+ * @param {string} params.geolocationMode
205
+ * @param {*} params.settings
206
+ * @param {boolean} params.offline
207
+ * @param {*} params.site
208
+ * @param {import('../../utils/state-config').StateConfig} params.state
206
209
  * @returns
207
210
  */
208
- const startProxyServer = async ({ addonsUrls, options, settings, site }) => {
209
- let url
210
- if (options.edgeHandlers || options.trafficMesh) {
211
- url = await startForwardProxy({
212
- port: settings.port,
213
- frameworkPort: settings.frameworkPort,
214
- functionsPort: settings.functionsPort,
215
- publishDir: settings.dist,
216
- debug: options.debug,
217
- locationDb: options.locationDb,
218
- jwtRolesPath: settings.jwtRolePath,
219
- jwtSecret: settings.jwtSecret,
220
- })
221
- if (!url) {
222
- log(NETLIFYDEVERR, `Unable to start forward proxy on port '${settings.port}'`)
223
- exit(1)
224
- }
225
- } else {
226
- url = await startProxy(settings, addonsUrls, site.configPath, site.root)
227
- if (!url) {
228
- log(NETLIFYDEVERR, `Unable to start proxy server on port '${settings.port}'`)
229
- exit(1)
230
- }
211
+ const startProxyServer = async ({
212
+ addonsUrls,
213
+ config,
214
+ geolocationMode,
215
+ getUpdatedConfig,
216
+ offline,
217
+ settings,
218
+ site,
219
+ state,
220
+ }) => {
221
+ const url = await startProxy({
222
+ addonsUrls,
223
+ config,
224
+ configPath: site.configPath,
225
+ geolocationMode,
226
+ getUpdatedConfig,
227
+ offline,
228
+ projectDir: site.root,
229
+ settings,
230
+ state,
231
+ })
232
+
233
+ if (!url) {
234
+ log(NETLIFYDEVERR, `Unable to start proxy server on port '${settings.port}'`)
235
+ exit(1)
231
236
  }
237
+
232
238
  return url
233
239
  }
234
240
 
@@ -313,7 +319,7 @@ const startPollingForAPIAuthentication = async function (options) {
313
319
  */
314
320
  const dev = async (options, command) => {
315
321
  log(`${NETLIFYDEV}`)
316
- const { api, config, site, siteInfo, state } = command.netlify
322
+ const { api, config, repositoryRoot, site, siteInfo, state } = command.netlify
317
323
  config.dev = { ...config.dev }
318
324
  config.build = { ...config.build }
319
325
  /** @type {import('./types').DevConfig} */
@@ -325,13 +331,8 @@ const dev = async (options, command) => {
325
331
  ...options,
326
332
  }
327
333
 
328
- if (options.trafficMesh) {
329
- warn(
330
- '--trafficMesh and -t are deprecated and will be removed in the near future. Please use --edgeHandlers or -e instead.',
331
- )
332
- }
333
-
334
334
  await injectEnvVariables({ devConfig, env: command.netlify.cachedConfig.env, site })
335
+ await promptEditorHelper({ chalk, config, log, NETLIFYDEVLOG, repositoryRoot, state })
335
336
 
336
337
  const { addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({
337
338
  // inherited from base command --offline
@@ -370,7 +371,25 @@ const dev = async (options, command) => {
370
371
  })
371
372
  await startFrameworkServer({ settings })
372
373
 
373
- let url = await startProxyServer({ options, settings, site, addonsUrls })
374
+ // TODO: We should consolidate this with the existing config watcher.
375
+ const getUpdatedConfig = async () => {
376
+ const cwd = options.cwd || process.cwd()
377
+ const { config: newConfig } = await command.getConfig({ cwd, offline: true, state })
378
+ const normalizedNewConfig = normalizeConfig(newConfig)
379
+
380
+ return normalizedNewConfig
381
+ }
382
+
383
+ let url = await startProxyServer({
384
+ addonsUrls,
385
+ config,
386
+ geolocationMode: options.geo,
387
+ getUpdatedConfig,
388
+ offline: options.offline,
389
+ settings,
390
+ site,
391
+ state,
392
+ })
374
393
 
375
394
  const liveTunnelUrl = await handleLiveTunnel({ options, site, api, settings })
376
395
  url = liveTunnelUrl || url
@@ -474,7 +493,6 @@ const dev = async (options, command) => {
474
493
  */
475
494
  const createDevCommand = (program) => {
476
495
  createDevExecCommand(program)
477
- createDevTraceCommand(program)
478
496
 
479
497
  return program
480
498
  .command('dev')
@@ -490,23 +508,18 @@ const createDevCommand = (program) => {
490
508
  .option('-o ,--offline', 'disables any features that require network access')
491
509
  .option('-l, --live', 'start a public live session', false)
492
510
  .option('--functionsPort <port>', 'port of functions server', (value) => Number.parseInt(value))
493
- .addOption(
494
- new Option('--staticServerPort <port>', 'port of the static app server used when no framework is detected')
495
- .argParser((value) => Number.parseInt(value))
496
- .hideHelp(),
497
- )
498
- .addOption(new Option('-e ,--edgeHandlers', 'activates the Edge Handlers runtime').hideHelp())
499
511
  .addOption(
500
512
  new Option(
501
- '-t ,--trafficMesh',
502
- '(DEPRECATED: use --edgeHandlers or -e instead) uses Traffic Mesh for proxying requests',
503
- ).hideHelp(),
513
+ '--geo <mode>',
514
+ 'force geolocation data to be updated, use cached data from the last 24h if found, or use a mock location',
515
+ )
516
+ .choices(['cache', 'mock', 'update'])
517
+ .default('cache'),
504
518
  )
505
519
  .addOption(
506
- new Option(
507
- '-g ,--locationDb <path>',
508
- 'specify the path to a local GeoIP location database in MMDB format',
509
- ).hideHelp(),
520
+ new Option('--staticServerPort <port>', 'port of the static app server used when no framework is detected')
521
+ .argParser((value) => Number.parseInt(value))
522
+ .hideHelp(),
510
523
  )
511
524
  .addOption(new Option('--graph', 'enable Netlify Graph support').hideHelp())
512
525
  .addExamples([
@@ -36,6 +36,7 @@ const { createLmCommand } = require('./lm')
36
36
  const { createLoginCommand } = require('./login')
37
37
  const { createLogoutCommand } = require('./logout')
38
38
  const { createOpenCommand } = require('./open')
39
+ const { createRecipesCommand, createRecipesListCommand } = require('./recipes')
39
40
  const { createSitesCommand } = require('./sites')
40
41
  const { createStatusCommand } = require('./status')
41
42
  const { createSwitchCommand } = require('./switch')
@@ -171,6 +172,8 @@ const createMainCommand = () => {
171
172
  createDevCommand(program)
172
173
  createEnvCommand(program)
173
174
  createFunctionsCommand(program)
175
+ createRecipesCommand(program)
176
+ createRecipesListCommand(program)
174
177
  createGraphCommand(program)
175
178
  createInitCommand(program)
176
179
  createLinkCommand(program)
@@ -0,0 +1,33 @@
1
+ const { promises: fs } = require('fs')
2
+ const { join, resolve } = require('path')
3
+
4
+ const getRecipe = (name) => {
5
+ const recipePath = resolve(__dirname, '../../recipes', name)
6
+
7
+ // eslint-disable-next-line import/no-dynamic-require, n/global-require
8
+ const recipe = require(recipePath)
9
+
10
+ return recipe
11
+ }
12
+
13
+ const listRecipes = async () => {
14
+ const recipesPath = resolve(__dirname, '../../recipes')
15
+ const recipeNames = await fs.readdir(recipesPath)
16
+ const recipes = await Promise.all(
17
+ recipeNames.map((name) => {
18
+ const recipePath = join(recipesPath, name)
19
+
20
+ // eslint-disable-next-line import/no-dynamic-require, n/global-require
21
+ const recipe = require(recipePath)
22
+
23
+ return {
24
+ ...recipe,
25
+ name,
26
+ }
27
+ }),
28
+ )
29
+
30
+ return recipes
31
+ }
32
+
33
+ module.exports = { getRecipe, listRecipes }
@@ -0,0 +1,8 @@
1
+ const { createRecipesCommand, runRecipe } = require('./recipes')
2
+ const { createRecipesListCommand } = require('./recipes-list')
3
+
4
+ module.exports = {
5
+ createRecipesCommand,
6
+ createRecipesListCommand,
7
+ runRecipe,
8
+ }
@@ -0,0 +1,34 @@
1
+ // @ts-check
2
+ const AsciiTable = require('ascii-table')
3
+
4
+ const { listRecipes } = require('./common')
5
+
6
+ /**
7
+ * The recipes:list command
8
+ */
9
+ const recipesListCommand = async () => {
10
+ const recipes = await listRecipes()
11
+ const table = new AsciiTable(`Usage: netlify recipes <name>`)
12
+
13
+ table.setHeading('Name', 'Description')
14
+
15
+ recipes.forEach(({ description, name }) => {
16
+ table.addRow(name, description)
17
+ })
18
+
19
+ console.log(table.toString())
20
+ }
21
+
22
+ /**
23
+ * Creates the `netlify recipes:list` command
24
+ * @param {import('../base-command').BaseCommand} program
25
+ * @returns
26
+ */
27
+ const createRecipesListCommand = (program) =>
28
+ program
29
+ .command('recipes:list')
30
+ .description(`(Beta) List the recipes available to create and modify files in a project`)
31
+ .addExamples(['netlify recipes:list'])
32
+ .action(recipesListCommand)
33
+
34
+ module.exports = { createRecipesListCommand }
@@ -0,0 +1,85 @@
1
+ // @ts-check
2
+ const { basename } = require('path')
3
+
4
+ const inquirer = require('inquirer')
5
+ const { findBestMatch } = require('string-similarity')
6
+
7
+ const utils = require('../../utils/command-helpers')
8
+
9
+ const { getRecipe, listRecipes } = require('./common')
10
+
11
+ const SUGGESTION_TIMEOUT = 1e4
12
+
13
+ /**
14
+ * The recipes command
15
+ * @param {string} recipeName
16
+ * @param {import('commander').OptionValues} options
17
+ * @param {import('../base-command').BaseCommand} command
18
+ */
19
+ const recipesCommand = async (recipeName, options, command) => {
20
+ const { config, repositoryRoot } = command.netlify
21
+ const sanitizedRecipeName = basename(recipeName || '').toLowerCase()
22
+
23
+ if (sanitizedRecipeName.length === 0) {
24
+ return command.help()
25
+ }
26
+
27
+ try {
28
+ return await runRecipe({ config, recipeName: sanitizedRecipeName, repositoryRoot })
29
+ } catch (error) {
30
+ if (error.code !== 'MODULE_NOT_FOUND') {
31
+ throw error
32
+ }
33
+
34
+ utils.log(`${utils.NETLIFYDEVERR} ${utils.chalk.yellow(recipeName)} is not a valid recipe name.`)
35
+
36
+ const recipes = await listRecipes()
37
+ const recipeNames = recipes.map(({ name }) => name)
38
+ const {
39
+ bestMatch: { target: suggestion },
40
+ } = findBestMatch(recipeName, recipeNames)
41
+ const applySuggestion = await new Promise((resolve) => {
42
+ const prompt = inquirer.prompt({
43
+ type: 'confirm',
44
+ name: 'suggestion',
45
+ message: `Did you mean ${utils.chalk.blue(suggestion)}`,
46
+ default: false,
47
+ })
48
+
49
+ setTimeout(() => {
50
+ // @ts-ignore
51
+ prompt.ui.close()
52
+ resolve(false)
53
+ }, SUGGESTION_TIMEOUT)
54
+
55
+ // eslint-disable-next-line promise/catch-or-return
56
+ prompt.then((value) => resolve(value.suggestion))
57
+ })
58
+
59
+ if (applySuggestion) {
60
+ return recipesCommand(suggestion, options, command)
61
+ }
62
+ }
63
+ }
64
+
65
+ const runRecipe = ({ config, recipeName, repositoryRoot }) => {
66
+ const recipe = getRecipe(recipeName)
67
+
68
+ return recipe.run({ config, repositoryRoot })
69
+ }
70
+
71
+ /**
72
+ * Creates the `netlify recipes` command
73
+ * @param {import('../base-command').BaseCommand} program
74
+ * @returns
75
+ */
76
+ const createRecipesCommand = (program) =>
77
+ program
78
+ .command('recipes')
79
+ .argument('[name]', 'name of the recipe')
80
+ .description(`(Beta) Create and modify files in a project using pre-defined recipes`)
81
+ .option('-n, --name <name>', 'recipe name to use')
82
+ .addExamples(['netlify recipes my-recipe', 'netlify recipes --name my-recipe'])
83
+ .action(recipesCommand)
84
+
85
+ module.exports = { createRecipesCommand, runRecipe }
package/src/lib/api.js CHANGED
@@ -1,76 +1,5 @@
1
- const fetch = require('node-fetch')
2
-
3
1
  const { warn } = require('../utils/command-helpers')
4
2
 
5
- const getHeaders = ({ token }) => ({
6
- 'Content-Type': 'application/json',
7
- Authorization: `Bearer ${token}`,
8
- })
9
-
10
- const getErrorMessage = async ({ response }) => {
11
- const contentType = response.headers.get('content-type')
12
- if (contentType && contentType.includes('application/json')) {
13
- const json = await response.json()
14
- return json.message
15
- }
16
- const text = await response.text()
17
- return text
18
- }
19
-
20
- const checkResponse = async ({ response }) => {
21
- if (!response.ok) {
22
- const message = await getErrorMessage({ response }).catch(() => {})
23
- const errorPostfix = message ? ` and message '${message}'` : ''
24
- throw new Error(`Request failed with status '${response.status}'${errorPostfix}`)
25
- }
26
- }
27
-
28
- const getApiUrl = ({ api }) => `${api.scheme}://${api.host}${api.pathPrefix}`
29
-
30
- const apiPost = async ({ api, data, path }) => {
31
- const apiUrl = getApiUrl({ api })
32
- const response = await fetch(`${apiUrl}/${path}`, {
33
- method: 'POST',
34
- body: JSON.stringify(data),
35
- headers: getHeaders({ token: api.accessToken }),
36
- agent: api.agent,
37
- })
38
-
39
- await checkResponse({ response })
40
-
41
- return response
42
- }
43
-
44
- const uploadEdgeHandlers = async ({ api, bundleBuffer, deployId, manifest }) => {
45
- // TODO: use open-api spec via api when it is exposed
46
- const response = await apiPost({ api, path: `deploys/${deployId}/edge_handlers`, data: manifest })
47
- const { error, exists, upload_url: uploadUrl } = await response.json()
48
- if (error) {
49
- throw new Error(error)
50
- }
51
-
52
- if (exists) {
53
- return false
54
- }
55
-
56
- if (!uploadUrl) {
57
- throw new Error('Missing upload URL')
58
- }
59
-
60
- const putResponse = await fetch(uploadUrl, {
61
- method: 'PUT',
62
- body: bundleBuffer,
63
- headers: {
64
- 'Content-Type': 'application/javascript',
65
- },
66
- agent: api.agent,
67
- })
68
-
69
- await checkResponse({ response: putResponse })
70
-
71
- return true
72
- }
73
-
74
3
  const cancelDeploy = async ({ api, deployId }) => {
75
4
  try {
76
5
  await api.cancelSiteDeploy({ deploy_id: deployId })
@@ -92,4 +21,4 @@ const listSites = async ({ api, options }) => {
92
21
  return sites
93
22
  }
94
23
 
95
- module.exports = { uploadEdgeHandlers, cancelDeploy, listSites }
24
+ module.exports = { cancelDeploy, listSites }
@@ -0,0 +1,21 @@
1
+ const DEFAULT_SRC_DIR = 'netlify/edge-functions'
2
+ const DIST_IMPORT_MAP_PATH = 'edge-functions-import-map.json'
3
+ const INTERNAL_EDGE_FUNCTIONS_FOLDER = 'edge-functions'
4
+ const EDGE_FUNCTIONS_FOLDER = 'edge-functions-dist'
5
+ const PUBLIC_URL_PATH = '.netlify/internal/edge-functions'
6
+
7
+ // 1 second
8
+ const SERVER_POLL_INTERNAL = 1e3
9
+
10
+ // 10 seconds
11
+ const SERVER_POLL_TIMEOUT = 1e4
12
+
13
+ module.exports = {
14
+ DEFAULT_SRC_DIR,
15
+ DIST_IMPORT_MAP_PATH,
16
+ INTERNAL_EDGE_FUNCTIONS_FOLDER,
17
+ EDGE_FUNCTIONS_FOLDER,
18
+ PUBLIC_URL_PATH,
19
+ SERVER_POLL_INTERNAL,
20
+ SERVER_POLL_TIMEOUT,
21
+ }
@@ -0,0 +1,41 @@
1
+ // @ts-check
2
+ const { stat } = require('fs').promises
3
+ const path = require('path')
4
+
5
+ const { getPathInProject } = require('../settings')
6
+
7
+ const { EDGE_FUNCTIONS_FOLDER, PUBLIC_URL_PATH } = require('./consts')
8
+
9
+ const distPath = getPathInProject([EDGE_FUNCTIONS_FOLDER])
10
+
11
+ const deployFileNormalizer = (file) => {
12
+ const isEdgeFunction = file.root === distPath
13
+ const normalizedPath = isEdgeFunction ? path.join(PUBLIC_URL_PATH, file.normalizedPath) : file.normalizedPath
14
+
15
+ return {
16
+ ...file,
17
+ normalizedPath,
18
+ }
19
+ }
20
+
21
+ const getDistPathIfExists = async () => {
22
+ try {
23
+ const stats = await stat(distPath)
24
+
25
+ if (!stats.isDirectory()) {
26
+ throw new Error(`Path ${distPath} must be a directory.`)
27
+ }
28
+
29
+ return distPath
30
+ } catch {
31
+ // no-op
32
+ }
33
+ }
34
+
35
+ const isEdgeFunctionFile = (filePath) => filePath.startsWith(`${PUBLIC_URL_PATH}${path.sep}`)
36
+
37
+ module.exports = {
38
+ deployFileNormalizer,
39
+ getDistPathIfExists,
40
+ isEdgeFunctionFile,
41
+ }
@@ -0,0 +1,41 @@
1
+ const { env } = require('process')
2
+
3
+ const inquirer = require('inquirer')
4
+
5
+ const { runRecipe } = require('../../commands/recipes')
6
+
7
+ const STATE_PROMPT_PROPERTY = 'promptVSCodeSettings'
8
+
9
+ const promptEditorHelper = async ({ NETLIFYDEVLOG, chalk, config, log, repositoryRoot, state }) => {
10
+ const isVSCode = env.TERM_PROGRAM === 'vscode'
11
+ const hasShownPrompt = Boolean(state.get(STATE_PROMPT_PROPERTY))
12
+ const hasEdgeFunctions = Boolean(config.edge_functions && config.edge_functions.length !== 0)
13
+
14
+ if (!isVSCode || hasShownPrompt || !hasEdgeFunctions) {
15
+ return
16
+ }
17
+
18
+ state.set(STATE_PROMPT_PROPERTY, true)
19
+
20
+ const message = 'Would you like to configure VS Code to use Edge Functions?'
21
+ const { confirm } = await inquirer.prompt({
22
+ type: 'confirm',
23
+ name: 'confirm',
24
+ message,
25
+ default: true,
26
+ })
27
+
28
+ if (!confirm) {
29
+ log(
30
+ `${NETLIFYDEVLOG} You can start this configuration manually by running ${chalk.magenta.bold(
31
+ 'netlify recipes vscode',
32
+ )}.`,
33
+ )
34
+
35
+ return
36
+ }
37
+
38
+ await runRecipe({ config, recipeName: 'vscode', repositoryRoot })
39
+ }
40
+
41
+ module.exports = { promptEditorHelper }
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ Functions: 'x-deno-functions',
3
+ Geo: 'x-nf-geo',
4
+ PassHost: 'X-NF-Pass-Host',
5
+ Passthrough: 'x-deno-pass',
6
+ RequestID: 'X-NF-Request-ID',
7
+ }
@@ -0,0 +1,7 @@
1
+ // @ts-check
2
+ const constants = require('./consts')
3
+ const deploy = require('./deploy')
4
+ const editorHelper = require('./editor-helper')
5
+ const proxy = require('./proxy')
6
+
7
+ module.exports = { ...constants, ...deploy, ...editorHelper, ...proxy }