@netlify/zip-it-and-ship-it 8.4.2 → 8.6.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/README.md CHANGED
@@ -47,7 +47,7 @@ A directory or a list of directories containing the source files. If a string is
47
47
  must exist. If an array of strings is provided, at least one directory must exist.
48
48
 
49
49
  In Netlify, this directory is the
50
- ["Functions folder"](https://docs.netlify.com/functions/configure-and-deploy/#configure-the-functions-folder).
50
+ ["Functions folder"](https://docs.netlify.com/functions/optional-configuration/?fn-language=ts#directory).
51
51
 
52
52
  A source folder can contain:
53
53
 
@@ -279,7 +279,7 @@ import { zipFunction } from '@netlify/zip-it-and-ship-it'
279
279
  const archive = await zipFunction('functions/function.js', 'functions-dist')
280
280
  ```
281
281
 
282
- This is like [`zipFunctions()`](#zipfunctionssrcfolder-destfolder-options) except it bundles a single Function.
282
+ This is like [`zipFunctions()`](#zipfunctionssrcfolders-destfolder-options) except it bundles a single Function.
283
283
 
284
284
  The return value is `undefined` if the function is invalid.
285
285
 
@@ -315,6 +315,10 @@ Each object has the following properties:
315
315
  Function's name. This is the one used in the Function URL. For example, if a Function is a `myFunc.js` regular file,
316
316
  the `name` is `myFunc` and the URL is `https://{hostname}/.netlify/functions/myFunc`.
317
317
 
318
+ - `displayName` `string`
319
+
320
+ If there was a user-defined configuration object applied to the function, and it had a `name` defined. This will be returned here.
321
+
318
322
  - `mainFile`: `string`
319
323
 
320
324
  Absolute path to the Function's main file. If the Function is a Node.js directory, this is its `index.js` or
@@ -330,7 +334,7 @@ Each object has the following properties:
330
334
 
331
335
  ## listFunctionsFiles(srcFolders)
332
336
 
333
- Like [`listFunctions()`](#listfunctionssrcfolder), except it returns not only the Functions main files, but also all
337
+ Like [`listFunctions()`](#listfunctionssrcfolders-options), except it returns not only the Functions main files, but also all
334
338
  their required files. This is much slower.
335
339
 
336
340
  ```js
@@ -354,7 +358,7 @@ See [feature flags](#feature-flags).
354
358
 
355
359
  ### Return value
356
360
 
357
- The return value is the same as [`listFunctions()`](#listfunctionssrcfolder) but with the following additional
361
+ The return value is the same as [`listFunctions()`](#listfunctionssrcfolders-options) but with the following additional
358
362
  properties.
359
363
 
360
364
  - `srcFile`: `string`
@@ -367,7 +371,7 @@ properties.
367
371
  $ zip-it-and-ship-it srcFolder destFolder
368
372
  ```
369
373
 
370
- The CLI performs the same logic as [`zipFunctions()`](#zipfunctionssrcfolder-destfolder-options). The archives are
374
+ The CLI performs the same logic as [`zipFunctions()`](#zipfunctionssrcfolders-destfolder-options). The archives are
371
375
  printed on `stdout` as a JSON array.
372
376
 
373
377
  # Bundling Node.js functions
@@ -425,7 +429,7 @@ These are supplied to each of the entrypoint functions (`zipFunction`, `zipFunct
425
429
  `listFunctionsFiles`) as a named parameter called `featureFlags`. It consists of an object where each key is the name of
426
430
  a feature flag and the values are Booleans indicating whether each feature flag is enabled or disabled.
427
431
 
428
- The list of all feature flags currently being used can be found [here](src/feature_flags.js).
432
+ The list of all feature flags currently being used can be found [here](src/feature_flags.ts).
429
433
 
430
434
  # Troubleshooting
431
435
 
@@ -464,7 +468,7 @@ In Netlify, this is done by ensuring that the following Node.js versions are the
464
468
  - Build-time Node.js version: this defaults to Node `16`, but can be
465
469
  [overridden with a `.nvmrc` or `NODE_VERSION` environment variable](https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascript).
466
470
  - Function runtime Node.js version: this defaults to `nodejs16.x` but can be
467
- [overridden with a `AWS_LAMBDA_JS_RUNTIME` environment variable](https://docs.netlify.com/functions/build-with-javascript/#runtime-settings).
471
+ [overridden with a `AWS_LAMBDA_JS_RUNTIME` environment variable](https://docs.netlify.com/functions/optional-configuration/?fn-language=js#node-js-version-for-runtime-2).
468
472
 
469
473
  Note that this problem might not apply for Node.js native modules using the [N-API](https://nodejs.org/api/n-api.html).
470
474
 
@@ -16,6 +16,8 @@ export const defaultFlags = {
16
16
  project_deploy_configuration_api_use_per_function_configuration_files: false,
17
17
  // Output CJS file extension
18
18
  zisi_output_cjs_extension: false,
19
+ // Do not allow ___netlify-entry-point as function or file name
20
+ zisi_disallow_new_entry_name: false,
19
21
  };
20
22
  // List of supported flags and their default value.
21
23
  export const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
package/dist/main.d.ts CHANGED
@@ -11,6 +11,7 @@ export interface ListedFunction {
11
11
  runtime: RuntimeType;
12
12
  extension: string;
13
13
  schedule?: string;
14
+ displayName?: string;
14
15
  }
15
16
  type ListedFunctionFile = ListedFunction & {
16
17
  srcFile: string;
@@ -18,17 +19,20 @@ type ListedFunctionFile = ListedFunction & {
18
19
  interface ListFunctionsOptions {
19
20
  basePath?: string;
20
21
  config?: Config;
22
+ configFileDirectories?: string[];
21
23
  featureFlags?: FeatureFlags;
22
24
  parseISC?: boolean;
23
25
  }
24
- export declare const listFunctions: (relativeSrcFolders: string | string[], { featureFlags: inputFeatureFlags, config, parseISC, }?: {
26
+ export declare const listFunctions: (relativeSrcFolders: string | string[], { featureFlags: inputFeatureFlags, config, configFileDirectories, parseISC, }?: {
25
27
  featureFlags?: FeatureFlags | undefined;
26
28
  config?: Config | undefined;
29
+ configFileDirectories?: string[] | undefined;
27
30
  parseISC?: boolean | undefined;
28
31
  }) => Promise<ListedFunction[]>;
29
- export declare const listFunction: (path: string, { featureFlags: inputFeatureFlags, config, parseISC, }?: {
32
+ export declare const listFunction: (path: string, { featureFlags: inputFeatureFlags, config, configFileDirectories, parseISC, }?: {
30
33
  featureFlags?: FeatureFlags | undefined;
31
34
  config?: Config | undefined;
35
+ configFileDirectories?: string[] | undefined;
32
36
  parseISC?: boolean | undefined;
33
37
  }) => Promise<ListedFunction | undefined>;
34
- export declare const listFunctionsFiles: (relativeSrcFolders: string | string[], { basePath, config, featureFlags: inputFeatureFlags, parseISC }?: ListFunctionsOptions) => Promise<ListedFunctionFile[]>;
38
+ export declare const listFunctionsFiles: (relativeSrcFolders: string | string[], { basePath, config, configFileDirectories, featureFlags: inputFeatureFlags, parseISC, }?: ListFunctionsOptions) => Promise<ListedFunctionFile[]>;
package/dist/main.js CHANGED
@@ -6,7 +6,8 @@ import { RuntimeCache } from './utils/cache.js';
6
6
  import { listFunctionsDirectories, resolveFunctionsDirectories } from './utils/fs.js';
7
7
  export { zipFunction, zipFunctions } from './zip.js';
8
8
  const augmentWithISC = async (func) => {
9
- // ISC is currently only supported in JavaScript and TypeScript functions.
9
+ // ISC is currently only supported in JavaScript and TypeScript functions
10
+ // and only supports scheduled functions.
10
11
  if (func.runtime.name !== "js" /* RuntimeType.JAVASCRIPT */) {
11
12
  return func;
12
13
  }
@@ -14,21 +15,21 @@ const augmentWithISC = async (func) => {
14
15
  return { ...func, inSourceConfig };
15
16
  };
16
17
  // List all Netlify Functions main entry files for a specific directory
17
- export const listFunctions = async function (relativeSrcFolders, { featureFlags: inputFeatureFlags, config, parseISC = false, } = {}) {
18
+ export const listFunctions = async function (relativeSrcFolders, { featureFlags: inputFeatureFlags, config, configFileDirectories, parseISC = false, } = {}) {
18
19
  const featureFlags = getFlags(inputFeatureFlags);
19
20
  const srcFolders = resolveFunctionsDirectories(relativeSrcFolders);
20
21
  const paths = await listFunctionsDirectories(srcFolders);
21
22
  const cache = new RuntimeCache();
22
- const functionsMap = await getFunctionsFromPaths(paths, { cache, config, featureFlags });
23
+ const functionsMap = await getFunctionsFromPaths(paths, { cache, config, configFileDirectories, featureFlags });
23
24
  const functions = [...functionsMap.values()];
24
25
  const augmentedFunctions = parseISC ? await Promise.all(functions.map(augmentWithISC)) : functions;
25
26
  return augmentedFunctions.map(getListedFunction);
26
27
  };
27
28
  // Finds a function at a specific path.
28
- export const listFunction = async function (path, { featureFlags: inputFeatureFlags, config, parseISC = false, } = {}) {
29
+ export const listFunction = async function (path, { featureFlags: inputFeatureFlags, config, configFileDirectories, parseISC = false, } = {}) {
29
30
  const featureFlags = getFlags(inputFeatureFlags);
30
31
  const cache = new RuntimeCache();
31
- const func = await getFunctionFromPath(path, { cache, config, featureFlags });
32
+ const func = await getFunctionFromPath(path, { cache, config, configFileDirectories, featureFlags });
32
33
  if (!func) {
33
34
  return;
34
35
  }
@@ -36,19 +37,26 @@ export const listFunction = async function (path, { featureFlags: inputFeatureFl
36
37
  return getListedFunction(augmentedFunction);
37
38
  };
38
39
  // List all Netlify Functions files for a specific directory
39
- export const listFunctionsFiles = async function (relativeSrcFolders, { basePath, config, featureFlags: inputFeatureFlags, parseISC = false } = {}) {
40
+ export const listFunctionsFiles = async function (relativeSrcFolders, { basePath, config, configFileDirectories, featureFlags: inputFeatureFlags, parseISC = false, } = {}) {
40
41
  const featureFlags = getFlags(inputFeatureFlags);
41
42
  const srcFolders = resolveFunctionsDirectories(relativeSrcFolders);
42
43
  const paths = await listFunctionsDirectories(srcFolders);
43
44
  const cache = new RuntimeCache();
44
- const functionsMap = await getFunctionsFromPaths(paths, { cache, config, featureFlags });
45
+ const functionsMap = await getFunctionsFromPaths(paths, { cache, config, configFileDirectories, featureFlags });
45
46
  const functions = [...functionsMap.values()];
46
47
  const augmentedFunctions = parseISC ? await Promise.all(functions.map(augmentWithISC)) : functions;
47
48
  const listedFunctionsFiles = await Promise.all(augmentedFunctions.map((func) => getListedFunctionFiles(func, { basePath, featureFlags })));
48
49
  return listedFunctionsFiles.flat();
49
50
  };
50
51
  const getListedFunction = function ({ runtime, name, mainFile, extension, config, inSourceConfig, }) {
51
- return { name, mainFile, runtime: runtime.name, extension, schedule: inSourceConfig?.schedule ?? config.schedule };
52
+ return {
53
+ name,
54
+ displayName: config.name,
55
+ mainFile,
56
+ runtime: runtime.name,
57
+ extension,
58
+ schedule: inSourceConfig?.schedule ?? config.schedule,
59
+ };
52
60
  };
53
61
  const getListedFunctionFiles = async function (func, options) {
54
62
  const srcFiles = await getSrcFiles({ ...func, ...options });
@@ -16,9 +16,10 @@ export declare const getFunctionsFromPaths: (paths: string[], { cache, config, c
16
16
  /**
17
17
  * Gets a list of functions found in a list of paths.
18
18
  */
19
- export declare const getFunctionFromPath: (path: string, { cache, config, featureFlags }: {
19
+ export declare const getFunctionFromPath: (path: string, { cache, config, configFileDirectories, featureFlags, }: {
20
20
  cache: RuntimeCache;
21
21
  config?: Config | undefined;
22
+ configFileDirectories?: string[] | undefined;
22
23
  featureFlags?: FeatureFlags | undefined;
23
24
  }) => Promise<FunctionSource | undefined>;
24
25
  export {};
@@ -1,8 +1,10 @@
1
1
  import { extname, basename } from 'path';
2
2
  import { getConfigForFunction } from '../config.js';
3
3
  import { defaultFlags } from '../feature_flags.js';
4
+ import { FunctionBundlingUserError } from '../utils/error.js';
4
5
  import goRuntime from './go/index.js';
5
6
  import jsRuntime from './node/index.js';
7
+ import { ENTRY_FILE_NAME } from './node/utils/entry_file.js';
6
8
  import rustRuntime from './rust/index.js';
7
9
  /**
8
10
  * Finds functions for a list of paths using a specific runtime. The return
@@ -17,15 +19,23 @@ const findFunctionsInRuntime = async function ({ cache, dedupe = false, featureF
17
19
  // `srcPath`, so that both functions are returned.
18
20
  const key = dedupe ? 'name' : 'srcPath';
19
21
  // Augmenting the function objects with additional information.
20
- const augmentedFunctions = functions.map((func) => [
21
- func[key],
22
- {
23
- ...func,
24
- extension: extname(func.mainFile),
25
- filename: basename(func.srcPath),
26
- runtime,
27
- },
28
- ]);
22
+ const augmentedFunctions = functions.map((func) => {
23
+ if (featureFlags.zisi_disallow_new_entry_name && func.name === ENTRY_FILE_NAME) {
24
+ throw new FunctionBundlingUserError(`'${ENTRY_FILE_NAME}' is a reserved word and cannot be used as a function name.`, {
25
+ functionName: func.name,
26
+ runtime: runtime.name,
27
+ });
28
+ }
29
+ return [
30
+ func[key],
31
+ {
32
+ ...func,
33
+ extension: extname(func.mainFile),
34
+ filename: basename(func.srcPath),
35
+ runtime,
36
+ },
37
+ ];
38
+ });
29
39
  const usedPaths = new Set(augmentedFunctions.map(([path]) => path));
30
40
  const remainingPaths = paths.filter((path) => !usedPaths.has(path));
31
41
  return { functions: augmentedFunctions, remainingPaths };
@@ -66,11 +76,16 @@ export const getFunctionsFromPaths = async (paths, { cache, config, configFileDi
66
76
  /**
67
77
  * Gets a list of functions found in a list of paths.
68
78
  */
69
- export const getFunctionFromPath = async (path, { cache, config, featureFlags = defaultFlags }) => {
79
+ export const getFunctionFromPath = async (path, { cache, config, configFileDirectories, featureFlags = defaultFlags, }) => {
70
80
  for (const runtime of RUNTIMES) {
71
81
  const func = await runtime.findFunctionInPath({ path, cache, featureFlags });
72
82
  if (func) {
73
- const functionConfig = await getConfigForFunction({ config, func: { ...func, runtime }, featureFlags });
83
+ const functionConfig = await getConfigForFunction({
84
+ config,
85
+ configFileDirectories,
86
+ func: { ...func, runtime },
87
+ featureFlags,
88
+ });
74
89
  return {
75
90
  ...func,
76
91
  runtime,
@@ -1,5 +1,6 @@
1
1
  import type { FeatureFlags } from '../../../feature_flags.js';
2
2
  import { ModuleFormat } from './module_format.js';
3
+ export declare const ENTRY_FILE_NAME = "___netlify-entry-point";
3
4
  export interface EntryFile {
4
5
  contents: string;
5
6
  filename: string;
@@ -8,8 +9,10 @@ export declare const isNamedLikeEntryFile: (file: string, { basePath, filename,
8
9
  basePath: string;
9
10
  filename: string;
10
11
  }) => boolean;
11
- export declare const conflictsWithEntryFile: (srcFiles: string[], { basePath, mainFile, filename, }: {
12
+ export declare const conflictsWithEntryFile: (srcFiles: string[], { basePath, extension, featureFlags, filename, mainFile, }: {
12
13
  basePath: string;
14
+ extension: string;
15
+ featureFlags: FeatureFlags;
13
16
  filename: string;
14
17
  mainFile: string;
15
18
  }) => boolean;
@@ -1,6 +1,8 @@
1
1
  import { basename, extname, resolve } from 'path';
2
+ import { FunctionBundlingUserError } from '../../../utils/error.js';
2
3
  import { getFileExtensionForFormat } from './module_format.js';
3
4
  import { normalizeFilePath } from './normalize_path.js';
5
+ export const ENTRY_FILE_NAME = '___netlify-entry-point';
4
6
  const getEntryFileContents = (mainPath, moduleFormat) => {
5
7
  const importPath = `.${mainPath.startsWith('/') ? mainPath : `/${mainPath}`}`;
6
8
  if (moduleFormat === "cjs" /* ModuleFormat.COMMONJS */) {
@@ -17,7 +19,21 @@ export const isNamedLikeEntryFile = (file, { basePath, filename, }) => POSSIBLE_
17
19
  return entryFilePath === file;
18
20
  });
19
21
  // Check if any src file (except the mainFile) is considered an entry file for AWS Lambda
20
- export const conflictsWithEntryFile = (srcFiles, { basePath, mainFile, filename, }) => srcFiles.some((srcFile) => isNamedLikeEntryFile(srcFile, { basePath, filename }) && srcFile !== mainFile);
22
+ export const conflictsWithEntryFile = (srcFiles, { basePath, extension, featureFlags, filename, mainFile, }) => {
23
+ let hasConflict = false;
24
+ srcFiles.forEach((srcFile) => {
25
+ if (featureFlags.zisi_disallow_new_entry_name && srcFile.includes(ENTRY_FILE_NAME)) {
26
+ throw new FunctionBundlingUserError(`'${ENTRY_FILE_NAME}' is a reserved word and cannot be used as a file or directory name.`, {
27
+ functionName: basename(filename, extension),
28
+ runtime: "js" /* RuntimeType.JAVASCRIPT */,
29
+ });
30
+ }
31
+ if (!hasConflict && isNamedLikeEntryFile(srcFile, { basePath, filename }) && srcFile !== mainFile) {
32
+ hasConflict = true;
33
+ }
34
+ });
35
+ return hasConflict;
36
+ };
21
37
  // Returns the name for the AWS Lambda entry file
22
38
  // We do set the handler in AWS Lambda to `<func-name>.handler` and because of
23
39
  // this it considers `<func-name>.(c|m)?js` as possible entry-points
@@ -53,6 +53,8 @@ const createZipArchive = async function ({ aliases, basePath, cache, destFolder,
53
53
  // take.
54
54
  const hasEntryFileConflict = conflictsWithEntryFile(srcFiles, {
55
55
  basePath,
56
+ extension,
57
+ featureFlags,
56
58
  filename,
57
59
  mainFile,
58
60
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/zip-it-and-ship-it",
3
- "version": "8.4.2",
3
+ "version": "8.6.0",
4
4
  "description": "Zip it and ship it",
5
5
  "main": "./dist/main.js",
6
6
  "type": "module",