@adobe/helix-html-pipeline 6.27.23 → 6.27.25

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
+ ## [6.27.25](https://github.com/adobe/helix-html-pipeline/compare/v6.27.24...v6.27.25) (2026-03-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * better logging for xfh ([b09cf5d](https://github.com/adobe/helix-html-pipeline/commit/b09cf5de887f56aadebf6db37812910a9d45f7e2))
7
+
8
+ ## [6.27.24](https://github.com/adobe/helix-html-pipeline/compare/v6.27.23...v6.27.24) (2026-03-10)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **init-config:** warn when cdn.prod.host is absent and x-forwarded-host fallback is used ([#1038](https://github.com/adobe/helix-html-pipeline/issues/1038)) ([ba213ab](https://github.com/adobe/helix-html-pipeline/commit/ba213ab6a989697927c85578d06af1e5afeae229))
14
+
1
15
  ## [6.27.23](https://github.com/adobe/helix-html-pipeline/compare/v6.27.22...v6.27.23) (2026-02-22)
2
16
 
3
17
 
package/CLAUDE.md ADDED
@@ -0,0 +1,75 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ npm test # Run tests with c8 code coverage
9
+ npm run lint # Run ESLint
10
+ npm ci # Install dependencies (CI-style)
11
+ ```
12
+
13
+ Run a single test file:
14
+ ```bash
15
+ npx mocha test/html-pipe.test.js
16
+ ```
17
+
18
+ Run a specific test by name (grep):
19
+ ```bash
20
+ npx mocha --grep "test name" test/rendering.test.js
21
+ ```
22
+
23
+ ## Architecture
24
+
25
+ This is a platform-neutral (Node + Cloudflare Worker) library for rendering Helix3 HTML responses. It serves as shared code between `helix-pipeline-service` and `helix-cloudflare-page`.
26
+
27
+ ### Entry Points (Pipe Functions)
28
+
29
+ Each HTTP response type has a dedicated "pipe" function:
30
+ - **`htmlPipe`** (`src/html-pipe.js`) — Markdown → HTML rendering pipeline (30+ steps)
31
+ - **`jsonPipe`** (`src/json-pipe.js`) — JSON response pipeline with folder mapping
32
+ - **`optionsPipe`** (`src/options-pipe.js`) — HTTP OPTIONS method handler
33
+ - **`robotsPipe`** (`src/robots-pipe.js`) — `robots.txt` generation
34
+ - **`sitemapPipe`** (`src/sitemap-pipe.js`) — XML sitemap generation
35
+
36
+ ### Core Classes
37
+
38
+ - **`PipelineState`** — Execution context; holds org, site, repo, owner, ref, partition, metadata, headers, and content
39
+ - **`PipelineRequest`** / **`PipelineResponse`** — HTTP request/response wrappers
40
+ - **`PipelineContent`** — Content container (source markdown, parsed AST, rendered HTML)
41
+ - **`PipelineStatusError`** — Custom error for pipeline-specific HTTP status codes
42
+
43
+ ### Pipeline Steps Pattern
44
+
45
+ Each step is an async function with signature `(state, req?, res?) => void`. Steps live in `src/steps/` and are composed in sequence within each pipe function. Categories:
46
+ - **Content fetching**: `fetch-content.js`, `fetch-404.js`, `fetch-sourced-metadata.js`
47
+ - **Markdown processing**: `parse-markdown.js`, `split-sections.js`
48
+ - **HTML transformation**: `make-html.js`, `create-page-blocks.js`, `create-pictures.js`, `extract-metadata.js`
49
+ - **URL rewriting**: `rewrite-urls.js`, `rewrite-icons.js`
50
+ - **Response formatting**: `stringify-response.js`, `render.js`, `render-code.js`
51
+
52
+ ### AST Processing
53
+
54
+ Uses the `unified` ecosystem (remark for Markdown, rehype for HTML). The conversion path is: raw Markdown → mdast (via `remark-parse`) → hast (via custom `mdast-to-hast.js`) → serialized HTML (via `rehype-stringify`). Custom handling in `src/utils/mdast-to-hast.js` and `src/utils/hast-utils.js`.
55
+
56
+ ### Platform Abstraction
57
+
58
+ Crypto operations use `src/utils/crypto.node.js` vs `src/utils/crypto.worker.js` to stay compatible with both Node.js and Cloudflare Worker runtimes. No Node-specific or browser-specific modules should be added as runtime dependencies.
59
+
60
+ ### Content Sources
61
+
62
+ Content is fetched from two S3-backed sources:
63
+ - **Content bus** — Markdown and metadata (`.md`, `metadata.json`)
64
+ - **Code bus** — Templates, headers, footers, scripts
65
+
66
+ The S3 loader is injected into `PipelineState` and abstracted for testing via `test/FileS3Loader.js` and `test/StaticS3Loader.js`.
67
+
68
+ ## Testing
69
+
70
+ Tests use Mocha + c8. Test fixtures live in `test/fixtures/` organized by type (`content/`, `code/`, `json/`, `mdasts/`, `sections/`). The `test/setup-env.js` file initializes the test environment.
71
+
72
+ Key test files:
73
+ - `test/rendering.test.js` — Large integration tests for HTML rendering (49KB)
74
+ - `test/html-pipe.test.js` / `test/json-pipe.test.js` — Pipe-level integration tests
75
+ - `test/steps/` and `test/utils/` — Unit tests for individual modules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-html-pipeline",
3
- "version": "6.27.23",
3
+ "version": "6.27.25",
4
4
  "description": "Helix HTML Pipeline",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -70,12 +70,12 @@
70
70
  "unist-util-visit-parents": "6.0.2"
71
71
  },
72
72
  "devDependencies": {
73
- "@adobe/eslint-config-helix": "3.0.19",
73
+ "@adobe/eslint-config-helix": "3.0.21",
74
74
  "@eslint/config-helpers": "0.5.2",
75
75
  "@markedjs/html-differ": "5.0.4",
76
76
  "@semantic-release/changelog": "6.0.3",
77
77
  "@semantic-release/git": "10.0.1",
78
- "@semantic-release/npm": "13.1.3",
78
+ "@semantic-release/npm": "13.1.4",
79
79
  "c8": "10.1.3",
80
80
  "eslint": "9.4.0",
81
81
  "eslint-import-resolver-exports": "1.0.0-beta.5",
@@ -84,7 +84,7 @@
84
84
  "esmock": "2.7.3",
85
85
  "husky": "9.1.7",
86
86
  "js-yaml": "4.1.1",
87
- "jsdom": "28.0.0",
87
+ "jsdom": "28.1.0",
88
88
  "junit-report-builder": "5.1.1",
89
89
  "lint-staged": "16.2.7",
90
90
  "mocha": "11.7.5",
@@ -10,7 +10,7 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
  import { Modifiers } from '../utils/modifiers.js';
13
- import { getOriginalHost } from './utils.js';
13
+ import { getOriginalHost, getXFH } from './utils.js';
14
14
  import { recordLastModified } from '../utils/last-modified.js';
15
15
 
16
16
  function replaceParams(str, info) {
@@ -43,6 +43,11 @@ export default function initConfig(state, req, res) {
43
43
  // set custom preview and live hosts
44
44
  state.previewHost = replaceParams(config.cdn?.preview?.host, state);
45
45
  state.liveHost = replaceParams(config.cdn?.live?.host, state);
46
- state.prodHost = config.cdn?.prod?.host || getOriginalHost(req.headers);
46
+ const configuredProdHost = config.cdn?.prod?.host;
47
+ const xfh = getXFH(req.headers);
48
+ if (!configuredProdHost && xfh && !xfh.endsWith('.aem.page') && !xfh.endsWith('.aem.live')) {
49
+ state.log.warn(`[${state.org}/${state.site}] cdn.prod.host is not configured, falling back to x-forwarded-host: ${xfh}`);
50
+ }
51
+ state.prodHost = configuredProdHost || getOriginalHost(req.headers);
47
52
  recordLastModified(state, res, 'config', state.config.lastModified);
48
53
  }
@@ -17,11 +17,11 @@ const MEDIA_BLOB_REGEXP = /^https:\/\/.*\.(aem|hlx3?)\.(live|page)\/media_.*/;
17
17
  const HELIX_URL_REGEXP = /^https:\/\/.*\.(aem|hlx3?)\.(live|page)\/?.*/;
18
18
 
19
19
  /**
20
- * Returns the original host name from the request to the outer CDN.
20
+ * Returns the x-forwarded-host from the header
21
21
  * @param {object} headers The request headers
22
22
  * @returns {string} The original host
23
23
  */
24
- export function getOriginalHost(headers) {
24
+ export function getXFH(headers) {
25
25
  const xfh = headers.get('x-forwarded-host');
26
26
  if (xfh) {
27
27
  const segs = xfh.split(',');
@@ -32,7 +32,16 @@ export function getOriginalHost(headers) {
32
32
  }
33
33
  }
34
34
  }
35
- return headers.get('host');
35
+ return '';
36
+ }
37
+
38
+ /**
39
+ * Returns the original host name from the request to the outer CDN.
40
+ * @param {object} headers The request headers
41
+ * @returns {string} The original host
42
+ */
43
+ export function getOriginalHost(headers) {
44
+ return getXFH(headers) || headers.get('host');
36
45
  }
37
46
 
38
47
  /**