@angular/build 20.3.15 → 20.3.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/build",
3
- "version": "20.3.15",
3
+ "version": "20.3.17",
4
4
  "description": "Official build system for Angular",
5
5
  "keywords": [
6
6
  "Angular CLI",
@@ -23,7 +23,7 @@
23
23
  "builders": "builders.json",
24
24
  "dependencies": {
25
25
  "@ampproject/remapping": "2.3.0",
26
- "@angular-devkit/architect": "0.2003.15",
26
+ "@angular-devkit/architect": "0.2003.17",
27
27
  "@babel/core": "7.28.3",
28
28
  "@babel/helper-annotate-as-pure": "7.27.3",
29
29
  "@babel/helper-split-export-declaration": "7.24.7",
@@ -60,7 +60,7 @@
60
60
  "@angular/platform-browser": "^20.0.0",
61
61
  "@angular/platform-server": "^20.0.0",
62
62
  "@angular/service-worker": "^20.0.0",
63
- "@angular/ssr": "^20.3.15",
63
+ "@angular/ssr": "^20.3.17",
64
64
  "karma": "^6.4.0",
65
65
  "less": "^4.2.0",
66
66
  "ng-packagr": "^20.0.0",
@@ -60,7 +60,7 @@ const i18n_1 = require("./i18n");
60
60
  const setup_bundling_1 = require("./setup-bundling");
61
61
  // eslint-disable-next-line max-lines-per-function
62
62
  async function executeBuild(options, context, rebuildState) {
63
- const { projectRoot, workspaceRoot, i18nOptions, optimizationOptions, assets, cacheOptions, serverEntryPoint, baseHref, ssrOptions, verbose, colors, jsonLogs, } = options;
63
+ const { projectRoot, workspaceRoot, i18nOptions, optimizationOptions, assets, cacheOptions, serverEntryPoint, baseHref, ssrOptions, verbose, colors, jsonLogs, security, } = options;
64
64
  // TODO: Consider integrating into watch mode. Would require full rebuild on target changes.
65
65
  const browsers = (0, supported_browsers_1.getSupportedBrowsers)(projectRoot, context.logger);
66
66
  // Load active translations if inlining
@@ -216,7 +216,7 @@ async function executeBuild(options, context, rebuildState) {
216
216
  }
217
217
  // Create server app engine manifest
218
218
  if (serverEntryPoint) {
219
- executionResult.addOutputFile(manifest_1.SERVER_APP_ENGINE_MANIFEST_FILENAME, (0, manifest_1.generateAngularServerAppEngineManifest)(i18nOptions, baseHref), bundler_context_1.BuildOutputFileType.ServerRoot);
219
+ executionResult.addOutputFile(manifest_1.SERVER_APP_ENGINE_MANIFEST_FILENAME, (0, manifest_1.generateAngularServerAppEngineManifest)(i18nOptions, security.allowedHosts, baseHref), bundler_context_1.BuildOutputFileType.ServerRoot);
220
220
  }
221
221
  // Perform i18n translation inlining if enabled
222
222
  if (i18nOptions.shouldInline) {
@@ -197,6 +197,7 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
197
197
  externalRuntimeStyles: boolean | undefined;
198
198
  instrumentForCoverage: ((filename: string) => boolean) | undefined;
199
199
  security: {
200
+ allowedHosts: string[];
200
201
  autoCsp: {
201
202
  unsafeEval: boolean;
202
203
  } | undefined;
@@ -247,8 +247,9 @@ async function normalizeOptions(context, projectName, options, extensions) {
247
247
  throw new Error('The "index" option cannot be set to false when enabling "ssr", "prerender" or "app-shell".');
248
248
  }
249
249
  }
250
- const autoCsp = options.security?.autoCsp;
250
+ const { autoCsp, allowedHosts = [] } = options.security ?? {};
251
251
  const security = {
252
+ allowedHosts,
252
253
  autoCsp: autoCsp
253
254
  ? {
254
255
  unsafeEval: autoCsp === true ? false : !!autoCsp.unsafeEval,
@@ -496,6 +496,12 @@ export type ScriptClass = {
496
496
  * Security features to protect against XSS and other common attacks
497
497
  */
498
498
  export type Security = {
499
+ /**
500
+ * A list of hostnames that are allowed to access the server-side application. For more
501
+ * information, see
502
+ * https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf.
503
+ */
504
+ allowedHosts?: string[];
499
505
  /**
500
506
  * Enables automatic generation of a hash-based Strict Content Security Policy
501
507
  * (https://web.dev/articles/strict-csp#choose-hash) based on scripts in index.html. Will
@@ -52,6 +52,14 @@
52
52
  "type": "object",
53
53
  "additionalProperties": false,
54
54
  "properties": {
55
+ "allowedHosts": {
56
+ "description": "A list of hostnames that are allowed to access the server-side application. For more information, see https://angular.dev/best-practices/security#preventing-server-side-request-forgery-ssrf.",
57
+ "type": "array",
58
+ "uniqueItems": true,
59
+ "items": {
60
+ "type": "string"
61
+ }
62
+ },
55
63
  "autoCsp": {
56
64
  "description": "Enables automatic generation of a hash-based Strict Content Security Policy (https://web.dev/articles/strict-csp#choose-hash) based on scripts in index.html. Will default to true once we are out of experimental/preview phases.",
57
65
  "default": false,
@@ -84,7 +84,14 @@ async function* serveWithVite(serverOptions, builderName, builderAction, context
84
84
  browserOptions.ssr ||= true;
85
85
  }
86
86
  // Disable auto CSP.
87
+ const allowedHosts = Array.isArray(serverOptions.allowedHosts)
88
+ ? [...serverOptions.allowedHosts]
89
+ : [];
90
+ // Always allow the dev server host
91
+ allowedHosts.push(serverOptions.host);
87
92
  browserOptions.security = {
93
+ allowedHosts,
94
+ // Disable auto CSP.
88
95
  autoCsp: false,
89
96
  };
90
97
  // Disable JSON build stats.
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.normalizeCacheOptions = normalizeCacheOptions;
11
11
  const node_path_1 = require("node:path");
12
12
  /** Version placeholder is replaced during the build process with actual package version */
13
- const VERSION = '20.3.15';
13
+ const VERSION = '20.3.17';
14
14
  function hasCacheMetadata(value) {
15
15
  return (!!value &&
16
16
  typeof value === 'object' &&
@@ -19,10 +19,11 @@ export declare const SERVER_APP_ENGINE_MANIFEST_FILENAME = "angular-app-engine-m
19
19
  *
20
20
  * @param i18nOptions - The internationalization options for the application build. This
21
21
  * includes settings for inlining locales and determining the output structure.
22
+ * @param allowedHosts - A list of hosts that are allowed to access the server-side application.
22
23
  * @param baseHref - The base HREF for the application. This is used to set the base URL
23
24
  * for all relative URLs in the application.
24
25
  */
25
- export declare function generateAngularServerAppEngineManifest(i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], baseHref: string | undefined): string;
26
+ export declare function generateAngularServerAppEngineManifest(i18nOptions: NormalizedApplicationBuildOptions['i18nOptions'], allowedHosts: string[], baseHref: string | undefined): string;
26
27
  /**
27
28
  * Generates the server manifest for the standard Node.js environment.
28
29
  *
@@ -45,10 +45,11 @@ function escapeUnsafeChars(str) {
45
45
  *
46
46
  * @param i18nOptions - The internationalization options for the application build. This
47
47
  * includes settings for inlining locales and determining the output structure.
48
+ * @param allowedHosts - A list of hosts that are allowed to access the server-side application.
48
49
  * @param baseHref - The base HREF for the application. This is used to set the base URL
49
50
  * for all relative URLs in the application.
50
51
  */
51
- function generateAngularServerAppEngineManifest(i18nOptions, baseHref) {
52
+ function generateAngularServerAppEngineManifest(i18nOptions, allowedHosts, baseHref) {
52
53
  const entryPoints = {};
53
54
  const supportedLocales = {};
54
55
  if (i18nOptions.shouldInline && !i18nOptions.flatOutput) {
@@ -71,6 +72,7 @@ function generateAngularServerAppEngineManifest(i18nOptions, baseHref) {
71
72
  const manifestContent = `
72
73
  export default {
73
74
  basePath: '${basePath}',
75
+ allowedHosts: ${JSON.stringify(allowedHosts, undefined, 2)},
74
76
  supportedLocales: ${JSON.stringify(supportedLocales, undefined, 2)},
75
77
  entryPoints: {
76
78
  ${Object.entries(entryPoints)
@@ -126,6 +126,9 @@ async function renderPages(baseHref, sourcemap, serializableRouteTreeNode, maxTh
126
126
  hasSsrEntry: !!outputFilesForWorker['server.mjs'],
127
127
  },
128
128
  execArgv: workerExecArgv,
129
+ env: {
130
+ 'NG_ALLOWED_HOSTS': 'localhost',
131
+ },
129
132
  });
130
133
  try {
131
134
  const renderingPromises = [];
@@ -205,6 +208,9 @@ async function getAllRoutes(workspaceRoot, baseHref, outputFilesForWorker, asset
205
208
  hasSsrEntry: !!outputFilesForWorker['server.mjs'],
206
209
  },
207
210
  execArgv: workerExecArgv,
211
+ env: {
212
+ 'NG_ALLOWED_HOSTS': 'localhost',
213
+ },
208
214
  });
209
215
  try {
210
216
  const { serializedRouteTree, appShellRoute, errors } = await renderWorker.run({});
@@ -1,46 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.dev/license
7
- */
8
- import type { OutputFile } from 'esbuild';
9
- export declare const SERVER_APP_MANIFEST_FILENAME = "angular-app-manifest.mjs";
10
- export declare const SERVER_APP_ENGINE_MANIFEST_FILENAME = "angular-app-engine-manifest.mjs";
11
- export interface BuildOutputAsset {
12
- source: string;
13
- destination: string;
14
- }
15
- export interface InitialFileRecord {
16
- entrypoint: boolean;
17
- name?: string;
18
- type: 'script' | 'style';
19
- external?: boolean;
20
- serverFile: boolean;
21
- depth: number;
22
- }
23
- export declare enum BuildOutputFileType {
24
- Browser = 0,
25
- Media = 1,
26
- ServerApplication = 2,
27
- ServerRoot = 3,
28
- Root = 4
29
- }
30
- export interface BuildOutputFile extends OutputFile {
31
- type: BuildOutputFileType;
32
- readonly size: number;
33
- clone: () => BuildOutputFile;
34
- }
35
- export type PrerenderedRoutesRecord = Record<string, {
36
- headers?: Record<string, string>;
37
- }>;
38
- /**
39
- * A set of server-generated dependencies that are treated as external.
40
- *
41
- * These dependencies are marked as external because they are produced by a
42
- * separate bundling process and are not included in the primary bundle. This
43
- * ensures that these generated files are resolved from an external source rather
44
- * than being part of the main bundle.
45
- */
46
- export declare const SERVER_GENERATED_EXTERNALS: Set<string>;
@@ -1,33 +0,0 @@
1
- "use strict";
2
- /**
3
- * @license
4
- * Copyright Google LLC All Rights Reserved.
5
- *
6
- * Use of this source code is governed by an MIT-style license that can be
7
- * found in the LICENSE file at https://angular.dev/license
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.SERVER_GENERATED_EXTERNALS = exports.BuildOutputFileType = exports.SERVER_APP_ENGINE_MANIFEST_FILENAME = exports.SERVER_APP_MANIFEST_FILENAME = void 0;
11
- exports.SERVER_APP_MANIFEST_FILENAME = 'angular-app-manifest.mjs';
12
- exports.SERVER_APP_ENGINE_MANIFEST_FILENAME = 'angular-app-engine-manifest.mjs';
13
- var BuildOutputFileType;
14
- (function (BuildOutputFileType) {
15
- BuildOutputFileType[BuildOutputFileType["Browser"] = 0] = "Browser";
16
- BuildOutputFileType[BuildOutputFileType["Media"] = 1] = "Media";
17
- BuildOutputFileType[BuildOutputFileType["ServerApplication"] = 2] = "ServerApplication";
18
- BuildOutputFileType[BuildOutputFileType["ServerRoot"] = 3] = "ServerRoot";
19
- BuildOutputFileType[BuildOutputFileType["Root"] = 4] = "Root";
20
- })(BuildOutputFileType || (exports.BuildOutputFileType = BuildOutputFileType = {}));
21
- /**
22
- * A set of server-generated dependencies that are treated as external.
23
- *
24
- * These dependencies are marked as external because they are produced by a
25
- * separate bundling process and are not included in the primary bundle. This
26
- * ensures that these generated files are resolved from an external source rather
27
- * than being part of the main bundle.
28
- */
29
- exports.SERVER_GENERATED_EXTERNALS = new Set([
30
- './polyfills.server.mjs',
31
- './' + exports.SERVER_APP_MANIFEST_FILENAME,
32
- './' + exports.SERVER_APP_ENGINE_MANIFEST_FILENAME,
33
- ]);
@@ -1,12 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright Google LLC All Rights Reserved.
4
- *
5
- * Use of this source code is governed by an MIT-style license that can be
6
- * found in the LICENSE file at https://angular.dev/license
7
- */
8
- import type { OutputFile } from 'esbuild';
9
- import type { BuildOutputFile } from './esbuild-definitions';
10
- import { BuildOutputFileType } from './esbuild-definitions';
11
- export declare function createOutputFile(path: string, data: string | Uint8Array, type: BuildOutputFileType): BuildOutputFile;
12
- export declare function convertOutputFile(file: OutputFile, type: BuildOutputFileType): BuildOutputFile;
@@ -1,103 +0,0 @@
1
- "use strict";
2
- /**
3
- * @license
4
- * Copyright Google LLC All Rights Reserved.
5
- *
6
- * Use of this source code is governed by an MIT-style license that can be
7
- * found in the LICENSE file at https://angular.dev/license
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.createOutputFile = createOutputFile;
11
- exports.convertOutputFile = convertOutputFile;
12
- const node_crypto_1 = require("node:crypto");
13
- function createOutputFile(path, data, type) {
14
- if (typeof data === 'string') {
15
- let cachedContents = null;
16
- let cachedText = data;
17
- let cachedHash = null;
18
- return {
19
- path,
20
- type,
21
- get contents() {
22
- cachedContents ??= new TextEncoder().encode(data);
23
- return cachedContents;
24
- },
25
- set contents(value) {
26
- cachedContents = value;
27
- cachedText = null;
28
- },
29
- get text() {
30
- cachedText ??= new TextDecoder('utf-8').decode(this.contents);
31
- return cachedText;
32
- },
33
- get size() {
34
- return this.contents.byteLength;
35
- },
36
- get hash() {
37
- cachedHash ??= (0, node_crypto_1.createHash)('sha256')
38
- .update(cachedText ?? this.contents)
39
- .digest('hex');
40
- return cachedHash;
41
- },
42
- clone() {
43
- return createOutputFile(this.path, cachedText ?? this.contents, this.type);
44
- },
45
- };
46
- }
47
- else {
48
- let cachedContents = data;
49
- let cachedText = null;
50
- let cachedHash = null;
51
- return {
52
- get contents() {
53
- return cachedContents;
54
- },
55
- set contents(value) {
56
- cachedContents = value;
57
- cachedText = null;
58
- },
59
- path,
60
- type,
61
- get size() {
62
- return this.contents.byteLength;
63
- },
64
- get text() {
65
- cachedText ??= new TextDecoder('utf-8').decode(this.contents);
66
- return cachedText;
67
- },
68
- get hash() {
69
- cachedHash ??= (0, node_crypto_1.createHash)('sha256').update(this.contents).digest('hex');
70
- return cachedHash;
71
- },
72
- clone() {
73
- return createOutputFile(this.path, this.contents, this.type);
74
- },
75
- };
76
- }
77
- }
78
- function convertOutputFile(file, type) {
79
- let { contents: cachedContents } = file;
80
- let cachedText = null;
81
- return {
82
- get contents() {
83
- return cachedContents;
84
- },
85
- set contents(value) {
86
- cachedContents = value;
87
- cachedText = null;
88
- },
89
- hash: file.hash,
90
- path: file.path,
91
- type,
92
- get size() {
93
- return this.contents.byteLength;
94
- },
95
- get text() {
96
- cachedText ??= new TextDecoder('utf-8').decode(this.contents);
97
- return cachedText;
98
- },
99
- clone() {
100
- return convertOutputFile(this, this.type);
101
- },
102
- };
103
- }