@netlify/zip-it-and-ship-it 16.1.0 → 16.2.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/dist/main.d.ts CHANGED
@@ -5,8 +5,9 @@ import { ModuleFormat } from './runtimes/node/utils/module_format.js';
5
5
  import { RuntimeName } from './runtimes/runtime.js';
6
6
  import type { ExtendedRoute, Route } from './utils/routes.js';
7
7
  export { Config, FunctionConfig } from './config.js';
8
- export { bundle, zipFunction, zipFunctions, ZipFunctionOptions, ZipFunctionsOptions } from './zip.js';
9
- export type { BundleOptions, BundleResult, FunctionsOptions, ServerOptions, ServerResult } from './zip.js';
8
+ export { zipFunction, zipFunctions, zipServer, ZipFunctionOptions, ZipFunctionsOptions } from './zip.js';
9
+ export type { ServerOptions, ServerResult, ZipServerOptions } from './zip.js';
10
+ export { findServerEntry } from './server.js';
10
11
  export type { FunctionsBag, MixedPaths } from './paths.js';
11
12
  export { ArchiveFormat, ARCHIVE_FORMAT } from './archive.js';
12
13
  export type { TrafficRules } from './rate_limit.js';
@@ -14,7 +15,7 @@ export type { ExtendedRoute, Route } from './utils/routes.js';
14
15
  export { NodeBundlerName, NODE_BUNDLER } from './runtimes/node/bundlers/types.js';
15
16
  export { RuntimeName, RUNTIME } from './runtimes/runtime.js';
16
17
  export { ModuleFormat, MODULE_FORMAT } from './runtimes/node/utils/module_format.js';
17
- export { Manifest } from './manifest.js';
18
+ export type { FunctionsManifest, Manifest, ServerManifest } from './manifest.js';
18
19
  export { FunctionResult } from './utils/format_result.js';
19
20
  export interface ListedFunction {
20
21
  name: string;
package/dist/main.js CHANGED
@@ -6,7 +6,8 @@ import { parseFile } from './runtimes/node/in_source_config/index.js';
6
6
  import { RUNTIME } from './runtimes/runtime.js';
7
7
  import { RuntimeCache } from './utils/cache.js';
8
8
  import { listFunctionsDirectories, resolveFunctionsDirectories } from './utils/fs.js';
9
- export { bundle, zipFunction, zipFunctions } from './zip.js';
9
+ export { zipFunction, zipFunctions, zipServer } from './zip.js';
10
+ export { findServerEntry } from './server.js';
10
11
  export { ARCHIVE_FORMAT } from './archive.js';
11
12
  export { NODE_BUNDLER } from './runtimes/node/bundlers/types.js';
12
13
  export { RUNTIME } from './runtimes/runtime.js';
@@ -37,9 +37,7 @@ interface ManifestServer {
37
37
  runtimeVersion?: string;
38
38
  vcpu?: number;
39
39
  }
40
- export interface Manifest {
41
- functions: ManifestFunction[];
42
- server?: ManifestServer;
40
+ interface ManifestBase {
43
41
  system: {
44
42
  arch: string;
45
43
  platform: string;
@@ -47,9 +45,29 @@ export interface Manifest {
47
45
  timestamp: number;
48
46
  version: number;
49
47
  }
50
- export declare const createManifest: ({ functions, path, server, }: {
48
+ export interface FunctionsManifest extends ManifestBase {
49
+ functions: ManifestFunction[];
50
+ /**
51
+ * A server is described by its own manifest now. Nothing writes this any
52
+ * more; it is kept so that readers of manifests written before the split
53
+ * still compile.
54
+ */
55
+ server?: ManifestServer;
56
+ }
57
+ export interface ServerManifest extends ManifestBase {
58
+ server: ManifestServer;
59
+ }
60
+ /**
61
+ * The functions manifest, under the name it had before the server manifest was
62
+ * introduced, for backwards compatibility.
63
+ */
64
+ export type Manifest = FunctionsManifest;
65
+ export declare const createFunctionsManifest: ({ functions, path }: {
51
66
  functions: FunctionResult[];
52
67
  path: string;
53
- server?: ServerResult;
68
+ }) => Promise<void>;
69
+ export declare const createServerManifest: ({ path, server }: {
70
+ path: string;
71
+ server: ServerResult;
54
72
  }) => Promise<void>;
55
73
  export {};
package/dist/manifest.js CHANGED
@@ -2,10 +2,19 @@ import { promises as fs } from 'fs';
2
2
  import { resolve } from 'path';
3
3
  import { arch, platform } from 'process';
4
4
  const MANIFEST_VERSION = 1;
5
- export const createManifest = async ({ functions, path, server, }) => {
5
+ export const createFunctionsManifest = async ({ functions, path }) => {
6
+ const formattedFunctions = functions.map((func) => formatFunctionForManifest(func));
6
7
  const payload = {
7
- functions: functions.map((func) => formatFunctionForManifest(func)),
8
- server: server && formatServerForManifest(server),
8
+ functions: formattedFunctions,
9
+ system: { arch, platform },
10
+ timestamp: Date.now(),
11
+ version: MANIFEST_VERSION,
12
+ };
13
+ await fs.writeFile(path, JSON.stringify(payload));
14
+ };
15
+ export const createServerManifest = async ({ path, server }) => {
16
+ const payload = {
17
+ server: formatServerForManifest(server),
9
18
  system: { arch, platform },
10
19
  timestamp: Date.now(),
11
20
  version: MANIFEST_VERSION,
package/dist/server.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import type { FeatureFlags } from './feature_flags.js';
2
- import type { RuntimeName } from './runtimes/runtime.js';
2
+ import { type RuntimeName } from './runtimes/runtime.js';
3
3
  import type { RuntimeCache } from './utils/cache.js';
4
4
  import type { getLogger } from './utils/logger.js';
5
5
  import type { ExtendedRoute, Route } from './utils/routes.js';
6
6
  /**
7
- * A bundled Netlify Server. It is built like a function, but it is described on
8
- * its own terms: it carries no schedule, event subscriptions, invocation mode,
9
- * priority or timeout, because it is not invoked per request.
7
+ * Resolves the server entrypoint inside `directory`, or undefined when there is
8
+ * none.
10
9
  */
10
+ export declare const findServerEntry: (directory: string) => Promise<string | undefined>;
11
11
  export type ServerResult = {
12
12
  bundler?: string;
13
13
  excludedRoutes?: Route[];
@@ -22,8 +22,7 @@ export type ServerResult = {
22
22
  vcpu?: number;
23
23
  };
24
24
  /**
25
- * The deploy's Netlify Server, and how to bundle it. Set by whatever generates
26
- * the server, not by the user.
25
+ * The deploy's Netlify Server, and how to bundle it.
27
26
  */
28
27
  export interface ServerOptions {
29
28
  /**
package/dist/server.js CHANGED
@@ -1,42 +1,72 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import { extname, join, resolve } from 'path';
3
3
  import { ARCHIVE_FORMAT } from './archive.js';
4
+ import { NODE_BUNDLER } from './runtimes/node/bundlers/types.js';
4
5
  import { getFunctionFromPath } from './runtimes/index.js';
6
+ import { RUNTIME } from './runtimes/runtime.js';
7
+ import { FunctionBundlingUserError } from './utils/error.js';
5
8
  import { formatZipResult } from './utils/format_result.js';
6
9
  import { removeUndefined } from './utils/remove_undefined.js';
7
10
  import { getRoutes } from './utils/routes.js';
8
11
  // A server claims every path the rest of the deploy does not.
9
12
  const SERVER_ROUTE = '/*';
10
- // Names the server's output folder and its archive.
13
+ // Names the server's archive. Everywhere else it is only a label, identifying
14
+ // the server in bundling errors, since a server has no name of its own.
11
15
  const SERVER_NAME = 'server';
12
- // A server that cannot be read leaves the deploy with no backend at all, so it
13
- // fails the build rather than coming up empty.
16
+ const SERVER_ENTRY_BASENAMES = new Set(['index.js', 'index.mjs', 'index.ts', 'index.mts']);
17
+ /**
18
+ * Resolves the server entrypoint inside `directory`, or undefined when there is
19
+ * none.
20
+ */
21
+ export const findServerEntry = async (directory) => {
22
+ let entries;
23
+ try {
24
+ entries = await fs.readdir(directory);
25
+ }
26
+ catch (error) {
27
+ const { code } = error;
28
+ if (code === 'ENOENT' || code === 'ENOTDIR') {
29
+ return undefined;
30
+ }
31
+ throw error;
32
+ }
33
+ const candidates = entries.filter((name) => SERVER_ENTRY_BASENAMES.has(name)).sort();
34
+ if (candidates.length === 0) {
35
+ return undefined;
36
+ }
37
+ if (candidates.length > 1) {
38
+ throw new Error(`Found multiple server entrypoints in ${directory} (${candidates.join(', ')}). A site can have one server only.`);
39
+ }
40
+ return join(directory, candidates[0]);
41
+ };
14
42
  const readServerSource = async (srcPath, { cache, featureFlags }) => {
15
43
  let source;
44
+ // A server that cannot be read is the user's file being wrong, so it is
45
+ // reported as a bundling failure rather than an internal error.
46
+ const unreadable = (detail) => new FunctionBundlingUserError(`Could not read the Netlify Server at ${srcPath}${detail ? `: ${detail}` : ''}`, {
47
+ functionName: SERVER_NAME,
48
+ runtime: RUNTIME.JAVASCRIPT,
49
+ });
16
50
  try {
17
51
  source = await getFunctionFromPath(srcPath, { cache, featureFlags });
18
52
  }
19
53
  catch (error) {
20
- throw new Error(`Could not read the Netlify Server at ${srcPath}: ${error.message}`);
54
+ throw unreadable(error.message);
21
55
  }
22
56
  if (source === undefined) {
23
- throw new Error(`Could not read the Netlify Server at ${srcPath}`);
57
+ throw unreadable();
24
58
  }
25
59
  return source;
26
60
  };
27
- // Bundles a Netlify Server through the same runtime as a function, into its own
28
- // folder so its archive does not land among theirs.
29
61
  export const bundleServer = async (server, destFolder, { basePath, cache, featureFlags, logger, repositoryRoot, }) => {
30
62
  const srcPath = resolve(server.path);
31
63
  const source = await readServerSource(srcPath, { cache, featureFlags });
32
- const serverFolder = join(destFolder, SERVER_NAME);
33
- await fs.mkdir(serverFolder, { recursive: true });
34
64
  const zipResult = await source.runtime.zipFunction({
35
65
  archiveFormat: ARCHIVE_FORMAT.ZIP,
36
66
  basePath,
37
67
  cache,
38
- config: source.config,
39
- destFolder: serverFolder,
68
+ config: { ...source.config, nodeBundler: NODE_BUNDLER.NFT },
69
+ destFolder,
40
70
  extension: source.extension,
41
71
  featureFlags,
42
72
  filename: source.filename,
@@ -51,7 +81,7 @@ export const bundleServer = async (server, destFolder, { basePath, cache, featur
51
81
  srcPath,
52
82
  stat: source.stat,
53
83
  });
54
- const path = join(serverFolder, `${SERVER_NAME}${extname(zipResult.path)}`);
84
+ const path = join(destFolder, `${SERVER_NAME}${extname(zipResult.path)}`);
55
85
  await fs.rename(zipResult.path, path);
56
86
  const result = formatZipResult({
57
87
  ...zipResult,
package/dist/zip.d.ts CHANGED
@@ -17,53 +17,23 @@ export interface ZipFunctionOptions {
17
17
  debug?: boolean;
18
18
  internalSrcFolder?: string;
19
19
  }
20
- export interface BundleResult {
21
- /**
22
- * The bundled functions. A server is never among them.
23
- */
24
- functions: FunctionResult[];
25
- /**
26
- * The bundled Netlify Server, when one was given.
27
- */
28
- server?: ServerResult;
29
- }
30
20
  export type ZipFunctionsOptions = ZipFunctionOptions & {
31
21
  configFileDirectories?: string[];
32
22
  manifest?: string;
33
23
  parallelLimit?: number;
34
24
  };
35
- /**
36
- * The deploy's functions, and how to bundle them.
37
- */
38
- export interface FunctionsOptions {
39
- /**
40
- * Directories to search, specific function paths, or both.
41
- */
42
- paths: MixedPaths;
43
- archiveFormat?: ArchiveFormat;
44
- config?: Config;
45
- configFileDirectories?: string[];
46
- parallelLimit?: number;
47
- }
48
- export type { ServerOptions, ServerResult };
49
- export interface BundleOptions {
50
- /**
51
- * Where the archives and the manifest are written.
52
- */
53
- destFolder: string;
54
- functions?: FunctionsOptions;
55
- server?: ServerOptions;
25
+ export interface ZipServerOptions {
26
+ basePath?: string;
27
+ debug?: boolean;
28
+ featureFlags?: FeatureFlags;
56
29
  /**
57
30
  * Path of the manifest file. Defaults to `manifest.json` inside `destFolder`.
58
31
  */
59
32
  manifest?: string;
60
- basePath?: string;
61
- branch?: string;
62
- debug?: boolean;
63
- featureFlags?: FeatureFlags;
64
33
  repositoryRoot?: string;
65
34
  systemLog?: LogFunction;
66
35
  }
67
- export declare const zipFunctions: (input: MixedPaths, destFolder: string, { archiveFormat, basePath, branch, config, configFileDirectories, debug, featureFlags, manifest, parallelLimit, repositoryRoot, systemLog, }?: ZipFunctionsOptions) => Promise<FunctionResult[]>;
68
- export declare const bundle: ({ basePath, branch, debug, destFolder, featureFlags: inputFeatureFlags, functions: functionsOptions, manifest, repositoryRoot, server, systemLog, }: BundleOptions) => Promise<BundleResult>;
36
+ export type { ServerOptions, ServerResult };
37
+ export declare const zipFunctions: (input: MixedPaths, destFolder: string, { archiveFormat, basePath, branch, config, configFileDirectories, featureFlags: inputFeatureFlags, manifest, parallelLimit, repositoryRoot, systemLog, debug, }?: ZipFunctionsOptions) => Promise<FunctionResult[]>;
38
+ export declare const zipServer: (srcPath: string, destFolder: string, { basePath, debug, featureFlags: inputFeatureFlags, manifest, repositoryRoot, systemLog, }?: ZipServerOptions) => Promise<ServerResult>;
69
39
  export declare const zipFunction: (relativeSrcPath: string, destFolder: string, { archiveFormat, basePath, config: inputConfig, featureFlags: inputFeatureFlags, repositoryRoot, systemLog, debug, internalSrcFolder, }?: ZipFunctionOptions) => Promise<FunctionResult | undefined>;
package/dist/zip.js CHANGED
@@ -4,7 +4,7 @@ import isPathInside from 'is-path-inside';
4
4
  import pMap from 'p-map';
5
5
  import { ARCHIVE_FORMAT } from './archive.js';
6
6
  import { getFlags } from './feature_flags.js';
7
- import { createManifest } from './manifest.js';
7
+ import { createFunctionsManifest, createServerManifest } from './manifest.js';
8
8
  import { bundleServer } from './server.js';
9
9
  import { getFunctionsFromPaths } from './runtimes/index.js';
10
10
  import { MODULE_FORMAT } from './runtimes/node/utils/module_format.js';
@@ -23,41 +23,15 @@ const validateArchiveFormat = (archiveFormat) => {
23
23
  };
24
24
  // Zip `srcFolder/*` (Node.js or Go files) to `destFolder/*.zip` so it can be
25
25
  // used by AWS Lambda
26
- export const zipFunctions = async function (input, destFolder, { archiveFormat, basePath, branch, config, configFileDirectories, debug, featureFlags, manifest, parallelLimit, repositoryRoot, systemLog, } = {}) {
27
- const { functions } = await bundle({
28
- basePath,
29
- branch,
30
- debug,
31
- destFolder,
32
- featureFlags,
33
- functions: {
34
- archiveFormat,
35
- config,
36
- configFileDirectories,
37
- parallelLimit,
38
- paths: input,
39
- },
40
- manifest,
41
- repositoryRoot,
42
- systemLog,
43
- });
44
- return functions;
45
- };
46
- // Bundles a deploy's functions and its Netlify Server, writing the one manifest
47
- // that describes both.
48
- export const bundle = async function ({ basePath, branch, debug, destFolder, featureFlags: inputFeatureFlags, functions: functionsOptions, manifest, repositoryRoot = basePath, server, systemLog, }) {
49
- const { archiveFormat = ARCHIVE_FORMAT.ZIP, config = {}, configFileDirectories, parallelLimit = DEFAULT_PARALLEL_LIMIT, paths, } = functionsOptions ?? { paths: [] };
26
+ export const zipFunctions = async function (input, destFolder, { archiveFormat = ARCHIVE_FORMAT.ZIP, basePath, branch, config = {}, configFileDirectories, featureFlags: inputFeatureFlags, manifest, parallelLimit = DEFAULT_PARALLEL_LIMIT, repositoryRoot = basePath, systemLog, debug, } = {}) {
50
27
  validateArchiveFormat(archiveFormat);
51
28
  const logger = getLogger(systemLog, debug);
52
29
  const cache = new RuntimeCache();
53
30
  const featureFlags = getFlags(inputFeatureFlags);
54
- const bag = getFunctionsBag(paths);
31
+ const bag = getFunctionsBag(input);
55
32
  const srcFolders = resolveFunctionsDirectories([...bag.generated.directories, ...bag.user.directories]);
56
- const [foundPaths] = await Promise.all([
57
- listFunctionsDirectories(srcFolders),
58
- fs.mkdir(destFolder, { recursive: true }),
59
- ]);
60
- const functions = await getFunctionsFromPaths([...foundPaths, ...bag.generated.functions, ...bag.user.functions], {
33
+ const [paths] = await Promise.all([listFunctionsDirectories(srcFolders), fs.mkdir(destFolder, { recursive: true })]);
34
+ const functions = await getFunctionsFromPaths([...paths, ...bag.generated.functions, ...bag.user.functions], {
61
35
  cache,
62
36
  config,
63
37
  configFileDirectories,
@@ -101,21 +75,26 @@ export const bundle = async function ({ basePath, branch, debug, destFolder, fea
101
75
  const resultWithSize = await addArchiveSize(result);
102
76
  return formatZipResult(resultWithSize);
103
77
  }));
104
- const serverResult = server === undefined
105
- ? undefined
106
- : await bundleServer(server, destFolder, {
107
- basePath,
108
- cache,
109
- featureFlags,
110
- logger,
111
- repositoryRoot,
112
- });
113
- await createManifest({
78
+ await createFunctionsManifest({
114
79
  functions: formattedResults,
115
80
  path: resolve(manifest || join(destFolder, 'manifest.json')),
116
- server: serverResult,
117
81
  });
118
- return { functions: formattedResults, server: serverResult };
82
+ return formattedResults;
83
+ };
84
+ export const zipServer = async function (srcPath, destFolder, { basePath, debug, featureFlags: inputFeatureFlags, manifest, repositoryRoot = basePath, systemLog, } = {}) {
85
+ const logger = getLogger(systemLog, debug);
86
+ const cache = new RuntimeCache();
87
+ const featureFlags = getFlags(inputFeatureFlags);
88
+ await fs.mkdir(destFolder, { recursive: true });
89
+ const result = await bundleServer({ path: srcPath }, destFolder, {
90
+ basePath,
91
+ cache,
92
+ featureFlags,
93
+ logger,
94
+ repositoryRoot,
95
+ });
96
+ await createServerManifest({ path: resolve(manifest || join(destFolder, 'manifest.json')), server: result });
97
+ return result;
119
98
  };
120
99
  export const zipFunction = async function (relativeSrcPath, destFolder, { archiveFormat = ARCHIVE_FORMAT.ZIP, basePath, config: inputConfig = {}, featureFlags: inputFeatureFlags, repositoryRoot = basePath, systemLog, debug, internalSrcFolder, } = {}) {
121
100
  validateArchiveFormat(archiveFormat);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/zip-it-and-ship-it",
3
- "version": "16.1.0",
3
+ "version": "16.2.0",
4
4
  "description": "Zip it and ship it",
5
5
  "main": "./dist/main.js",
6
6
  "type": "module",
@@ -100,5 +100,5 @@
100
100
  "engines": {
101
101
  "node": ">=22.12.0"
102
102
  },
103
- "gitHead": "22902a5992a5909a97bb366c88c96f6d95c18b33"
103
+ "gitHead": "b1c3e6b1ed61a7be7bc06e4a8e4b2e48f5882de3"
104
104
  }