@netlify/config 25.1.0 → 25.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.
@@ -1,3 +1,5 @@
1
+ export declare const EDGE_FUNCTIONS_PROPERTIES: string[];
2
+ export declare const EDGE_FUNCTIONS_INTERNAL_PROPERTIES: string[];
1
3
  export declare const validations: ({
2
4
  example: () => {
3
5
  edge_functions: {
@@ -4,10 +4,30 @@ const methodValues = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
4
4
  const isMethod = (value) => typeof value === 'string' && methodValues.includes(value.toUpperCase());
5
5
  const isValidHeaderValue = (value) => typeof value === 'boolean' || typeof value === 'string';
6
6
  const isValidHeaders = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && Object.values(value).every(isValidHeaderValue);
7
+ // Properties that can be set on an edge function declaration from any origin,
8
+ // including the user's `netlify.toml`.
9
+ export const EDGE_FUNCTIONS_PROPERTIES = [
10
+ 'path',
11
+ 'excludedPath',
12
+ 'pattern',
13
+ 'excludedPattern',
14
+ 'function',
15
+ 'cache',
16
+ 'method',
17
+ 'header',
18
+ 'name',
19
+ ];
20
+ // Properties that can only be set by platform-generated configuration, i.e. by
21
+ // frameworks and integrations through the Frameworks API — never from the
22
+ // user's `netlify.toml`.
23
+ export const EDGE_FUNCTIONS_INTERNAL_PROPERTIES = ['generator'];
7
24
  export const validations = [
8
25
  {
9
26
  property: 'edge_functions.*',
10
- ...validProperties(['path', 'excludedPath', 'pattern', 'excludedPattern', 'function', 'cache', 'method', 'header'], []),
27
+ // This runs on the fully-merged configuration, which may include properties
28
+ // contributed by the Frameworks API, so it validates against the full set.
29
+ // User-facing restrictions are enforced separately (see `CONFIG_FILE_VALIDATIONS`).
30
+ ...validProperties([...EDGE_FUNCTIONS_PROPERTIES, ...EDGE_FUNCTIONS_INTERNAL_PROPERTIES], []),
11
31
  example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
12
32
  },
13
33
  {
@@ -68,6 +88,18 @@ export const validations = [
68
88
  message: 'must be a string.',
69
89
  example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
70
90
  },
91
+ {
92
+ property: 'edge_functions.*.name',
93
+ check: isString,
94
+ message: 'must be a string.',
95
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello', name: 'Hello' }] }),
96
+ },
97
+ {
98
+ property: 'edge_functions.*.generator',
99
+ check: isString,
100
+ message: 'must be a string.',
101
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello', generator: 'package-name@1.2.3' }] }),
102
+ },
71
103
  {
72
104
  property: 'edge_functions.*.path',
73
105
  check: (pathName) => pathName.startsWith('/'),
@@ -1,8 +1,8 @@
1
1
  import { normalizeConfigCase } from './case.js';
2
2
  import { normalizeConfig } from './normalize.js';
3
- import { addOrigins } from './origin.js';
3
+ import { addOrigins, CONFIG_ORIGIN } from './origin.js';
4
4
  import { validateIdenticalPlugins } from './validate/identical.js';
5
- import { validatePreCaseNormalize, validatePreMergeConfig, validatePreNormalizeConfig, validatePostNormalizeConfig, } from './validate/main.js';
5
+ import { validatePreCaseNormalize, validatePreMergeConfig, validateConfigFile, validatePreNormalizeConfig, validatePostNormalizeConfig, } from './validate/main.js';
6
6
  /**
7
7
  * Perform validation and normalization logic to apply to all of:
8
8
  * - config, defaultConfig, inlineConfig
@@ -13,6 +13,11 @@ export const normalizeBeforeConfigMerge = function (config, origin) {
13
13
  validatePreCaseNormalize(config);
14
14
  const configA = normalizeConfigCase(config);
15
15
  validatePreMergeConfig(configA);
16
+ // Some properties are only allowed to be set from the user's `netlify.toml`
17
+ // file, so they are validated exclusively against that origin.
18
+ if (origin === CONFIG_ORIGIN) {
19
+ validateConfigFile(configA);
20
+ }
16
21
  const configB = addOrigins(configA, origin);
17
22
  validateIdenticalPlugins(configB);
18
23
  return configB;
@@ -65,6 +65,7 @@ const MUTABLE_PROPS = {
65
65
  images: { lastEvent: 'onPostBuild' },
66
66
  'images.remote_images': { lastEvent: 'onPostBuild' },
67
67
  redirects: { lastEvent: 'onPostBuild' },
68
+ spa_fallback: { lastEvent: 'onPostBuild' },
68
69
  dev: { lastEvent: 'onPreDev' },
69
70
  'dev.processing': { lastEvent: 'onPreDev' },
70
71
  'dev.processing.html': { lastEvent: 'onPreDev' },
@@ -1,6 +1,7 @@
1
1
  export function isArrayOfObjects(value: any): value is Record<PropertyKey, unknown>[];
2
2
  export function isArrayOfStrings(value: any): value is string[];
3
3
  export function isString(value: any): value is string;
4
+ export function isBoolean(value: any): value is boolean;
4
5
  export function validProperties(propNames: any, legacyPropNames: any): {
5
6
  check: (value: any) => boolean;
6
7
  message: string;
@@ -8,6 +8,9 @@ export const isArrayOfStrings = function (value) {
8
8
  export const isString = function (value) {
9
9
  return typeof value === 'string';
10
10
  };
11
+ export const isBoolean = function (value) {
12
+ return typeof value === 'boolean';
13
+ };
11
14
  // Check an object valid properties, including legacy ones
12
15
  export const validProperties = function (propNames, legacyPropNames) {
13
16
  return {
@@ -1,5 +1,6 @@
1
1
  export function validatePreCaseNormalize(config: any): void;
2
2
  export function validatePreMergeConfig(config: any): void;
3
+ export function validateConfigFile(config: any): void;
3
4
  export function validatePreContextConfig(config: any): void;
4
5
  export function validatePreNormalizeConfig(config: any): void;
5
6
  export function validatePostNormalizeConfig(config: any): void;
@@ -1,7 +1,7 @@
1
1
  import { throwUserError } from '../error.js';
2
2
  import { THEME } from '../log/theme.js';
3
3
  import { getExample } from './example.js';
4
- import { PRE_CASE_NORMALIZE_VALIDATIONS, PRE_MERGE_VALIDATIONS, PRE_CONTEXT_VALIDATIONS, PRE_NORMALIZE_VALIDATIONS, POST_NORMALIZE_VALIDATIONS, } from './validations.js';
4
+ import { PRE_CASE_NORMALIZE_VALIDATIONS, PRE_MERGE_VALIDATIONS, PRE_CONTEXT_VALIDATIONS, PRE_NORMALIZE_VALIDATIONS, POST_NORMALIZE_VALIDATIONS, CONFIG_FILE_VALIDATIONS, } from './validations.js';
5
5
  // Validate the configuration file, before case normalization.
6
6
  export const validatePreCaseNormalize = function (config) {
7
7
  validateConfig(config, PRE_CASE_NORMALIZE_VALIDATIONS);
@@ -10,6 +10,13 @@ export const validatePreCaseNormalize = function (config) {
10
10
  export const validatePreMergeConfig = function (config) {
11
11
  validateConfig(config, PRE_MERGE_VALIDATIONS);
12
12
  };
13
+ // Validate properties that are only allowed to be set from the user's
14
+ // configuration file (`netlify.toml`). This runs exclusively on the config
15
+ // coming from that file, so properties reserved for other origins (e.g. the
16
+ // Frameworks API) can still set them.
17
+ export const validateConfigFile = function (config) {
18
+ validateConfig(config, CONFIG_FILE_VALIDATIONS);
19
+ };
13
20
  // Validate the configuration file, before context merge.
14
21
  export const validatePreContextConfig = function (config) {
15
22
  validateConfig(config, PRE_CONTEXT_VALIDATIONS);
@@ -8,6 +8,17 @@ export const PRE_CASE_NORMALIZE_VALIDATIONS: {
8
8
  };
9
9
  };
10
10
  }[];
11
+ export const CONFIG_FILE_VALIDATIONS: {
12
+ check: (edgeFunction: any) => boolean;
13
+ example: () => {
14
+ edge_functions: {
15
+ path: string;
16
+ function: string;
17
+ }[];
18
+ };
19
+ message: string;
20
+ property: string;
21
+ }[];
11
22
  export const PRE_MERGE_VALIDATIONS: ({
12
23
  property: string;
13
24
  check: (value: any) => value is string;
@@ -204,6 +215,13 @@ export const POST_NORMALIZE_VALIDATIONS: ({
204
215
  edge_functions: string;
205
216
  };
206
217
  };
218
+ } | {
219
+ property: string;
220
+ check: (value: any) => value is boolean;
221
+ message: string;
222
+ example: () => {
223
+ spa_fallback: boolean;
224
+ };
207
225
  } | {
208
226
  property: string;
209
227
  check: typeof isPlainObj;
@@ -1,9 +1,9 @@
1
1
  import CronParser from 'cron-parser';
2
2
  import isPlainObj from 'is-plain-obj';
3
3
  import validateNpmPackageName from 'validate-npm-package-name';
4
- import { validations as edgeFunctionValidations } from '../edge_functions.js';
4
+ import { validations as edgeFunctionValidations, EDGE_FUNCTIONS_PROPERTIES } from '../edge_functions.js';
5
5
  import { bundlers, WILDCARD_ALL as FUNCTIONS_CONFIG_WILDCARD_ALL } from '../functions_config.js';
6
- import { functionsDirectoryCheck, isArrayOfObjects, isArrayOfStrings, isString, validProperties } from './helpers.js';
6
+ import { functionsDirectoryCheck, isArrayOfObjects, isArrayOfStrings, isBoolean, isString, validProperties, } from './helpers.js';
7
7
  /**
8
8
  * @param {string} cron
9
9
  * @returns {boolean}
@@ -40,6 +40,24 @@ export const PRE_CASE_NORMALIZE_VALIDATIONS = [
40
40
  example: () => ({ build: { command: 'npm run build' } }),
41
41
  },
42
42
  ];
43
+ const edgeFunctionsUserProperties = validProperties(EDGE_FUNCTIONS_PROPERTIES, []);
44
+ // Validations performed only on the user's configuration file (`netlify.toml`),
45
+ // i.e. not on configuration coming from other origins such as the UI, the CLI,
46
+ // or the Frameworks API. This is where the schema is restricted to the subset
47
+ // of properties that users are allowed to set, excluding those reserved for
48
+ // platform-generated configuration (e.g. `generator`).
49
+ export const CONFIG_FILE_VALIDATIONS = [
50
+ {
51
+ property: 'edge_functions.*',
52
+ ...edgeFunctionsUserProperties,
53
+ // Structural problems, such as an entry that is not an object, are reported
54
+ // by the shared `edge_functions` validations, which run later. We only check
55
+ // the properties of actual objects here, so that those validations remain
56
+ // the ones surfacing a meaningful error.
57
+ check: (edgeFunction) => !isPlainObj(edgeFunction) || edgeFunctionsUserProperties.check(edgeFunction),
58
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
59
+ },
60
+ ];
43
61
  // Properties with an `origin` property need to be validated twice:
44
62
  // - Before the `origin` property is added
45
63
  // - After `context.*` is merged, since they might contain that property
@@ -191,6 +209,12 @@ export const POST_NORMALIZE_VALIDATIONS = [
191
209
  message: 'must be a string.',
192
210
  example: () => ({ build: { edge_functions: 'edge-functions' } }),
193
211
  },
212
+ {
213
+ property: 'spa_fallback',
214
+ check: isBoolean,
215
+ message: 'must be a boolean.',
216
+ example: () => ({ spa_fallback: true }),
217
+ },
194
218
  {
195
219
  property: 'functions.*',
196
220
  check: isPlainObj,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/config",
3
- "version": "25.1.0",
3
+ "version": "25.2.0",
4
4
  "description": "Netlify config module",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -96,5 +96,5 @@
96
96
  "engines": {
97
97
  "node": ">=22.12.0"
98
98
  },
99
- "gitHead": "0a4aa4be3f9abbb49ebe00e82c64898148986715"
99
+ "gitHead": "f34dd81fc3bc8925aabe5cf9c1cdce4e8eebc4e0"
100
100
  }