netlify 27.8.1 → 27.10.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.
@@ -10,6 +10,7 @@ export const blobsDelete = async (storeName, key, _options, command) => {
10
10
  const store = getStore({
11
11
  apiURL: `${api.scheme}://${api.host}`,
12
12
  name: storeName,
13
+ region: _options.region,
13
14
  siteID: siteInfo.id ?? '',
14
15
  token: api.accessToken ?? '',
15
16
  });
@@ -1,7 +1,9 @@
1
+ import { type GetStoreOptions } from '@netlify/blobs';
1
2
  import { OptionValues } from 'commander';
2
3
  import BaseCommand from '../base-command.js';
3
4
  interface Options extends OptionValues {
4
5
  output?: string;
6
+ region?: GetStoreOptions['region'];
5
7
  }
6
8
  export declare const blobsGet: (storeName: string, key: string, options: Options, command: BaseCommand) => Promise<undefined>;
7
9
  export {};
@@ -8,6 +8,7 @@ export const blobsGet = async (storeName, key, options, command) => {
8
8
  const store = getStore({
9
9
  apiURL: `${api.scheme}://${api.host}`,
10
10
  name: storeName,
11
+ region: options.region,
11
12
  siteID: siteInfo?.id ?? '',
12
13
  token: api.accessToken ?? '',
13
14
  });
@@ -1,9 +1,11 @@
1
+ import { type GetStoreOptions } from '@netlify/blobs';
1
2
  import { OptionValues } from 'commander';
2
3
  import BaseCommand from '../base-command.js';
3
4
  interface Options extends OptionValues {
4
5
  directories?: boolean;
5
6
  json?: boolean;
6
7
  prefix?: string;
8
+ region?: GetStoreOptions['region'];
7
9
  }
8
10
  export declare const blobsList: (storeName: string, options: Options, command: BaseCommand) => Promise<undefined>;
9
11
  export {};
@@ -6,6 +6,7 @@ export const blobsList = async (storeName, options, command) => {
6
6
  const store = getStore({
7
7
  apiURL: `${api.scheme}://${api.host}`,
8
8
  name: storeName,
9
+ region: options.region,
9
10
  siteID: siteInfo.id,
10
11
  token: api.accessToken ?? '',
11
12
  });
@@ -1,8 +1,10 @@
1
+ import { type GetStoreOptions } from '@netlify/blobs';
1
2
  import { OptionValues } from 'commander';
2
3
  import BaseCommand from '../base-command.js';
3
4
  interface Options extends OptionValues {
4
5
  input?: string;
5
6
  force?: string | boolean;
7
+ region?: GetStoreOptions['region'];
6
8
  }
7
9
  export declare const blobsSet: (storeName: string, key: string, valueParts: string[], options: Options, command: BaseCommand) => Promise<undefined>;
8
10
  export {};
@@ -9,6 +9,7 @@ export const blobsSet = async (storeName, key, valueParts, options, command) =>
9
9
  const store = getStore({
10
10
  apiURL: `${api.scheme}://${api.host}`,
11
11
  name: storeName,
12
+ region: options.region,
12
13
  siteID: siteInfo.id,
13
14
  token: api.accessToken ?? '',
14
15
  });
@@ -15,6 +15,7 @@ export const createBlobsCommand = (program) => {
15
15
  .description(`Deletes an object with a given key, if it exists, from a Netlify Blobs store`)
16
16
  .argument('<store>', 'Name of the store')
17
17
  .argument('<key>', 'Object key')
18
+ .option('--region <region>', "The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used")
18
19
  .alias('blob:delete')
19
20
  .hook('preAction', requiresSiteInfo)
20
21
  .action(async (storeName, key, _options, command) => {
@@ -27,6 +28,7 @@ export const createBlobsCommand = (program) => {
27
28
  .argument('<store>', 'Name of the store')
28
29
  .argument('<key>', 'Object key')
29
30
  .option('-O, --output <path>', 'Defines the filesystem path where the blob data should be persisted')
31
+ .option('--region <region>', "The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used")
30
32
  .alias('blob:get')
31
33
  .hook('preAction', requiresSiteInfo)
32
34
  .action(async (storeName, key, options, command) => {
@@ -40,6 +42,7 @@ export const createBlobsCommand = (program) => {
40
42
  .option('-d, --directories', `Indicates that keys with the '/' character should be treated as directories, returning a list of sub-directories at a given level rather than all the keys inside them`)
41
43
  .option('-p, --prefix <prefix>', `A string for filtering down the entries; when specified, only the entries whose key starts with that prefix are returned`)
42
44
  .option('--json', 'Output list contents as JSON')
45
+ .option('--region <region>', "The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used")
43
46
  .alias('blob:list')
44
47
  .hook('preAction', requiresSiteInfo)
45
48
  .action(async (storeName, options, command) => {
@@ -53,6 +56,7 @@ export const createBlobsCommand = (program) => {
53
56
  .argument('<key>', 'Object key')
54
57
  .argument('[value...]', 'Object value')
55
58
  .option('-i, --input <path>', 'Defines the filesystem path where the blob data should be read from')
59
+ .option('--region <region>', "The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used")
56
60
  .alias('blob:set')
57
61
  .hook('preAction', requiresSiteInfo)
58
62
  .action(async (storeName, key, valueParts, options, command) => {
@@ -76,6 +80,7 @@ For more information about Netlify Blobs, see ${terminalLink(docsUrl, docsUrl, {
76
80
  'netlify blobs:delete my-store my-key',
77
81
  'netlify blobs:list my-store',
78
82
  'netlify blobs:list my-store --json',
83
+ 'netlify blobs:list my-store --region eu-central-1',
79
84
  ])
80
85
  .action(blobs);
81
86
  };
@@ -22,7 +22,7 @@ import { getDeploySourceFields } from '../../utils/deploy/deploy-source.js';
22
22
  import { uploadSourceZip } from '../../utils/deploy/upload-source-zip.js';
23
23
  import { getEnvelopeEnv } from '../../utils/env/index.js';
24
24
  import { mergeDeployEnvVars } from '../../utils/env/deploy-env-vars.js';
25
- import { getFunctionsManifestPath, getInternalFunctionsDir } from '../../utils/functions/index.js';
25
+ import { getFunctionsManifestPath, getInternalFunctionsDir, getServerManifestPath, } from '../../utils/functions/index.js';
26
26
  import { isEmpty } from '../../utils/object-utilities.js';
27
27
  import openBrowser from '../../utils/open-browser.js';
28
28
  import { isInteractive } from '../../utils/scripted-commands.js';
@@ -458,6 +458,7 @@ title, deployId: existingDeployId, }) => {
458
458
  functionsFolder,
459
459
  ].filter((folder) => Boolean(folder));
460
460
  const manifestPath = skipFunctionsCache ? null : await getFunctionsManifestPath({ base: site.root, packagePath });
461
+ const serverManifestPath = await getServerManifestPath({ base: site.root, packagePath });
461
462
  const redirectsPath = `${deployFolder}/_redirects`;
462
463
  const headersPath = `${deployFolder}/_headers`;
463
464
  const { redirects } = await parseAllRedirects({
@@ -493,6 +494,9 @@ title, deployId: existingDeployId, }) => {
493
494
  filter: getDeployFilesFilter({ site, deployFolder }),
494
495
  workingDir: command.workingDir,
495
496
  manifestPath,
497
+ packagePath,
498
+ serverEnabled: Boolean(siteData?.feature_flags?.netlify_build_server_standalone),
499
+ serverManifestPath: serverManifestPath ?? undefined,
496
500
  skipFunctionsCache,
497
501
  siteRoot: site.root,
498
502
  environment: mergeDeployEnvVars(options.env, options.secretEnv),
@@ -3,13 +3,16 @@ import { type $TSFixMe } from '../../commands/types.js';
3
3
  import type { DeployEvent } from './status-cb.js';
4
4
  import type { DeployEnvironmentVariable } from '../env/deploy-env-vars.js';
5
5
  export type { DeployEvent };
6
- export declare const deploySite: (command: BaseCommand, api: $TSFixMe, siteId: any, dir: any, { assetType, branch, concurrentHash, concurrentUpload, config, deployId, deployTimeout, draft, environment, filter, fnDir, functionsConfig, hashAlgorithm, manifestPath, maxRetry, siteRoot, skipFunctionsCache, statusCb, syncFileLimit, tmpDir, workingDir, }: {
6
+ export declare const deploySite: (command: BaseCommand, api: $TSFixMe, siteId: any, dir: any, { assetType, branch, concurrentHash, concurrentUpload, config, deployId, deployTimeout, draft, environment, filter, fnDir, functionsConfig, hashAlgorithm, manifestPath, maxRetry, packagePath, serverEnabled, serverManifestPath, siteRoot, skipFunctionsCache, statusCb, syncFileLimit, tmpDir, workingDir, }: {
7
7
  concurrentHash?: number;
8
8
  concurrentUpload?: number;
9
9
  deployTimeout?: number;
10
10
  draft?: boolean;
11
11
  environment?: DeployEnvironmentVariable[];
12
12
  maxRetry?: number;
13
+ packagePath?: string;
14
+ serverEnabled?: boolean;
15
+ serverManifestPath?: string;
13
16
  statusCb?: (status: DeployEvent) => void;
14
17
  syncFileLimit?: number;
15
18
  tmpDir?: string;
@@ -36,7 +36,7 @@ functionsConfig,
36
36
  // @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
37
37
  hashAlgorithm,
38
38
  // @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
39
- manifestPath, maxRetry = DEFAULT_MAX_RETRY,
39
+ manifestPath, maxRetry = DEFAULT_MAX_RETRY, packagePath, serverEnabled, serverManifestPath,
40
40
  // @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
41
41
  siteRoot,
42
42
  // @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
@@ -51,7 +51,7 @@ skipFunctionsCache, statusCb = () => {
51
51
  const edgeFunctionsDistPath = await getEdgeFunctionsDistPathIfExists(workingDir);
52
52
  const deployConfigPath = await getDeployConfigPathIfExists(workingDir);
53
53
  const dbMigrationsDistPath = await getDbMigrationsDistPathIfExists(workingDir);
54
- const [{ files: staticFiles, filesShaMap: staticShaMap }, { fnConfig, fnShaMap, functionSchedules, functions, functionsWithNativeModules }, configFile, { edgeFunctions, edgeFnShaMap },] = await Promise.all([
54
+ const [{ files: staticFiles, filesShaMap: staticShaMap }, { fnConfig, fnShaMap, functionSchedules, functions, functionsWithNativeModules, server, serverShaMap }, configFile, { edgeFunctions, edgeFnShaMap },] = await Promise.all([
55
55
  hashFiles({
56
56
  assetType,
57
57
  concurrentHash,
@@ -68,6 +68,9 @@ skipFunctionsCache, statusCb = () => {
68
68
  hashAlgorithm,
69
69
  statusCb,
70
70
  manifestPath,
71
+ packagePath,
72
+ serverEnabled,
73
+ serverManifestPath,
71
74
  skipFunctionsCache,
72
75
  rootDir: siteRoot,
73
76
  }),
@@ -122,6 +125,7 @@ For more information, visit https://ntl.fyi/cli-native-modules.`);
122
125
  files,
123
126
  functions,
124
127
  edge_functions: edgeFunctions,
128
+ server,
125
129
  function_schedules: functionSchedules,
126
130
  functions_config: fnConfig,
127
131
  async: Object.keys(files).length > syncFileLimit,
@@ -141,7 +145,7 @@ For more information, visit https://ntl.fyi/cli-native-modules.`);
141
145
  let deploy = await api.updateSiteDeploy(deployParams);
142
146
  if (deployParams.body.async)
143
147
  deploy = await waitForDiff(api, deploy.id, siteId, deployTimeout);
144
- const { required: requiredFiles, required_functions: requiredFns, required_edge_functions: requiredEdgeFns } = deploy;
148
+ const { required: requiredFiles, required_functions: requiredFns, required_edge_functions: requiredEdgeFns, required_server: requiredServer, } = deploy;
145
149
  statusCb({
146
150
  type: 'create-deploy',
147
151
  msg: `CDN requesting ${requiredFiles.length} files${Array.isArray(requiredFns) ? ` and ${requiredFns.length} functions` : ''}${Array.isArray(requiredEdgeFns) ? ` and ${requiredEdgeFns.length} edge functions` : ''}`,
@@ -150,7 +154,8 @@ For more information, visit https://ntl.fyi/cli-native-modules.`);
150
154
  const filesUploadList = getUploadList(requiredFiles, filesShaMap);
151
155
  const functionsUploadList = getUploadList(requiredFns, fnShaMap);
152
156
  const edgeFunctionsUploadList = getUploadList(requiredEdgeFns, edgeFnShaMap);
153
- const uploadList = [...filesUploadList, ...functionsUploadList, ...edgeFunctionsUploadList];
157
+ const serverUploadList = getUploadList(requiredServer, serverShaMap);
158
+ const uploadList = [...filesUploadList, ...functionsUploadList, ...edgeFunctionsUploadList, ...serverUploadList];
154
159
  await uploadFiles(api, deployId, uploadList, { concurrentUpload, statusCb, maxRetry });
155
160
  statusCb({
156
161
  type: 'wait-for-deploy',
@@ -1,11 +1,15 @@
1
1
  import BaseCommand from '../../commands/base-command.js';
2
2
  import { $TSFixMe } from '../../commands/types.js';
3
- declare const hashFns: (command: BaseCommand, directories: string[], { concurrentHash, functionsConfig, hashAlgorithm, manifestPath, rootDir, skipFunctionsCache, statusCb, tmpDir, }: {
3
+ import type { ServerUploadFile } from './upload-files.js';
4
+ declare const hashFns: (command: BaseCommand, directories: string[], { concurrentHash, functionsConfig, hashAlgorithm, manifestPath, packagePath, rootDir, serverEnabled, serverManifestPath, skipFunctionsCache, statusCb, tmpDir, }: {
4
5
  concurrentHash?: number;
5
6
  functionsConfig?: $TSFixMe;
6
7
  hashAlgorithm?: string | undefined;
7
8
  manifestPath?: string | undefined;
9
+ packagePath?: string | undefined;
8
10
  rootDir?: string | undefined;
11
+ serverEnabled?: boolean | undefined;
12
+ serverManifestPath?: string | undefined;
9
13
  skipFunctionsCache?: boolean | undefined;
10
14
  statusCb: $TSFixMe;
11
15
  tmpDir: $TSFixMe;
@@ -19,6 +23,11 @@ declare const hashFns: (command: BaseCommand, directories: string[], { concurren
19
23
  shaMap?: Record<string, $TSFixMe> | undefined;
20
24
  fnShaMap?: Record<string, $TSFixMe[]> | undefined;
21
25
  fnConfig?: Record<string, $TSFixMe> | undefined;
26
+ server?: {
27
+ sha: string;
28
+ region?: string;
29
+ } | undefined;
30
+ serverShaMap?: Record<string, ServerUploadFile[]> | undefined;
22
31
  }>;
23
32
  export default hashFns;
24
33
  //# sourceMappingURL=hash-fns.d.ts.map
@@ -1,8 +1,9 @@
1
1
  import { readFile } from 'fs/promises';
2
- import path from 'path';
2
+ import path, { join } from 'path';
3
3
  import { pipeline } from 'stream/promises';
4
4
  import { Readable } from 'stream';
5
- import { zipFunctions } from '@netlify/zip-it-and-ship-it';
5
+ import { SERVER_DIRECTORY } from '@netlify/build';
6
+ import { findServerEntry, zipFunctions, zipServer, } from '@netlify/zip-it-and-ship-it';
6
7
  import { INTERNAL_FUNCTIONS_FOLDER } from '../functions/functions.js';
7
8
  import { hasherCtor, manifestCollectorCtor } from './hasher-segments.js';
8
9
  // Maximum age of functions manifest (2 minutes).
@@ -15,9 +16,7 @@ const getFunctionZips = async ({ command, directories, functionsConfig, manifest
15
16
  });
16
17
  if (manifestPath) {
17
18
  try {
18
- // read manifest.json file
19
- // @ts-expect-error TS(2345) FIXME: Argument of type 'Buffer' is not assignable to par... Remove this comment to see the full error message
20
- const { functions, timestamp } = JSON.parse(await readFile(manifestPath));
19
+ const { functions, timestamp } = JSON.parse(await readFile(manifestPath, 'utf-8'));
21
20
  const manifestAge = Date.now() - timestamp;
22
21
  if (manifestAge > MANIFEST_FILE_TTL) {
23
22
  throw new Error('Manifest expired');
@@ -53,6 +52,28 @@ const getFunctionZips = async ({ command, directories, functionsConfig, manifest
53
52
  config: functionsConfig,
54
53
  });
55
54
  };
55
+ const getServerBundle = async ({ packagePath, rootDir, serverEnabled, serverManifestPath, tmpDir, }) => {
56
+ if (!serverEnabled) {
57
+ return undefined;
58
+ }
59
+ if (serverManifestPath) {
60
+ try {
61
+ const { server, timestamp } = JSON.parse(await readFile(serverManifestPath, 'utf-8'));
62
+ if (server && Date.now() - timestamp <= MANIFEST_FILE_TTL) {
63
+ return server;
64
+ }
65
+ }
66
+ catch {
67
+ // An unusable manifest is no different from not having one: the server is
68
+ // rebuilt below.
69
+ }
70
+ }
71
+ const entryPath = rootDir ? await findServerEntry(join(rootDir, packagePath ?? '', SERVER_DIRECTORY)) : undefined;
72
+ if (entryPath === undefined) {
73
+ return undefined;
74
+ }
75
+ return await zipServer(entryPath, join(tmpDir, 'server'), { basePath: rootDir });
76
+ };
56
77
  const trafficRulesConfig = (trafficRules) => {
57
78
  if (!trafficRules) {
58
79
  return;
@@ -72,24 +93,30 @@ const trafficRulesConfig = (trafficRules) => {
72
93
  },
73
94
  };
74
95
  };
75
- const hashFns = async (command, directories, { concurrentHash, functionsConfig, hashAlgorithm = 'sha256', manifestPath, rootDir, skipFunctionsCache, statusCb, tmpDir, }) => {
76
- // Exit early if no functions directories are configured.
77
- if (directories.length === 0) {
96
+ const hashFns = async (command, directories, { concurrentHash, functionsConfig, hashAlgorithm = 'sha256', manifestPath, packagePath, rootDir, serverEnabled, serverManifestPath, skipFunctionsCache, statusCb, tmpDir, }) => {
97
+ // Exit early if there is nothing to bundle. A site can have a server without
98
+ // any functions directory.
99
+ if (directories.length === 0 && !serverEnabled) {
78
100
  return { functions: {}, functionsWithNativeModules: [], shaMap: {} };
79
101
  }
80
102
  if (!tmpDir) {
81
103
  throw new Error('Missing tmpDir directory for zipping files');
82
104
  }
83
- const functionZips = await getFunctionZips({
84
- command,
85
- directories,
86
- functionsConfig,
87
- manifestPath,
88
- rootDir,
89
- skipFunctionsCache,
90
- statusCb,
91
- tmpDir,
92
- });
105
+ const [functionZips, serverBundle] = await Promise.all([
106
+ directories.length === 0
107
+ ? []
108
+ : getFunctionZips({
109
+ command,
110
+ directories,
111
+ functionsConfig,
112
+ manifestPath,
113
+ rootDir,
114
+ skipFunctionsCache,
115
+ statusCb,
116
+ tmpDir,
117
+ }),
118
+ getServerBundle({ packagePath, rootDir, serverEnabled, serverManifestPath, tmpDir }),
119
+ ]);
93
120
  // ZISI's in-memory FunctionResult only nests bootstrap/runtime version into
94
121
  // buildData when writing the manifest cache. Reconstruct it for direct-zip paths.
95
122
  for (const func of functionZips) {
@@ -156,7 +183,34 @@ const hashFns = async (command, directories, { concurrentHash, functionsConfig,
156
183
  const fnShaMap = {};
157
184
  const manifestCollector = manifestCollectorCtor(functions, fnShaMap, { statusCb });
158
185
  await pipeline([functionStream, hasher, manifestCollector]);
159
- return { functionSchedules, functions, functionsWithNativeModules, fnShaMap, fnConfig };
186
+ const { server, serverShaMap } = await hashServer(serverBundle, { concurrentHash, hashAlgorithm, statusCb, tmpDir });
187
+ return { functionSchedules, functions, functionsWithNativeModules, fnShaMap, fnConfig, server, serverShaMap };
188
+ };
189
+ // A deploy has at most one server, so it is declared on its own rather than in a
190
+ // map keyed by name. It still goes through the same hashing pipeline, so the
191
+ // upload flow can treat it like any other artifact.
192
+ const hashServer = async (serverBundle, { concurrentHash, hashAlgorithm, statusCb, tmpDir, }) => {
193
+ if (!serverBundle) {
194
+ return {};
195
+ }
196
+ const fileObj = {
197
+ filepath: serverBundle.path,
198
+ root: tmpDir,
199
+ relname: path.relative(tmpDir, serverBundle.path),
200
+ basename: path.basename(serverBundle.path),
201
+ extname: path.extname(serverBundle.path),
202
+ type: 'file',
203
+ assetType: 'server',
204
+ normalizedPath: path.basename(serverBundle.path, path.extname(serverBundle.path)),
205
+ };
206
+ const servers = {};
207
+ const serverShaMap = {};
208
+ await pipeline([
209
+ Readable.from([fileObj]),
210
+ hasherCtor({ concurrentHash, hashAlgorithm }),
211
+ manifestCollectorCtor(servers, serverShaMap, { statusCb }),
212
+ ]);
213
+ return { server: { sha: Object.values(servers)[0], region: serverBundle.region }, serverShaMap };
160
214
  };
161
215
  export default hashFns;
162
216
  //# sourceMappingURL=hash-fns.js.map
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import type { NetlifyAPI } from '@netlify/api';
3
3
  import type { StatusCallback } from './status-cb.js';
4
- export type UploadApi = Pick<NetlifyAPI, 'uploadDeployFile' | 'uploadDeployFunction' | 'uploadDeployEdgeFunction'>;
4
+ export type UploadApi = Pick<NetlifyAPI, 'uploadDeployFile' | 'uploadDeployFunction' | 'uploadDeployEdgeFunction' | 'uploadDeployServer'>;
5
5
  interface UploadFileBase {
6
6
  filepath: string;
7
7
  normalizedPath: string;
@@ -20,7 +20,11 @@ export interface EdgeFunctionUploadFile extends UploadFileBase {
20
20
  assetType: 'edge-function';
21
21
  hash: string;
22
22
  }
23
- export type UploadFile = StaticUploadFile | FunctionUploadFile | EdgeFunctionUploadFile;
23
+ export interface ServerUploadFile extends UploadFileBase {
24
+ assetType: 'server';
25
+ hash: string;
26
+ }
27
+ export type UploadFile = StaticUploadFile | FunctionUploadFile | EdgeFunctionUploadFile | ServerUploadFile;
24
28
  interface UploadFilesOptions {
25
29
  concurrentUpload: number;
26
30
  maxRetry: number;
@@ -63,6 +63,19 @@ const uploadFiles = async (api, deployId, uploadList, { concurrentUpload, maxRet
63
63
  return api.uploadDeployEdgeFunction(params);
64
64
  }, maxRetry);
65
65
  }
66
+ case 'server': {
67
+ return await retryUpload((retryCount) => {
68
+ const params = {
69
+ body: readStreamCtor,
70
+ deployId,
71
+ codeSha: fileObj.hash,
72
+ };
73
+ if (retryCount > 0) {
74
+ params.xNfRetryCount = retryCount;
75
+ }
76
+ return api.uploadDeployServer(params);
77
+ }, maxRetry);
78
+ }
66
79
  default: {
67
80
  throw new MissingAssetTypeError(fileObj);
68
81
  }
@@ -13,6 +13,10 @@ export declare const getFunctionsManifestPath: ({ base, packagePath }: {
13
13
  base: string;
14
14
  packagePath?: string;
15
15
  }) => Promise<string | null>;
16
+ export declare const getServerManifestPath: ({ base, packagePath }: {
17
+ base: string;
18
+ packagePath?: string;
19
+ }) => Promise<string | null>;
16
20
  export declare const getFunctionsDistPath: ({ base, packagePath, }: {
17
21
  base?: undefined | string;
18
22
  packagePath?: string;
@@ -17,6 +17,11 @@ export const getFunctionsManifestPath = async ({ base, packagePath = '' }) => {
17
17
  const isFile = await isFileAsync(path);
18
18
  return isFile ? path : null;
19
19
  };
20
+ export const getServerManifestPath = async ({ base, packagePath = '' }) => {
21
+ const path = resolve(base, packagePath, getPathInProject(['server', 'manifest.json']));
22
+ const isFile = await isFileAsync(path);
23
+ return isFile ? path : null;
24
+ };
20
25
  export const getFunctionsDistPath = async ({ base, packagePath = '', }) => {
21
26
  const path = resolve(base ?? '', packagePath, getPathInProject(['functions']));
22
27
  const isDirectory = await isDirectoryAsync(path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "netlify",
3
- "version": "27.8.1",
3
+ "version": "27.10.0",
4
4
  "description": "Netlify command line tool",
5
5
  "keywords": [
6
6
  "api",
@@ -55,12 +55,12 @@
55
55
  "@netlify/ai": "^1.0.1",
56
56
  "@netlify/api": "^15.1.2",
57
57
  "@netlify/blobs": "^11.1.0",
58
- "@netlify/build": "^37.0.0",
58
+ "@netlify/build": "^37.3.0",
59
59
  "@netlify/build-info": "^11.3.0",
60
60
  "@netlify/config": "^25.2.5",
61
61
  "@netlify/dev": "^5.1.2",
62
62
  "@netlify/dev-utils": "^6.0.1",
63
- "@netlify/edge-bundler": "^16.0.4",
63
+ "@netlify/edge-bundler": "^16.1.0",
64
64
  "@netlify/edge-functions": "^4.0.0",
65
65
  "@netlify/edge-functions-bootstrap": "^3.2.0",
66
66
  "@netlify/headers-parser": "^10.1.1",
@@ -68,7 +68,7 @@
68
68
  "@netlify/local-functions-proxy": "^2.0.3",
69
69
  "@netlify/redirect-parser": "^16.1.1",
70
70
  "@netlify/server-dev": "^0.1.1",
71
- "@netlify/zip-it-and-ship-it": "^16.0.0",
71
+ "@netlify/zip-it-and-ship-it": "^16.2.0",
72
72
  "@octokit/rest": "^22.0.0",
73
73
  "@opentelemetry/api": "~1.9.0",
74
74
  "@pnpm/tabtab": "^0.5.4",