netlify-cli 17.10.1 → 17.11.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 (39) hide show
  1. package/npm-shrinkwrap.json +956 -203
  2. package/package.json +2 -3
  3. package/src/commands/base-command.js +47 -102
  4. package/src/commands/deploy/deploy.js +5 -8
  5. package/src/commands/dev/dev.js +0 -1
  6. package/src/commands/functions/functions-create.js +0 -4
  7. package/src/commands/link/link.js +0 -5
  8. package/src/commands/lm/lm-setup.js +0 -2
  9. package/src/commands/main.js +0 -2
  10. package/src/commands/serve/serve.js +3 -1
  11. package/src/commands/sites/sites-create-template.js +0 -3
  12. package/src/lib/blobs/blobs.js +1 -1
  13. package/src/lib/edge-functions/proxy.js +2 -21
  14. package/src/lib/edge-functions/registry.js +42 -10
  15. package/src/lib/exec-fetcher.js +0 -2
  16. package/src/lib/functions/local-proxy.js +1 -3
  17. package/src/lib/functions/netlify-function.js +3 -3
  18. package/src/lib/functions/registry.js +17 -27
  19. package/src/lib/functions/runtimes/go/index.js +0 -3
  20. package/src/lib/functions/runtimes/index.js +0 -34
  21. package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +10 -10
  22. package/src/lib/functions/runtimes/rust/index.js +0 -2
  23. package/src/lib/functions/server.js +23 -13
  24. package/src/utils/banner.js +2 -3
  25. package/src/utils/build-info.js +22 -39
  26. package/src/utils/command-helpers.js +3 -11
  27. package/src/utils/deploy/deploy-site.js +0 -6
  28. package/src/utils/detect-server-settings.js +15 -101
  29. package/src/utils/execa.js +1 -4
  30. package/src/utils/feature-flags.js +1 -7
  31. package/src/utils/framework-server.js +6 -10
  32. package/src/utils/functions/functions.js +2 -9
  33. package/src/utils/init/utils.js +17 -32
  34. package/src/utils/live-tunnel.js +0 -2
  35. package/src/utils/lm/requirements.js +0 -5
  36. package/src/utils/sites/utils.js +0 -1
  37. package/src/utils/telemetry/report-error.js +0 -2
  38. package/src/utils/telemetry/telemetry.js +1 -21
  39. package/src/lib/edge-functions/internal.js +0 -46
@@ -1,9 +1,14 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { join } from 'path';
1
3
  import { fileURLToPath } from 'url';
2
4
  import { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, nonNullable, chalk, log, warn, watchDebounced, isNodeError, } from '../../utils/command-helpers.js';
5
+ import { getPathInProject } from '../settings.js';
6
+ import { INTERNAL_EDGE_FUNCTIONS_FOLDER } from './consts.js';
3
7
  const featureFlags = { edge_functions_correct_order: true };
4
8
  export class EdgeFunctionsRegistry {
5
- constructor({ bundler, config, configPath, directories, env, getUpdatedConfig, internalDirectories, internalFunctions, projectDir, runIsolate, servePath, }) {
9
+ constructor({ bundler, config, configPath, directories, env, getUpdatedConfig, importMapFromTOML, projectDir, runIsolate, servePath, }) {
6
10
  this.buildError = null;
11
+ this.declarationsFromDeployConfig = [];
7
12
  this.dependencyPaths = new Map();
8
13
  this.directoryWatchers = new Map();
9
14
  this.functionPaths = new Map();
@@ -14,11 +19,11 @@ export class EdgeFunctionsRegistry {
14
19
  this.bundler = bundler;
15
20
  this.configPath = configPath;
16
21
  this.directories = directories;
17
- this.internalDirectories = internalDirectories;
18
22
  this.getUpdatedConfig = getUpdatedConfig;
19
23
  this.runIsolate = runIsolate;
20
24
  this.servePath = servePath;
21
- this.declarationsFromDeployConfig = internalFunctions;
25
+ this.projectDir = projectDir;
26
+ this.importMapFromTOML = importMapFromTOML;
22
27
  this.declarationsFromTOML = EdgeFunctionsRegistry.getDeclarationsFromTOML(config);
23
28
  this.env = EdgeFunctionsRegistry.getEnvironmentVariables(env);
24
29
  this.buildError = null;
@@ -28,7 +33,7 @@ export class EdgeFunctionsRegistry {
28
33
  this.userFunctions = [];
29
34
  this.internalFunctions = [];
30
35
  this.initialScan = this.doInitialScan();
31
- this.setupWatchers(projectDir);
36
+ this.setupWatchers();
32
37
  }
33
38
  async doInitialScan() {
34
39
  await this.scanForFunctions();
@@ -306,13 +311,40 @@ export class EdgeFunctionsRegistry {
306
311
  }
307
312
  const { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success } = await this.runIsolate(this.functions, this.env, {
308
313
  getFunctionsConfig: true,
314
+ importMapPaths: [this.importMapFromTOML, this.importMapFromDeployConfig].filter(nonNullable),
309
315
  });
310
316
  return { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success };
311
317
  }
318
+ get internalDirectory() {
319
+ return join(this.projectDir, getPathInProject([INTERNAL_EDGE_FUNCTIONS_FOLDER]));
320
+ }
321
+ async readDeployConfig() {
322
+ const manifestPath = join(this.internalDirectory, 'manifest.json');
323
+ try {
324
+ const contents = await readFile(manifestPath, 'utf8');
325
+ const manifest = JSON.parse(contents);
326
+ return manifest;
327
+ }
328
+ catch { }
329
+ }
330
+ async scanForDeployConfig() {
331
+ const deployConfig = await this.readDeployConfig();
332
+ if (!deployConfig) {
333
+ return;
334
+ }
335
+ if (deployConfig.version !== 1) {
336
+ throw new Error('Unsupported manifest format');
337
+ }
338
+ this.declarationsFromDeployConfig = deployConfig.functions;
339
+ this.importMapFromDeployConfig = deployConfig.import_map
340
+ ? join(this.internalDirectory, deployConfig.import_map)
341
+ : undefined;
342
+ }
312
343
  async scanForFunctions() {
313
344
  const [internalFunctions, userFunctions] = await Promise.all([
314
- this.bundler.find(this.internalDirectories),
345
+ this.bundler.find([this.internalDirectory]),
315
346
  this.bundler.find(this.directories),
347
+ this.scanForDeployConfig(),
316
348
  ]);
317
349
  const functions = [...internalFunctions, ...userFunctions];
318
350
  const newFunctions = functions.filter((func) => {
@@ -327,7 +359,7 @@ export class EdgeFunctionsRegistry {
327
359
  this.userFunctions = userFunctions;
328
360
  return { all: functions, new: newFunctions, deleted: deletedFunctions };
329
361
  }
330
- async setupWatchers(projectDir) {
362
+ async setupWatchers() {
331
363
  if (!this.configPath) {
332
364
  return;
333
365
  }
@@ -344,16 +376,16 @@ export class EdgeFunctionsRegistry {
344
376
  // directories, they might be importing files that are located in
345
377
  // parent directories. So we watch the entire project directory for
346
378
  // changes.
347
- await this.setupWatcherForDirectory(projectDir);
379
+ await this.setupWatcherForDirectory();
348
380
  }
349
- async setupWatcherForDirectory(directory) {
381
+ async setupWatcherForDirectory() {
350
382
  const ignored = [`${this.servePath}/**`];
351
- const watcher = await watchDebounced(directory, {
383
+ const watcher = await watchDebounced(this.projectDir, {
352
384
  ignored,
353
385
  onAdd: () => this.checkForAddedOrDeletedFunctions(),
354
386
  onChange: (paths) => this.handleFileChange(paths),
355
387
  onUnlink: () => this.checkForAddedOrDeletedFunctions(),
356
388
  });
357
- this.directoryWatchers.set(directory, watcher);
389
+ this.directoryWatchers.set(this.projectDir, watcher);
358
390
  }
359
391
  }
@@ -4,7 +4,6 @@ import { fetchLatest, fetchVersion, newerVersion, updateAvailable } from 'gh-rel
4
4
  // @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'isex... Remove this comment to see the full error message
5
5
  import isExe from 'isexe';
6
6
  import { NETLIFYDEVWARN, error, getTerminalLink, log } from '../utils/command-helpers.js';
7
- // @ts-expect-error TS(7034) FIXME: Variable 'execa' implicitly has type 'any' in some... Remove this comment to see the full error message
8
7
  import execa from '../utils/execa.js';
9
8
  const isWindows = () => process.platform === 'win32';
10
9
  // @ts-expect-error TS(7031) FIXME: Binding element 'packageName' implicitly has an 'a... Remove this comment to see the full error message
@@ -47,7 +46,6 @@ pattern, }) => {
47
46
  if (!exists) {
48
47
  return true;
49
48
  }
50
- // @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
51
49
  const { stdout } = await execa(execPath, execArgs);
52
50
  if (!stdout) {
53
51
  return false;
@@ -1,7 +1,6 @@
1
1
  import { stdout } from 'process';
2
2
  // @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module '@net... Remove this comment to see the full error message
3
3
  import { getBinaryPath as getFunctionsProxyPath } from '@netlify/local-functions-proxy';
4
- // @ts-expect-error TS(7034) FIXME: Variable 'execa' implicitly has type 'any' in some... Remove this comment to see the full error message
5
4
  import execa from '../../utils/execa.js';
6
5
  // @ts-expect-error TS(7031) FIXME: Binding element 'binaryPath' implicitly has an 'an... Remove this comment to see the full error message
7
6
  export const runFunctionsProxy = ({ binaryPath, context, directory, event, name, timeout }) => {
@@ -34,8 +33,7 @@ export const runFunctionsProxy = ({ binaryPath, context, directory, event, name,
34
33
  '--timeout',
35
34
  `${timeout}s`,
36
35
  ];
37
- // @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
38
36
  const proxyProcess = execa(functionsProxyPath, parameters);
39
- proxyProcess.stderr.pipe(stdout);
37
+ proxyProcess.stderr?.pipe(stdout);
40
38
  return proxyProcess;
41
39
  };
@@ -51,7 +51,6 @@ export default class NetlifyFunction {
51
51
  this.name = name;
52
52
  this.displayName = displayName ?? name;
53
53
  this.projectRoot = projectRoot;
54
- // @ts-expect-error TS(2339) FIXME: Property 'runtime' does not exist on type 'Netlify... Remove this comment to see the full error message
55
54
  this.runtime = runtime;
56
55
  this.timeoutBackground = timeoutBackground;
57
56
  this.timeoutSynchronous = timeoutSynchronous;
@@ -142,7 +141,9 @@ export default class NetlifyFunction {
142
141
  return { includedFiles, srcFilesDiff };
143
142
  }
144
143
  catch (error) {
145
- this.buildError = error;
144
+ if (error instanceof Error) {
145
+ this.buildError = error;
146
+ }
146
147
  return { error };
147
148
  }
148
149
  }
@@ -164,7 +165,6 @@ export default class NetlifyFunction {
164
165
  async invoke(event = {}, context = {}) {
165
166
  await this.buildQueue;
166
167
  if (this.buildError) {
167
- // @ts-expect-error TS(2339) FIXME: Property 'buildError' does not exist on type 'Netl... Remove this comment to see the full error message
168
168
  return { result: null, error: { errorMessage: this.buildError.message } };
169
169
  }
170
170
  const timeout = this.isBackground ? this.timeoutBackground : this.timeoutSynchronous;
@@ -13,6 +13,7 @@ import runtimes from './runtimes/index.js';
13
13
  export const DEFAULT_FUNCTION_URL_EXPRESSION = /^\/.netlify\/(functions|builders)\/([^/]+).*/;
14
14
  const TYPES_PACKAGE = '@netlify/functions';
15
15
  const ZIP_EXTENSION = '.zip';
16
+ const isInternalFunction = (func) => func.mainFile.includes(getPathInProject([INTERNAL_FUNCTIONS_FOLDER]));
16
17
  /**
17
18
  * @typedef {"buildError" | "extracted" | "loaded" | "missing-types-package" | "reloaded" | "reloading" | "removed"} FunctionEvent
18
19
  */
@@ -149,7 +150,6 @@ export class FunctionsRegistry {
149
150
  ? `rename the function file to ${chalk.underline(newFilename)}. Refer to https://ntl.fyi/functions-runtime for more information`
150
151
  : `refer to https://ntl.fyi/functions-runtime`;
151
152
  const warning = `The function is using the legacy CommonJS format. To start using ES modules, ${action}.`;
152
- // @ts-expect-error TS(2322) FIXME: Type 'string' is not assignable to type 'never'.
153
153
  FunctionsRegistry.logEvent(event, { func, warnings: [warning] });
154
154
  }
155
155
  else {
@@ -230,14 +230,7 @@ export class FunctionsRegistry {
230
230
  }
231
231
  /**
232
232
  * Logs an event associated with functions.
233
- *
234
- * @param {FunctionEvent} event
235
- * @param {object} data
236
- * @param {NetlifyFunction} [data.func]
237
- * @param {string[]} [data.warnings]
238
- * @returns
239
233
  */
240
- // @ts-expect-error TS(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
241
234
  static logEvent(event, { func, warnings = [] }) {
242
235
  let warningsText = '';
243
236
  if (warnings.length !== 0) {
@@ -280,18 +273,13 @@ export class FunctionsRegistry {
280
273
  }
281
274
  /**
282
275
  * Adds a function to the registry
283
- *
284
- * @param {string} name
285
- * @param {NetlifyFunction} funcBeforeHook
286
- * @param {boolean} [isReload]
287
- * @returns
288
276
  */
289
- // @ts-expect-error TS(7006) FIXME: Parameter 'name' implicitly has an 'any' type.
290
277
  async registerFunction(name, funcBeforeHook, isReload = false) {
291
278
  const { runtime } = funcBeforeHook;
292
279
  // The `onRegister` hook allows runtimes to modify the function before it's
293
280
  // registered, or to prevent it from being registered altogether if the
294
281
  // hook returns `null`.
282
+ // @ts-expect-error FIXME
295
283
  const func = typeof runtime.onRegister === 'function' ? runtime.onRegister(funcBeforeHook) : funcBeforeHook;
296
284
  if (func === null) {
297
285
  return;
@@ -339,31 +327,24 @@ export class FunctionsRegistry {
339
327
  /**
340
328
  * A proxy to zip-it-and-ship-it's `listFunctions` method. It exists just so
341
329
  * that we can mock it in tests.
342
- * @param {Parameters<listFunctions>} args
343
- * @returns
344
330
  */
345
- // @ts-expect-error TS(7019) FIXME: Rest parameter 'args' implicitly has an 'any[]' ty... Remove this comment to see the full error message
346
331
  // eslint-disable-next-line class-methods-use-this
347
332
  async listFunctions(...args) {
348
- // @ts-expect-error TS(2556) FIXME: A spread argument must either have a tuple type or... Remove this comment to see the full error message
349
333
  return await listFunctions(...args);
350
334
  }
351
335
  /**
352
336
  * Takes a list of directories and scans for functions. It keeps tracks of
353
337
  * any functions in those directories that we've previously seen, and takes
354
338
  * care of registering and unregistering functions as they come and go.
355
- *
356
- * @param {string[]} relativeDirs
357
339
  */
358
- // @ts-expect-error TS(7006) FIXME: Parameter 'relativeDirs' implicitly has an 'any' t... Remove this comment to see the full error message
359
340
  async scan(relativeDirs) {
360
- // @ts-expect-error TS(7006) FIXME: Parameter 'dir' implicitly has an 'any' type.
361
- const directories = relativeDirs.filter(Boolean).map((dir) => (isAbsolute(dir) ? dir : join(this.projectRoot, dir)));
341
+ const directories = relativeDirs
342
+ .filter((dir) => Boolean(dir))
343
+ .map((dir) => (isAbsolute(dir) ? dir : join(this.projectRoot, dir)));
362
344
  // check after filtering to filter out [undefined] for example
363
345
  if (directories.length === 0) {
364
346
  return;
365
347
  }
366
- // @ts-expect-error TS(7006) FIXME: Parameter 'path' implicitly has an 'any' type.
367
348
  await Promise.all(directories.map((path) => FunctionsRegistry.prepareDirectoryScan(path)));
368
349
  const functions = await this.listFunctions(directories, {
369
350
  featureFlags: {
@@ -373,10 +354,18 @@ export class FunctionsRegistry {
373
354
  // @ts-expect-error TS(2339) FIXME: Property 'config' does not exist on type 'Function... Remove this comment to see the full error message
374
355
  config: this.config.functions,
375
356
  });
357
+ // user-defined functions take precedence over internal functions,
358
+ // so we want to ignore any internal functions where there's a user-defined one with the same name
359
+ const ignoredFunctions = new Set(functions
360
+ .filter((func) => isInternalFunction(func) &&
361
+ this.functions.has(func.name) &&
362
+ !isInternalFunction(this.functions.get(func.name)))
363
+ .map((func) => func.name));
376
364
  // Before registering any functions, we look for any functions that were on
377
365
  // the previous list but are missing from the new one. We unregister them.
378
366
  const deletedFunctions = [...this.functions.values()].filter((oldFunc) => {
379
- const isFound = functions.some((newFunc) => newFunc.name === oldFunc.name && newFunc.mainFile === oldFunc.mainFile);
367
+ const isFound = functions.some((newFunc) => ignoredFunctions.has(newFunc.name) ||
368
+ (newFunc.name === oldFunc.name && newFunc.mainFile === oldFunc.mainFile));
380
369
  return !isFound;
381
370
  });
382
371
  await Promise.all(deletedFunctions.map((func) => this.unregisterFunction(func)));
@@ -386,6 +375,9 @@ export class FunctionsRegistry {
386
375
  // where the last ones precede the previous ones. This is why
387
376
  // we reverse the array so we get the right functions precedence in the CLI.
388
377
  functions.reverse().map(async ({ displayName, mainFile, name, runtime: runtimeName }) => {
378
+ if (ignoredFunctions.has(name)) {
379
+ return;
380
+ }
389
381
  const runtime = runtimes[runtimeName];
390
382
  // If there is no matching runtime, it means this function is not yet
391
383
  // supported in Netlify Dev.
@@ -400,7 +392,6 @@ export class FunctionsRegistry {
400
392
  blobsContext: this.blobsContext,
401
393
  // @ts-expect-error TS(2339) FIXME: Property 'config' does not exist on type 'Function... Remove this comment to see the full error message
402
394
  config: this.config,
403
- // @ts-expect-error TS(7006) FIXME: Parameter 'directory' implicitly has an 'any' type... Remove this comment to see the full error message
404
395
  directory: directories.find((directory) => mainFile.startsWith(directory)),
405
396
  mainFile,
406
397
  name,
@@ -430,7 +421,6 @@ export class FunctionsRegistry {
430
421
  }
431
422
  FunctionsRegistry.logEvent('removed', { func });
432
423
  });
433
- // @ts-expect-error TS(7006) FIXME: Parameter 'path' implicitly has an 'any' type.
434
424
  await Promise.all(directories.map((path) => this.setupDirectoryWatcher(path)));
435
425
  }
436
426
  /**
@@ -1,7 +1,6 @@
1
1
  import { dirname, extname } from 'path';
2
2
  import { platform } from 'process';
3
3
  import { temporaryFile } from 'tempy';
4
- // @ts-expect-error TS(7034) FIXME: Variable 'execa' implicitly has type 'any' in some... Remove this comment to see the full error message
5
4
  import execa from '../../../../utils/execa.js';
6
5
  import { runFunctionsProxy } from '../../local-proxy.js';
7
6
  const isWindows = platform === 'win32';
@@ -9,7 +8,6 @@ export const name = 'go';
9
8
  // @ts-expect-error TS(7031) FIXME: Binding element 'binaryPath' implicitly has an 'an... Remove this comment to see the full error message
10
9
  const build = async ({ binaryPath, functionDirectory }) => {
11
10
  try {
12
- // @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
13
11
  await execa('go', ['build', '-o', binaryPath], { cwd: functionDirectory });
14
12
  return { binaryPath, srcFiles: [functionDirectory] };
15
13
  }
@@ -24,7 +22,6 @@ const build = async ({ binaryPath, functionDirectory }) => {
24
22
  // @ts-expect-error TS(7031) FIXME: Binding element 'cwd' implicitly has an 'any' type... Remove this comment to see the full error message
25
23
  const checkGoInstallation = async ({ cwd }) => {
26
24
  try {
27
- // @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
28
25
  await execa('go', ['version'], { cwd });
29
26
  return true;
30
27
  }
@@ -1,40 +1,6 @@
1
1
  import * as go from './go/index.js';
2
2
  import * as js from './js/index.js';
3
3
  import * as rust from './rust/index.js';
4
- /* eslint-enable import/no-namespace */
5
- /**
6
- * @callback BuildFunction
7
- * @param {object} func
8
- * @returns {Promise<{srcFiles: string[], buildPath?: string}>}
9
- */
10
- /**
11
- * @callback GetBuildFunction
12
- * @param {{ config: object, context: object, errorExit: function, func: object, functionsDirectory: string, projectRoot: string }} params
13
- * @returns {Promise<BuildFunction>}
14
- */
15
- /**
16
- * @callback InvokeFunction
17
- * @param {{ context: object, event: object, func: object, timeout: number }} params
18
- * @returns {Promise<{ body: object, statusCode: number }>}
19
- */
20
- /**
21
- * @callback OnDirectoryScanFunction
22
- * @param {{ directory: string }} params
23
- * @returns {Promise<undefined>}
24
- */
25
- /**
26
- * @callback OnRegisterFunction
27
- * @param {object} func
28
- * @returns {object|null}
29
- */
30
- /**
31
- * @typedef {object} Runtime
32
- * @property {GetBuildFunction} getBuildFunction
33
- * @property {InvokeFunction} invokeFunction
34
- * @property {OnDirectoryScanFunction} [onDirectoryScan]
35
- * @property {OnRegisterFunction} [onRegister]
36
- * @property {string} name
37
- */
38
4
  const runtimes = {
39
5
  [go.name]: go,
40
6
  [js.name]: js,
@@ -1,7 +1,6 @@
1
1
  import { readFile } from 'fs/promises';
2
2
  import { resolve } from 'path';
3
- import minimist from 'minimist';
4
- // @ts-expect-error TS(7034) FIXME: Variable 'execa' implicitly has type 'any' in some... Remove this comment to see the full error message
3
+ import { program } from 'commander';
5
4
  import execa from '../../../../../utils/execa.js';
6
5
  import { fileExistsAsync } from '../../../../fs.js';
7
6
  import { memoizedBuild } from '../../../memoized-build.js';
@@ -15,18 +14,19 @@ export const detectNetlifyLambda = async function ({ packageJson } = {}) {
15
14
  const matchingScripts = Object.entries(scripts).filter(([, script]) => script.match(/netlify-lambda\s+build/));
16
15
  for (const [key, script] of matchingScripts) {
17
16
  // E.g. ["netlify-lambda", "build", "functions/folder"]
18
- // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
19
- const match = minimist(script.split(' '), {
20
- // these are all valid options for netlify-lambda
21
- boolean: ['s', 'static'],
22
- string: ['c', 'config', 'p', 'port', 'b', 'babelrc', 't', 'timeout'],
23
- });
17
+ // these are all valid options for netlify-lambda
18
+ program
19
+ .option('-s, --static')
20
+ .option('-c, --config [file]')
21
+ .option('-p, --port [number]')
22
+ .option('-b, --babelrc [file]')
23
+ .option('-t, --timeout [delay]');
24
+ program.parse(script.split(' ') ?? []);
24
25
  // We are not interested in 'netlify-lambda' and 'build' commands
25
- const functionDirectories = match._.slice(2);
26
+ const functionDirectories = program.args.filter((arg) => !['netlify-lambda', 'build'].includes(arg));
26
27
  if (functionDirectories.length === 1) {
27
28
  const srcFiles = [resolve(functionDirectories[0])];
28
29
  const yarnExists = await fileExistsAsync('yarn.lock');
29
- // @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
30
30
  const buildCommand = () => execa(yarnExists ? 'yarn' : 'npm', ['run', key]);
31
31
  return {
32
32
  build: async ({ cache = {} } = {}) => {
@@ -3,7 +3,6 @@ import { dirname, extname, join, resolve } from 'path';
3
3
  import { platform } from 'process';
4
4
  import { findUp } from 'find-up';
5
5
  import toml from 'toml';
6
- // @ts-expect-error TS(7034) FIXME: Variable 'execa' implicitly has type 'any' in some... Remove this comment to see the full error message
7
6
  import execa from '../../../../utils/execa.js';
8
7
  import { SERVE_FUNCTIONS_FOLDER } from '../../../../utils/functions/functions.js';
9
8
  import { getPathInProject } from '../../../settings.js';
@@ -18,7 +17,6 @@ const build = async ({ func }) => {
18
17
  const crateName = await getCrateName(functionDirectory);
19
18
  const binaryName = `${crateName}${isWindows ? '.exe' : ''}`;
20
19
  const binaryPath = join(targetDirectory, 'debug', binaryName);
21
- // @ts-expect-error TS(7005) FIXME: Variable 'execa' implicitly has an 'any' type.
22
20
  await execa('cargo', ['build', '--target-dir', targetDirectory], {
23
21
  cwd: functionDirectory,
24
22
  });
@@ -25,20 +25,31 @@ const buildClientContext = function (headers) {
25
25
  const parts = headers.authorization.split(' ');
26
26
  if (parts.length !== 2 || parts[0] !== 'Bearer')
27
27
  return;
28
+ const identity = {
29
+ url: 'https://netlify-dev-locally-emulated-identity.netlify.com/.netlify/identity',
30
+ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb3VyY2UiOiJuZXRsaWZ5IGRldiIsInRlc3REYXRhIjoiTkVUTElGWV9ERVZfTE9DQUxMWV9FTVVMQVRFRF9JREVOVElUWSJ9.2eSDqUOZAOBsx39FHFePjYj12k0LrxldvGnlvDu3GMI',
31
+ // you can decode this with https://jwt.io/
32
+ // just says
33
+ // {
34
+ // "source": "netlify dev",
35
+ // "testData": "NETLIFY_DEV_LOCALLY_EMULATED_IDENTITY"
36
+ // }
37
+ };
38
+ // This data is available on both the context root and under custom.netlify for retro-compatibility.
39
+ // In the future it will only be available in custom.netlify.
40
+ // @ts-expect-error
41
+ const user = jwtDecode(parts[1]);
42
+ const netlifyContext = JSON.stringify({
43
+ identity: identity,
44
+ user: user,
45
+ });
28
46
  try {
29
47
  return {
30
- identity: {
31
- url: 'https://netlify-dev-locally-emulated-identity.netlify.com/.netlify/identity',
32
- token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb3VyY2UiOiJuZXRsaWZ5IGRldiIsInRlc3REYXRhIjoiTkVUTElGWV9ERVZfTE9DQUxMWV9FTVVMQVRFRF9JREVOVElUWSJ9.2eSDqUOZAOBsx39FHFePjYj12k0LrxldvGnlvDu3GMI',
33
- // you can decode this with https://jwt.io/
34
- // just says
35
- // {
36
- // "source": "netlify dev",
37
- // "testData": "NETLIFY_DEV_LOCALLY_EMULATED_IDENTITY"
38
- // }
48
+ identity: identity,
49
+ user: user,
50
+ custom: {
51
+ netlify: Buffer.from(netlifyContext).toString('base64'),
39
52
  },
40
- // @ts-expect-error
41
- user: jwtDecode(parts[1]),
42
53
  };
43
54
  }
44
55
  catch {
@@ -114,7 +125,7 @@ export const createHandler = function (options) {
114
125
  'client-ip': [remoteAddress],
115
126
  'x-nf-client-connection-ip': [remoteAddress],
116
127
  'x-nf-account-id': [options.accountId],
117
- 'x-nf-site-id': [options?.siteInfo?.id] ?? 'unlinked',
128
+ 'x-nf-site-id': [options?.siteInfo?.id ?? 'unlinked'],
118
129
  [efHeaders.Geo]: Buffer.from(JSON.stringify(geoLocation)).toString('base64'),
119
130
  }).reduce((prev, [key, value]) => ({ ...prev, [key]: Array.isArray(value) ? value : [value] }), {});
120
131
  const rawQuery = new URLSearchParams(requestQuery).toString();
@@ -217,7 +228,6 @@ const getFunctionsServer = (options) => {
217
228
  // @ts-expect-error TS(7006) FIXME: Parameter 'options' implicitly has an 'any' type.
218
229
  export const startFunctionsServer = async (options) => {
219
230
  const { blobsContext, capabilities, command, config, debug, loadDistFunctions, settings, site, siteInfo, siteUrl, timeouts, } = options;
220
- // @ts-expect-error TS(2345) FIXME: Argument of type '{ base: any; }' is not assignabl... Remove this comment to see the full error message
221
231
  const internalFunctionsDir = await getInternalFunctionsDir({ base: site.root });
222
232
  const functionsDirectories = [];
223
233
  let manifest;
@@ -1,8 +1,7 @@
1
1
  import boxen from 'boxen';
2
2
  import { chalk, log, NETLIFYDEVLOG } from './command-helpers.js';
3
- // @ts-expect-error TS(7031) FIXME: Binding element 'url' implicitly has an 'any' type... Remove this comment to see the full error message
4
- export const printBanner = ({ url }) => {
5
- const banner = chalk.bold(`${NETLIFYDEVLOG} Server now ready on ${url}`);
3
+ export const printBanner = (options) => {
4
+ const banner = chalk.bold(`${NETLIFYDEVLOG} Server now ready on ${options.url}`);
6
5
  log(boxen(banner, {
7
6
  padding: 1,
8
7
  margin: 1,
@@ -3,28 +3,19 @@ import inquirer from 'inquirer';
3
3
  import { chalk, log } from './command-helpers.js';
4
4
  /**
5
5
  * Filters the inquirer settings based on the input
6
- * @param {ReturnType<typeof formatSettingsArrForInquirer>} scriptInquirerOptions
7
- * @param {string} input
8
6
  */
9
- // @ts-expect-error TS(7006) FIXME: Parameter 'scriptInquirerOptions' implicitly has a... Remove this comment to see the full error message
10
7
  const filterSettings = function (scriptInquirerOptions, input) {
11
- // @ts-expect-error TS(7006) FIXME: Parameter 'scriptInquirerOption' implicitly has an... Remove this comment to see the full error message
12
8
  const filterOptions = scriptInquirerOptions.map((scriptInquirerOption) => scriptInquirerOption.name);
13
9
  // TODO: remove once https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1394 is fixed
14
10
  // eslint-disable-next-line unicorn/no-array-method-this-argument
15
11
  const filteredSettings = fuzzy.filter(input, filterOptions);
16
12
  const filteredSettingNames = new Set(filteredSettings.map((filteredSetting) => (input ? filteredSetting.string : filteredSetting)));
17
- // @ts-expect-error TS(7006) FIXME: Parameter 't' implicitly has an 'any' type.
18
13
  return scriptInquirerOptions.filter((t) => filteredSettingNames.has(t.name));
19
14
  };
20
- /** @typedef {import('@netlify/build-info').Settings} Settings */
21
15
  /**
22
- * @param {Settings[]} settings
23
- * @param {'dev' | 'build'} type The type of command (dev or build)
16
+ * Formats the settings to present it as an array for the inquirer input so that it can choose one
24
17
  */
25
- // @ts-expect-error TS(7006) FIXME: Parameter 'settings' implicitly has an 'any' type.
26
18
  const formatSettingsArrForInquirer = function (settings, type = 'dev') {
27
- // @ts-expect-error TS(7006) FIXME: Parameter 'setting' implicitly has an 'any' type.
28
19
  return settings.map((setting) => {
29
20
  const cmd = type === 'dev' ? setting.devCommand : setting.buildCommand;
30
21
  return {
@@ -35,13 +26,26 @@ const formatSettingsArrForInquirer = function (settings, type = 'dev') {
35
26
  });
36
27
  };
37
28
  /**
38
- * Uses @netlify/build-info to detect the dev settings and port based on the framework
29
+ * Detects and filters the build setting for a project and a command
30
+ */
31
+ export async function detectBuildSettings(command) {
32
+ const { project, workspacePackage } = command;
33
+ const buildSettings = await project.getBuildSettings(project.workspace ? workspacePackage : '');
34
+ return buildSettings
35
+ .filter((setting) => {
36
+ if (project.workspace && project.relativeBaseDirectory && setting.packagePath) {
37
+ return project.relativeBaseDirectory.startsWith(setting.packagePath);
38
+ }
39
+ return true;
40
+ })
41
+ .filter((setting) => setting.devCommand);
42
+ }
43
+ /**
44
+ * Uses `@netlify/build-info` to detect the dev settings and port based on the framework
39
45
  * and the build system that is used.
40
- * @param {import('../commands/base-command.js').default} command
41
- * @param {'dev' | 'build'} type The type of command (dev or build)
42
- * @returns {Promise<Settings | undefined>}
46
+ * @param command The base command
47
+ * @param type The type of command (dev or build)
43
48
  */
44
- // @ts-expect-error TS(7006) FIXME: Parameter 'command' implicitly has an 'any' type.
45
49
  export const detectFrameworkSettings = async (command, type = 'dev') => {
46
50
  const { relConfigFilePath } = command.netlify;
47
51
  const settings = await detectBuildSettings(command);
@@ -49,16 +53,14 @@ export const detectFrameworkSettings = async (command, type = 'dev') => {
49
53
  return settings[0];
50
54
  }
51
55
  if (settings.length > 1) {
52
- /** multiple matching detectors, make the user choose */
56
+ // multiple matching detectors, make the user choose
53
57
  const scriptInquirerOptions = formatSettingsArrForInquirer(settings, type);
54
- /** @type {{chosenSettings: Settings}} */
55
58
  const { chosenSettings } = await inquirer.prompt({
56
59
  name: 'chosenSettings',
57
60
  message: `Multiple possible ${type} commands found`,
58
- // @ts-expect-error TS(2769) FIXME: No overload matches this call.
61
+ // @ts-expect-error is not known by the types as it uses the autocomplete plugin
59
62
  type: 'autocomplete',
60
- // @ts-expect-error TS(7006) FIXME: Parameter '_' implicitly has an 'any' type.
61
- source(/** @type {string} */ _, input = '') {
63
+ source(_, input = '') {
62
64
  if (!input)
63
65
  return scriptInquirerOptions;
64
66
  // only show filtered results
@@ -78,22 +80,3 @@ command = "${chosenSettings.devCommand}"
78
80
  return chosenSettings;
79
81
  }
80
82
  };
81
- /**
82
- * Detects and filters the build setting for a project and a command
83
- * @param {import('../commands/base-command.js').default} command
84
- */
85
- // @ts-expect-error TS(7006) FIXME: Parameter 'command' implicitly has an 'any' type.
86
- export const detectBuildSettings = async (command) => {
87
- const { project, workspacePackage } = command;
88
- const buildSettings = await project.getBuildSettings(project.workspace ? workspacePackage : '');
89
- return (buildSettings
90
- // @ts-expect-error TS(7006) FIXME: Parameter 'setting' implicitly has an 'any' type.
91
- .filter((setting) => {
92
- if (project.workspace && project.relativeBaseDirectory && setting.packagePath) {
93
- return project.relativeBaseDirectory.startsWith(setting.packagePath);
94
- }
95
- return true;
96
- })
97
- // @ts-expect-error TS(7006) FIXME: Parameter 'setting' implicitly has an 'any' type.
98
- .filter((setting) => setting.devCommand));
99
- };
@@ -158,22 +158,14 @@ export const warn = (message = '') => {
158
158
  const bang = chalk.yellow(BANG);
159
159
  log(` ${bang} Warning: ${message}`);
160
160
  };
161
- /**
162
- * throws an error or log it
163
- * @param {unknown} message
164
- * @param {object} [options]
165
- * @param {boolean} [options.exit]
166
- */
161
+ /** Throws an error or logs it */
167
162
  export const error = (message = '', options = {}) => {
168
- const err =
169
- // @ts-expect-error TS(2358) FIXME: The left-hand side of an 'instanceof' expression m... Remove this comment to see the full error message
170
- message instanceof Error
163
+ const err = message instanceof Error
171
164
  ? message
172
165
  : // eslint-disable-next-line unicorn/no-nested-ternary
173
166
  typeof message === 'string'
174
167
  ? new Error(message)
175
- : /** @type {Error} */ { message, stack: undefined, name: 'Error' };
176
- // @ts-expect-error TS(2339) FIXME: Property 'exit' does not exist on type '{}'.
168
+ : { message, stack: undefined, name: 'Error' };
177
169
  if (options.exit === false) {
178
170
  const bang = chalk.red(BANG);
179
171
  if (process.env.DEBUG) {