@adobe/aem-cli 16.16.32 → 16.17.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [16.17.0](https://github.com/adobe/helix-cli/compare/v16.16.33...v16.17.0) (2026-04-07)
2
+
3
+
4
+ ### Features
5
+
6
+ * **html-folder:** Add --html-mount flag to control URL path for html-folder serving ([#2697](https://github.com/adobe/helix-cli/issues/2697)) ([4ed1f4b](https://github.com/adobe/helix-cli/commit/4ed1f4bea996e2afcf79dd1fc94f2809689ed772))
7
+
8
+ ## [16.16.33](https://github.com/adobe/helix-cli/compare/v16.16.32...v16.16.33) (2026-04-06)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** update dependency jose to v6.2.2 ([#2701](https://github.com/adobe/helix-cli/issues/2701)) ([8c1ffd0](https://github.com/adobe/helix-cli/commit/8c1ffd093b29aa38a60fae7e43d9984bf3a6539f))
14
+
1
15
  ## [16.16.32](https://github.com/adobe/helix-cli/compare/v16.16.31...v16.16.32) (2026-04-02)
2
16
 
3
17
 
package/README.md CHANGED
@@ -79,13 +79,17 @@ This feature is especially helpful when:
79
79
  The `--html-folder` option enables serving HTML files without extensions, useful for previewing content changes when you don't have access to the authoring system.
80
80
 
81
81
  ```
82
- $ aem up --html-folder content
82
+ $ aem up --html-folder drafts # serves at /drafts/*
83
+ $ aem up --html-folder content --html-mount / # serves at /* (root)
84
+ $ aem up --html-folder drafts --html-mount /preview # serves at /preview/*
83
85
  ```
84
86
 
87
+ Use `--html-mount` to control the URL path where files are served. Without it, files are served at `/FOLDER/*`.
88
+
85
89
  This enables two features:
86
90
 
87
- 1. **Extension-less URLs**: Access `/content/page` to serve `content/page.html`
88
- 2. **Plain HTML with metadata**: Create `content/page.plain.html` files that are automatically wrapped with proper HTML structure and metadata processing
91
+ 1. **Extension-less URLs**: Access `/drafts/page` (or `/page` with root mount) to serve the corresponding `.html` file
92
+ 2. **Plain HTML with metadata**: Create `.plain.html` files that are automatically wrapped with proper HTML structure and metadata processing
89
93
 
90
94
  #### Plain HTML files (.plain.html)
91
95
 
@@ -181,7 +185,8 @@ If present, `ALL_PROXY` is used as fallback if there is no other match.
181
185
  | `--livereload` | `AEM_LIVERELOAD` | `true` | Enable automatic reloading of modified sources in browser. |
182
186
  | `--no-livereload` | `AEM_NO_LIVERELOAD` | `false` | Disable live-reload. |
183
187
  | `--forward-browser-logs` | `AEM_FORWARD_BROWSER_LOGS` | `false` | Forward browser console logs to terminal. |
184
- | `--html-folder` | `AEM_HTML_FOLDER` | undefined | Serve HTML files from folder without extensions. Supports .html and .plain.html files. |
188
+ | `--html-folder` | `AEM_HTML_FOLDER` | undefined | Serve HTML files from folder without extensions. |
189
+ | `--html-mount` | `AEM_HTML_MOUNT` | `/FOLDER` | URL path where html-folder files are served. |
185
190
  | `--open` | `AEM_OPEN` | `/` | Open a browser window at specified path after server start. |
186
191
  | `--no-open` | `AEM_NO_OPEN` | `false` | Disable automatic opening of browser window. |
187
192
  | `--tls-key` | `AEM_TLS_KEY` | undefined | Path to .key file (for enabling TLS) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/aem-cli",
3
- "version": "16.16.32",
3
+ "version": "16.17.0",
4
4
  "description": "AEM CLI",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -66,7 +66,7 @@
66
66
  "ignore": "7.0.5",
67
67
  "ini": "6.0.0",
68
68
  "isomorphic-git": "1.37.4",
69
- "jose": "6.2.1",
69
+ "jose": "6.2.2",
70
70
  "livereload-js": "4.0.2",
71
71
  "node-fetch": "3.3.2",
72
72
  "open": "11.0.0",
@@ -82,7 +82,7 @@
82
82
  "yargs": "18.0.0"
83
83
  },
84
84
  "devDependencies": {
85
- "@adobe/eslint-config-helix": "3.0.23",
85
+ "@adobe/eslint-config-helix": "3.0.24",
86
86
  "@eslint/config-helpers": "0.5.3",
87
87
  "@semantic-release/changelog": "6.0.3",
88
88
  "@semantic-release/git": "10.0.1",
@@ -22,9 +22,9 @@
22
22
  }
23
23
  },
24
24
  "node_modules/@adobe/eslint-config-helix": {
25
- "version": "3.0.23",
26
- "resolved": "https://registry.npmjs.org/@adobe/eslint-config-helix/-/eslint-config-helix-3.0.23.tgz",
27
- "integrity": "sha512-CdZ9ehUwq3HvEOSzo1VPHbWTNEEilCmyZkPJ7489pR6T5cCO1A1f/HU4PEsSwT7JOB5PrPhBWGZ2hW9leFZXmA==",
25
+ "version": "3.0.24",
26
+ "resolved": "https://registry.npmjs.org/@adobe/eslint-config-helix/-/eslint-config-helix-3.0.24.tgz",
27
+ "integrity": "sha512-JspRdcd9JVlIcj1FTVvX1+tP9QbgENUdjVUqQcYBS0KesLWgLemSWn3LL4bsBvO33QrGo/DySk3/0zFXRAWXRw==",
28
28
  "dev": true,
29
29
  "license": "Apache-2.0",
30
30
  "dependencies": {
@@ -86,16 +86,16 @@ export class HelixProject extends BaseProject {
86
86
  if (path.isAbsolute(value) || value.includes('..') || value.startsWith('/')) {
87
87
  throw new Error(`Invalid HTML folder name: ${value} only folders within the current workspace are allowed`);
88
88
  }
89
-
90
- this._htmlFolder = value;
91
- this._server.withHtmlFolder(value);
92
- } else {
93
89
  this._htmlFolder = value;
94
- this._server.withHtmlFolder(value);
95
90
  }
96
91
  return this;
97
92
  }
98
93
 
94
+ withHtmlMount(value) {
95
+ this._htmlMount = value;
96
+ return this;
97
+ }
98
+
99
99
  get proxyUrl() {
100
100
  return this._proxyUrl;
101
101
  }
@@ -142,6 +142,10 @@ export class HelixProject extends BaseProject {
142
142
  }
143
143
 
144
144
  async init() {
145
+ if (this._htmlFolder) {
146
+ const mount = this._htmlMount || `/${this._htmlFolder}`;
147
+ this._server.withHtmlFolder(this._htmlFolder, mount);
148
+ }
145
149
  await super.init();
146
150
  this._indexer = new Indexer()
147
151
  .withLogger(this._logger)
@@ -206,7 +210,7 @@ export class HelixProject extends BaseProject {
206
210
  await lstat(htmlFolderPath);
207
211
  this.log.debug(`Registered HTML folder for live-reload: ${this._htmlFolder}`);
208
212
  // Watch all HTML files in the folder - only .html extension
209
- this.liveReload.registerFiles([`${htmlFolderPath}/**/*.html`], `/${this._htmlFolder}/`);
213
+ this.liveReload.registerFiles([`${htmlFolderPath}/**/*.html`], this._server.mountPrefix);
210
214
  } catch (e) {
211
215
  this.log.error(`HTML folder '${this._htmlFolder}' does not exist`);
212
216
  throw new Error(`HTML folder '${this._htmlFolder}' does not exist`);
@@ -63,12 +63,17 @@ export class HelixServer extends BaseServer {
63
63
  return this;
64
64
  }
65
65
 
66
- withHtmlFolder(value) {
67
- // It's now sanitized in HelixProject.withHtmlFolder
68
- this._htmlFolder = value;
66
+ withHtmlFolder(folder, mount) {
67
+ this._htmlFolder = folder;
68
+ this._htmlMount = mount;
69
+ this._mountPrefix = mount.endsWith('/') ? mount : `${mount}/`;
69
70
  return this;
70
71
  }
71
72
 
73
+ get mountPrefix() {
74
+ return this._mountPrefix;
75
+ }
76
+
72
77
  async handleLogin(req, res) {
73
78
  const userAgent = req.headers['user-agent']?.toLowerCase();
74
79
  if (userAgent?.includes('safari') && !userAgent?.includes('chrome')) {
@@ -262,22 +267,15 @@ export class HelixServer extends BaseServer {
262
267
  * @param {Function} next next middleware
263
268
  */
264
269
  async handleHtmlFolderRequest(req, res, next) {
265
- if (!this._htmlFolder) {
266
- return next();
267
- }
268
-
269
- // Use Express's req.path for pathname extraction
270
270
  const pathname = req.path;
271
- const folderPrefix = `/${this._htmlFolder}/`;
272
271
 
273
- // Check if the request is for the HTML folder
274
- if (!pathname.startsWith(folderPrefix)) {
272
+ let relativePath;
273
+ if (pathname.startsWith(this._mountPrefix)) {
274
+ relativePath = pathname.slice(this._mountPrefix.length);
275
+ } else {
275
276
  return next();
276
277
  }
277
278
 
278
- // Extract the path within the HTML folder
279
- let relativePath = pathname.slice(folderPrefix.length);
280
-
281
279
  // Handle directory requests (trailing slash) by appending 'index'
282
280
  if (relativePath === '' || relativePath.endsWith('/')) {
283
281
  relativePath = `${relativePath}index`.replace(/\/+/g, '/');
@@ -452,10 +450,9 @@ export class HelixServer extends BaseServer {
452
450
 
453
451
  // Add HTML folder handler before the general proxy handler
454
452
  if (this._htmlFolder) {
455
- // Only handle GET requests for the HTML folder path
456
- const htmlFolderPattern = new RegExp(`^/${this._htmlFolder}/.*`);
457
- this.app.get(htmlFolderPattern, asyncHandler(this.handleHtmlFolderRequest.bind(this)));
458
- this.log.info(`Serving HTML files from folder: ${this._htmlFolder}`);
453
+ const mountPattern = new RegExp(`^${this._mountPrefix}.*`);
454
+ this.app.get(mountPattern, asyncHandler(this.handleHtmlFolderRequest.bind(this)));
455
+ this.log.info(`Serving HTML files from folder: ${this._htmlFolder} at ${this._htmlMount}`);
459
456
  }
460
457
 
461
458
  const handler = asyncHandler(this.handleProxyModeRequest.bind(this));
@@ -714,9 +714,15 @@ window.LiveReloadOptions = {
714
714
 
715
715
  // Build final metadata object with computed values
716
716
  const finalMetadata = { ...metadata };
717
- if (title) finalMetadata.title = title;
718
- if (description) finalMetadata.description = description;
719
- if (image) finalMetadata.image = image;
717
+ if (title) {
718
+ finalMetadata.title = title;
719
+ }
720
+ if (description) {
721
+ finalMetadata.description = description;
722
+ }
723
+ if (image) {
724
+ finalMetadata.image = image;
725
+ }
720
726
 
721
727
  // Remove special properties that shouldn't become meta tags
722
728
  delete finalMetadata['title:suffix'];
package/src/up.cmd.js CHANGED
@@ -56,11 +56,15 @@ export default class UpCommand extends AbstractServerCommand {
56
56
  }
57
57
 
58
58
  withHtmlFolder(value) {
59
- // Basic validation - detailed validation done in HelixProject
60
59
  this._htmlFolder = value;
61
60
  return this;
62
61
  }
63
62
 
63
+ withHtmlMount(value) {
64
+ this._htmlMount = value;
65
+ return this;
66
+ }
67
+
64
68
  async doStop() {
65
69
  await super.doStop();
66
70
  if (this._watcher) {
@@ -113,7 +117,8 @@ export default class UpCommand extends AbstractServerCommand {
113
117
  .withAllowInsecure(this._allowInsecure)
114
118
  .withSiteToken(this._siteToken)
115
119
  .withCookies(this._cookies)
116
- .withHtmlFolder(this._htmlFolder);
120
+ .withHtmlFolder(this._htmlFolder)
121
+ .withHtmlMount(this._htmlMount);
117
122
 
118
123
  this.log.info(chalk`{yellow ___ ________ ___ __ __ v${pkgJson.version}}`);
119
124
  this.log.info(chalk`{yellow / | / ____/ |/ / _____(_)___ ___ __ __/ /___ _/ /_____ _____}`);
package/src/up.js CHANGED
@@ -117,7 +117,12 @@ export default function up() {
117
117
  })
118
118
  .option('html-folder', {
119
119
  alias: 'htmlFolder',
120
- describe: 'Serve HTML files from this folder without extensions (e.g., /folder/file serves folder/file.html or folder/file.plain.html) use this to preview content changes if you do not have access to the authoring system',
120
+ describe: 'Serve HTML files from this folder without extensions. Defaults to serving at /FOLDER.',
121
+ type: 'string',
122
+ })
123
+ .option('html-mount', {
124
+ alias: 'htmlMount',
125
+ describe: 'URL path where html-folder files are served (e.g., / for root). Defaults to /FOLDER.',
121
126
  type: 'string',
122
127
  })
123
128
 
@@ -147,6 +152,7 @@ export default function up() {
147
152
  .withCache(argv.alphaCache)
148
153
  .withCookies(argv.cookies)
149
154
  .withHtmlFolder(argv.htmlFolder)
155
+ .withHtmlMount(argv.htmlMount)
150
156
  .run();
151
157
  },
152
158
  };