@adobe/aem-cli 16.16.6 → 16.16.8

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.16.8](https://github.com/adobe/helix-cli/compare/v16.16.7...v16.16.8) (2025-12-01)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **deps:** update external fixes ([#2643](https://github.com/adobe/helix-cli/issues/2643)) ([7e571e2](https://github.com/adobe/helix-cli/commit/7e571e218eadfff67fb1e40480a91b0a45991d2c))
7
+
8
+ ## [16.16.7](https://github.com/adobe/helix-cli/compare/v16.16.6...v16.16.7) (2025-11-28)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **server:** transform plain text 401/403 to Chrome-compatible HTML for sidekick ([#2414](https://github.com/adobe/helix-cli/issues/2414)) ([a261c6d](https://github.com/adobe/helix-cli/commit/a261c6dfa7a44ae44cd68bcf65f1a3473e1607cb)), closes [#2601](https://github.com/adobe/helix-cli/issues/2601)
14
+
1
15
  ## [16.16.6](https://github.com/adobe/helix-cli/compare/v16.16.5...v16.16.6) (2025-11-26)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/aem-cli",
3
- "version": "16.16.6",
3
+ "version": "16.16.8",
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.35.0",
69
- "jose": "6.1.1",
69
+ "jose": "6.1.2",
70
70
  "livereload-js": "4.0.2",
71
71
  "node-fetch": "3.3.2",
72
72
  "open": "10.2.0",
@@ -78,11 +78,12 @@
78
78
  "shelljs": "0.10.0",
79
79
  "unified": "11.0.5",
80
80
  "uuid": "13.0.0",
81
+ "xdg-basedir": "5.1.0",
81
82
  "yargs": "18.0.0"
82
83
  },
83
84
  "devDependencies": {
84
85
  "@adobe/eslint-config-helix": "3.0.14",
85
- "@eslint/config-helpers": "0.4.2",
86
+ "@eslint/config-helpers": "0.5.0",
86
87
  "@semantic-release/changelog": "6.0.3",
87
88
  "@semantic-release/git": "10.0.1",
88
89
  "c8": "10.1.3",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "devDependencies": {
15
15
  "@adobe/eslint-config-helix": "^3.0.9",
16
- "@eslint/config-helpers": "0.4.2",
16
+ "@eslint/config-helpers": "0.5.0",
17
17
  "@esm-bundle/chai": "4.3.4-fix.0",
18
18
  "@web/test-runner": "0.20.2",
19
19
  "@web/test-runner-junit-reporter": "0.8.0",
@@ -39,6 +39,32 @@
39
39
  "eslint": "^9.0.0"
40
40
  }
41
41
  },
42
+ "node_modules/@adobe/eslint-config-helix/node_modules/@eslint/config-helpers": {
43
+ "version": "0.4.2",
44
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
45
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
46
+ "dev": true,
47
+ "license": "Apache-2.0",
48
+ "dependencies": {
49
+ "@eslint/core": "^0.17.0"
50
+ },
51
+ "engines": {
52
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
53
+ }
54
+ },
55
+ "node_modules/@adobe/eslint-config-helix/node_modules/@eslint/core": {
56
+ "version": "0.17.0",
57
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
58
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
59
+ "dev": true,
60
+ "license": "Apache-2.0",
61
+ "dependencies": {
62
+ "@types/json-schema": "^7.0.15"
63
+ },
64
+ "engines": {
65
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
66
+ }
67
+ },
42
68
  "node_modules/@babel/code-frame": {
43
69
  "version": "7.27.1",
44
70
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
@@ -122,29 +148,29 @@
122
148
  }
123
149
  },
124
150
  "node_modules/@eslint/config-helpers": {
125
- "version": "0.4.2",
126
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
127
- "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
151
+ "version": "0.5.0",
152
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.0.tgz",
153
+ "integrity": "sha512-OCt2pY98qw68AXjNDGn+9q3vnqvBh4OFTZWmzaWH2thEpAugBZCBDRMHZa7oGsX+/ZybKOiKjJ6XX1E8hxcxGg==",
128
154
  "dev": true,
129
155
  "license": "Apache-2.0",
130
156
  "dependencies": {
131
- "@eslint/core": "^0.17.0"
157
+ "@eslint/core": "^1.0.0"
132
158
  },
133
159
  "engines": {
134
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
160
+ "node": "^20.19.0 || ^22.13.0 || >=24"
135
161
  }
136
162
  },
137
163
  "node_modules/@eslint/config-helpers/node_modules/@eslint/core": {
138
- "version": "0.17.0",
139
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
140
- "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
164
+ "version": "1.0.0",
165
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.0.0.tgz",
166
+ "integrity": "sha512-PRfWP+8FOldvbApr6xL7mNCw4cJcSTq4GA7tYbgq15mRb0kWKO/wEB2jr+uwjFH3sZvEZneZyCUGTxsv4Sahyw==",
141
167
  "dev": true,
142
168
  "license": "Apache-2.0",
143
169
  "dependencies": {
144
170
  "@types/json-schema": "^7.0.15"
145
171
  },
146
172
  "engines": {
147
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
173
+ "node": "^20.19.0 || ^22.13.0 || >=24"
148
174
  }
149
175
  },
150
176
  "node_modules/@eslint/core": {
@@ -2988,6 +3014,32 @@
2988
3014
  "url": "https://opencollective.com/eslint"
2989
3015
  }
2990
3016
  },
3017
+ "node_modules/eslint/node_modules/@eslint/config-helpers": {
3018
+ "version": "0.4.2",
3019
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
3020
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
3021
+ "dev": true,
3022
+ "license": "Apache-2.0",
3023
+ "dependencies": {
3024
+ "@eslint/core": "^0.17.0"
3025
+ },
3026
+ "engines": {
3027
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3028
+ }
3029
+ },
3030
+ "node_modules/eslint/node_modules/@eslint/config-helpers/node_modules/@eslint/core": {
3031
+ "version": "0.17.0",
3032
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
3033
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
3034
+ "dev": true,
3035
+ "license": "Apache-2.0",
3036
+ "dependencies": {
3037
+ "@types/json-schema": "^7.0.15"
3038
+ },
3039
+ "engines": {
3040
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3041
+ }
3042
+ },
2991
3043
  "node_modules/espree": {
2992
3044
  "version": "10.4.0",
2993
3045
  "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "devDependencies": {
15
15
  "@adobe/eslint-config-helix": "^3.0.9",
16
- "@eslint/config-helpers": "0.4.2",
16
+ "@eslint/config-helpers": "0.5.0",
17
17
  "@esm-bundle/chai": "4.3.4-fix.0",
18
18
  "@web/test-runner": "0.20.2",
19
19
  "@web/test-runner-playwright": "0.11.1",
@@ -412,15 +412,15 @@ window.LiveReloadOptions = {
412
412
  return;
413
413
  }
414
414
 
415
- let textBody = await ret.text();
416
- textBody = `<html>
417
- <head><meta property="hlx:proxyUrl" content="${url}"></head>
418
- <body>
419
- <pre>${textBody}</pre>
420
- <p>Click <b><a href="${opts.loginPath}">here</a></b> to login.</p>
421
- </body>
422
- </html>
423
- `;
415
+ // Transform plain text 401/403 responses into Chrome-compatible HTML
416
+ // This allows the sidekick to recognize the error page and enable login
417
+ const statusText = ret.status === 401 ? '401 Unauthorized' : '403 Forbidden';
418
+ const escapedUrl = url
419
+ .replace(/&/g, '&amp;')
420
+ .replace(/"/g, '&quot;');
421
+
422
+ const textBody = `<html><head><meta name="color-scheme" content="light dark"><meta property="hlx:proxyUrl" content="${escapedUrl}"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">${statusText}</pre></body></html>`;
423
+
424
424
  respHeaders['content-type'] = 'text/html';
425
425
  res
426
426
  .set(respHeaders)
package/src/up.cmd.js CHANGED
@@ -17,6 +17,7 @@ import { HelixProject } from './server/HelixProject.js';
17
17
  import GitUtils from './git-utils.js';
18
18
  import pkgJson from './package.cjs';
19
19
  import { AbstractServerCommand } from './abstract-server.cmd.js';
20
+ import { checkForUpdates } from './update-check.js';
20
21
 
21
22
  export default class UpCommand extends AbstractServerCommand {
22
23
  withLiveReload(value) {
@@ -121,6 +122,11 @@ export default class UpCommand extends AbstractServerCommand {
121
122
  this.log.info(chalk`{yellow /_/ |_/_____/_/ /_/ /____/_/_/ /_/ /_/\\__,_/_/\\__,_/\\__/\\____/_/}`);
122
123
  this.log.info('');
123
124
 
125
+ // Check for updates asynchronously (non-blocking)
126
+ checkForUpdates('@adobe/aem-cli', pkgJson.version, this.log).catch(() => {
127
+ // Silently ignore errors
128
+ });
129
+
124
130
  const ref = await GitUtils.getBranch(this.directory);
125
131
  this._gitUrl = await GitUtils.getOriginURL(this.directory, { ref });
126
132
  if (!this._gitUrl) {
@@ -0,0 +1,125 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ import fs from 'fs/promises';
13
+ import path from 'path';
14
+ import os from 'os';
15
+ import semver from 'semver';
16
+ import chalk from 'chalk-template';
17
+ import { xdgCache } from 'xdg-basedir';
18
+ import { getFetch } from './fetch-utils.js';
19
+
20
+ /**
21
+ * Gets the path to the update check cache file using XDG base directories.
22
+ * @returns {string} Path to the cache file
23
+ */
24
+ function getUpdateCheckCacheFile() {
25
+ const cacheDir = xdgCache || path.join(os.homedir(), '.cache');
26
+ return path.join(cacheDir, 'aem-cli', 'last-update-check');
27
+ }
28
+
29
+ /**
30
+ * Checks if we should skip the update check based on the last check time.
31
+ * @returns {Promise<boolean>} True if we should skip the check
32
+ */
33
+ async function shouldSkipUpdateCheck() {
34
+ try {
35
+ const cacheFile = getUpdateCheckCacheFile();
36
+ const stats = await fs.stat(cacheFile);
37
+ const lastCheck = stats.mtime.getTime();
38
+ const now = Date.now();
39
+ const oneDayInMs = 24 * 60 * 60 * 1000;
40
+
41
+ return (now - lastCheck) < oneDayInMs;
42
+ } catch (error) {
43
+ // If file doesn't exist or any other error, we should check
44
+ return false;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Updates the last update check timestamp.
50
+ */
51
+ async function updateLastCheckTime() {
52
+ try {
53
+ const cacheFile = getUpdateCheckCacheFile();
54
+ const cacheDir = path.dirname(cacheFile);
55
+
56
+ // Ensure cache directory exists
57
+ await fs.mkdir(cacheDir, { recursive: true });
58
+
59
+ // Touch the file to update its mtime
60
+ await fs.writeFile(cacheFile, Date.now().toString());
61
+ } catch (error) {
62
+ // Silently ignore errors - this is not critical
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Checks if a newer version of the package is available on npm.
68
+ * @param {string} packageName - The npm package name to check
69
+ * @param {string} currentVersion - The current version of the package
70
+ * @param {object} logger - Logger instance for outputting messages
71
+ * @returns {Promise<void>}
72
+ */
73
+ export async function checkForUpdates(packageName, currentVersion, logger) {
74
+ try {
75
+ // Check if we should skip the update check (rate limiting)
76
+ if (await shouldSkipUpdateCheck()) {
77
+ return;
78
+ }
79
+
80
+ const fetch = getFetch();
81
+ const controller = new AbortController();
82
+ const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
83
+
84
+ const response = await fetch(`https://registry.npmjs.org/${packageName}`, {
85
+ signal: controller.signal,
86
+ });
87
+ clearTimeout(timeoutId);
88
+
89
+ if (!response.ok) {
90
+ // Silently fail if we can't check for updates
91
+ return;
92
+ }
93
+
94
+ const data = await response.json();
95
+ const latestVersion = data['dist-tags']?.latest;
96
+
97
+ if (latestVersion && semver.gt(latestVersion, currentVersion)) {
98
+ const boxWidth = 61;
99
+ const updateMsg = `Update available! ${currentVersion} → ${latestVersion}`;
100
+ const installMsg = `Run npm install -g ${packageName} to update`;
101
+
102
+ // Use String.padEnd() instead of manual padding calculation
103
+ const updatePadded = ` ${updateMsg}`.padEnd(boxWidth - 1);
104
+ const installPadded = ` ${installMsg}`.padEnd(boxWidth - 1);
105
+
106
+ logger.warn('');
107
+ logger.warn(chalk`{yellow ╭─────────────────────────────────────────────────────────────╮}`);
108
+ logger.warn(chalk`{yellow │ │}`);
109
+ logger.warn(chalk`{yellow │${updatePadded} │}`);
110
+ logger.warn(chalk`{yellow │${installPadded} │}`);
111
+ logger.warn(chalk`{yellow │ │}`);
112
+ logger.warn(chalk`{yellow ╰─────────────────────────────────────────────────────────────╯}`);
113
+ logger.warn('');
114
+ }
115
+
116
+ // Update the last check time after a successful check
117
+ await updateLastCheckTime();
118
+ } catch (error) {
119
+ // Silently fail - don't block the command if update check fails
120
+ // Only log in debug mode if available
121
+ if (logger.level === 'debug' || logger.level === 'silly') {
122
+ logger.debug(`Update check failed: ${error.message}`);
123
+ }
124
+ }
125
+ }