@redpanda-data/docs-extensions-and-macros 5.3.7 → 5.7.1

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.
Files changed (35) hide show
  1. package/cli-utils/github-token.js +56 -6
  2. package/extensions/add-faq-structured-data.js +3 -0
  3. package/extensions/add-git-dates.js +3 -0
  4. package/extensions/add-global-attributes.js +2 -0
  5. package/extensions/add-llms-directive.js +3 -0
  6. package/extensions/add-markdown-urls-to-sitemap.js +3 -0
  7. package/extensions/add-pages-to-root.js +2 -0
  8. package/extensions/aggregate-terms.js +2 -0
  9. package/extensions/algolia-indexer/index.js +2 -0
  10. package/extensions/archive-attachments.js +2 -0
  11. package/extensions/collect-bloblang-samples.js +2 -0
  12. package/extensions/compute-end-of-life.js +3 -0
  13. package/extensions/conditional-home-redirect.js +3 -0
  14. package/extensions/convert-llms-to-txt.js +3 -0
  15. package/extensions/convert-to-markdown.js +2 -0
  16. package/extensions/find-related-docs.js +3 -0
  17. package/extensions/find-related-labs.js +3 -0
  18. package/extensions/generate-fields-only-pages.js +3 -0
  19. package/extensions/generate-index-data.js +3 -0
  20. package/extensions/generate-rp-connect-categories.js +3 -0
  21. package/extensions/generate-rp-connect-info.js +3 -0
  22. package/extensions/git-full-clone.js +30 -2
  23. package/extensions/modify-connect-tag-playbook.js +3 -0
  24. package/extensions/process-context-switcher.js +3 -0
  25. package/extensions/produce-redirects.js +3 -0
  26. package/extensions/replace-attributes-in-attachments.js +3 -0
  27. package/extensions/resolve-xrefs-in-attachments.js +3 -0
  28. package/extensions/set-available-attachment-versions.js +3 -0
  29. package/extensions/unified-navigation.js +3 -0
  30. package/extensions/unlisted-pages.js +3 -0
  31. package/extensions/unpublish-pages.js +3 -0
  32. package/extensions/util/raise-listener-limit.js +28 -0
  33. package/extensions/validate-attributes.js +3 -0
  34. package/extensions/version-fetcher/set-latest-version.js +3 -0
  35. package/package.json +1 -1
@@ -5,19 +5,68 @@
5
5
  * Supports multiple common token variable names with priority order.
6
6
  */
7
7
 
8
+ /**
9
+ * Extract a GitHub token from the GIT_CREDENTIALS environment variable.
10
+ *
11
+ * GIT_CREDENTIALS is the variable Antora's own credential manager reads, so in
12
+ * Antora builds (for example, Netlify) it is the source guaranteed to hold a
13
+ * working credential for private content sources. Entries follow the git
14
+ * credential store format and may be separated by commas or newlines:
15
+ *
16
+ * https://<token>:@github.com
17
+ * https://<username>:<password>@github.com
18
+ * https://x-access-token:<token>@github.com
19
+ *
20
+ * @param {string} [credentials] - Credential contents (defaults to process.env.GIT_CREDENTIALS)
21
+ * @returns {string|null} GitHub token or null if no github.com entry found
22
+ */
23
+ function getTokenFromGitCredentials(credentials = process.env.GIT_CREDENTIALS) {
24
+ if (!credentials) return null;
25
+
26
+ for (const entry of credentials.split(/[,\n]/)) {
27
+ const match = entry.trim().match(/^https?:\/\/([^@]+)@([^/]+)/);
28
+ // Exact host match (optional port) so entries for lookalike hosts such as
29
+ // github.com.evil.example or notgithub.com are never treated as GitHub.
30
+ if (!match || !/^github\.com(:\d+)?$/i.test(match[2])) continue;
31
+
32
+ const [username, ...passwordParts] = match[1].split(':');
33
+ const password = passwordParts.join(':');
34
+
35
+ // Token may sit in the username position (https://TOKEN:@github.com) or,
36
+ // when a username such as x-access-token is present, in the password position.
37
+ const token = password || username;
38
+ if (!token) continue;
39
+
40
+ try {
41
+ return decodeURIComponent(token);
42
+ } catch (err) {
43
+ return token;
44
+ }
45
+ }
46
+
47
+ return null;
48
+ }
49
+
8
50
  /**
9
51
  * Get GitHub token from environment variables
10
52
  * Checks multiple common variable names in priority order:
11
- * 1. REDPANDA_GITHUB_TOKEN - Custom Redpanda token
12
- * 2. ACTIONS_BOT_TOKEN - GitHub Actions bot token
13
- * 3. GITHUB_TOKEN - GitHub Actions default
14
- * 4. VBOT_GITHUB_API_TOKEN - Legacy bot token
15
- * 5. GH_TOKEN - GitHub CLI default
53
+ * 1. GIT_CREDENTIALS - Antora's credential store contents (github.com entry)
54
+ * 2. REDPANDA_GITHUB_TOKEN - Custom Redpanda token
55
+ * 3. ACTIONS_BOT_TOKEN - GitHub Actions bot token
56
+ * 4. GITHUB_TOKEN - GitHub Actions default
57
+ * 5. VBOT_GITHUB_API_TOKEN - Legacy bot token
58
+ * 6. GH_TOKEN - GitHub CLI default
59
+ *
60
+ * Note: this resolver feeds both git clone/fetch auth and GitHub API clients
61
+ * (Octokit). Wherever GIT_CREDENTIALS is set (for example, Antora builds on
62
+ * Netlify), API calls authenticate with that same token, whose API scopes may
63
+ * differ from the token env vars it outranks.
16
64
  *
17
65
  * @returns {string|null} GitHub token or null if not found
18
66
  */
19
67
  function getGitHubToken() {
20
- return process.env.REDPANDA_GITHUB_TOKEN ||
68
+ return getTokenFromGitCredentials() ||
69
+ process.env.REDPANDA_GITHUB_TOKEN ||
21
70
  process.env.ACTIONS_BOT_TOKEN ||
22
71
  process.env.GITHUB_TOKEN ||
23
72
  process.env.VBOT_GITHUB_API_TOKEN ||
@@ -57,6 +106,7 @@ function hasGitHubToken() {
57
106
 
58
107
  module.exports = {
59
108
  getGitHubToken,
109
+ getTokenFromGitCredentials,
60
110
  getAuthenticatedGitHubUrl,
61
111
  hasGitHubToken
62
112
  };
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  /**
4
6
  * Generates FAQPage JSON-LD structured data for SEO.
5
7
  *
@@ -147,6 +149,7 @@ function generateFaqJsonLd(faqs, baseUrl) {
147
149
  }
148
150
 
149
151
  module.exports.register = function () {
152
+ raiseListenerLimit(this)
150
153
  const logger = this.getLogger('add-faq-structured-data-extension')
151
154
  let playbook
152
155
 
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  /**
4
6
  * Adds Git commit dates to pages as attributes.
5
7
  *
@@ -179,6 +181,7 @@ async function getTreeFiles (git, gitdir, oid, prefix, cache, treeCache) {
179
181
  }
180
182
 
181
183
  module.exports.register = function () {
184
+ raiseListenerLimit(this)
182
185
  const logger = this.getLogger('add-git-dates-extension')
183
186
  const context = this
184
187
 
@@ -1,3 +1,4 @@
1
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
1
2
  /* Example use in the playbook
2
3
  * antora:
3
4
  extensions:
@@ -12,6 +13,7 @@ const _ = require('lodash');
12
13
  const ATTRIBUTES_PATH = 'modules/ROOT/partials/'; // Default path within the 'shared' component
13
14
 
14
15
  module.exports.register = function ({ config }) {
16
+ raiseListenerLimit(this)
15
17
  const logger = this.getLogger('global-attributes-extension');
16
18
 
17
19
  /**
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  /**
4
6
  * Adds llms.txt directive to HTML pages for agent-friendly documentation.
5
7
  *
@@ -16,6 +18,7 @@
16
18
  const { formatLlmsDirective } = require('../extension-utils/llms-utils')
17
19
 
18
20
  module.exports.register = function () {
21
+ raiseListenerLimit(this)
19
22
  const logger = this.getLogger('add-llms-directive-extension')
20
23
 
21
24
  this.on('pagesComposed', ({ contentCatalog }) => {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  /**
4
6
  * Adds markdown URL entries to sitemap.xml files for AI-friendly documentation.
5
7
  *
@@ -21,6 +23,7 @@ const { parseStringPromise } = require('xml2js')
21
23
  const { toMarkdownUrl } = require('../extension-utils/url-utils')
22
24
 
23
25
  module.exports.register = function () {
26
+ raiseListenerLimit(this)
24
27
  const logger = this.getLogger('add-markdown-urls-to-sitemap-extension')
25
28
 
26
29
  this.on('beforePublish', async ({ siteCatalog }) => {
@@ -1,4 +1,6 @@
1
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
1
2
  module.exports.register = function ({ config }) {
3
+ raiseListenerLimit(this)
2
4
  this.on('beforePublish', ({ siteCatalog, contentCatalog }) => {
3
5
  const logger = this.getLogger('add-pages-to-site-root');
4
6
  if (!config || !config.files || !config.files.length) {
@@ -1,3 +1,4 @@
1
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
1
2
  /* Example use in the playbook
2
3
  * antora:
3
4
  extensions:
@@ -10,6 +11,7 @@ const path = require('path');
10
11
  const TERMS_PATH = 'modules/terms/partials/'; // Default path within the 'shared' component
11
12
 
12
13
  module.exports.register = function ({ config }) {
14
+ raiseListenerLimit(this)
13
15
  const logger = this.getLogger('term-aggregation-extension');
14
16
 
15
17
  /**
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const generateIndex = require('./generate-index')
4
+ const { raiseListenerLimit } = require('../util/raise-listener-limit')
4
5
  const algoliasearch = require('algoliasearch')
5
6
  const http = require('http')
6
7
  const https = require('https')
@@ -21,6 +22,7 @@ function register ({
21
22
  ...unknownOptions
22
23
  }
23
24
  }) {
25
+ raiseListenerLimit(this)
24
26
  const logger = this.getLogger('algolia-indexer-extension')
25
27
 
26
28
  // Validate required environment variables
@@ -1,3 +1,4 @@
1
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
1
2
  "use strict";
2
3
 
3
4
  const fs = require("fs");
@@ -35,6 +36,7 @@ async function createTarInMemory(tempDir) {
35
36
  }
36
37
 
37
38
  module.exports.register = function ({ config }) {
39
+ raiseListenerLimit(this)
38
40
  const logger = this.getLogger("archive-attachments-extension");
39
41
  const archives = config.data?.archives || [];
40
42
 
@@ -1,6 +1,8 @@
1
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
1
2
  const yaml = require('js-yaml');
2
3
 
3
4
  module.exports.register = function () {
5
+ raiseListenerLimit(this)
4
6
  const logger = this.getLogger('collect-bloblang-samples');
5
7
 
6
8
  this.on('contentClassified', ({ contentCatalog }) => {
@@ -1,8 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const calculateEOL = require('./util/calculate-eol.js');
4
6
 
5
7
  module.exports.register = function ({ config }) {
8
+ raiseListenerLimit(this)
6
9
  this.on('contentClassified', ({ contentCatalog }) => {
7
10
  const logger = this.getLogger("compute-end-of-life-extension");
8
11
 
@@ -8,7 +8,10 @@
8
8
 
9
9
  'use strict'
10
10
 
11
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
12
+
11
13
  module.exports.register = function () {
14
+ raiseListenerLimit(this)
12
15
  const logger = this.getLogger('conditional-home-redirect')
13
16
  let shouldRedirect = false
14
17
 
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const { toMarkdownUrl } = require('../extension-utils/url-utils');
4
6
  const { stripMarkdownMetadata } = require('../extension-utils/llms-utils');
5
7
 
@@ -20,6 +22,7 @@ const { stripMarkdownMetadata } = require('../extension-utils/llms-utils');
20
22
  * Must run after convert-to-markdown extension to access page.markdownContents.
21
23
  */
22
24
  module.exports.register = function () {
25
+ raiseListenerLimit(this)
23
26
  const logger = this.getLogger('convert-llms-to-txt-extension');
24
27
  let siteUrl = '';
25
28
 
@@ -1,3 +1,4 @@
1
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
1
2
  const path = require('path')
2
3
  const os = require('os')
3
4
  const yaml = require('js-yaml')
@@ -187,6 +188,7 @@ function generateFrontmatter(page) {
187
188
  }
188
189
 
189
190
  module.exports.register = function () {
191
+ raiseListenerLimit(this)
190
192
  const logger = this.getLogger('convert-to-markdown-extension')
191
193
  let playbook
192
194
 
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  module.exports.register = function ({ config }) {
6
+ raiseListenerLimit(this)
4
7
  const logger = this.getLogger('related-docs-extension');
5
8
 
6
9
  this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  module.exports.register = function ({ config }) {
6
+ raiseListenerLimit(this)
4
7
  const logger = this.getLogger('related-labs-extension');
5
8
 
6
9
  this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const fs = require('fs')
4
6
  const path = require('path')
5
7
  const os = require('os')
@@ -121,6 +123,7 @@ const DEFAULTS = {
121
123
  }
122
124
 
123
125
  module.exports.register = function ({ config }) {
126
+ raiseListenerLimit(this)
124
127
  const logger = this.getLogger('generate-fields-only-pages-extension')
125
128
 
126
129
  // Merge config with defaults
@@ -1,7 +1,10 @@
1
1
  'use strict';
2
+
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
2
4
  const _ = require('lodash');
3
5
 
4
6
  module.exports.register = function ({ config }) {
7
+ raiseListenerLimit(this)
5
8
  const logger = this.getLogger('generate-index-data-extension');
6
9
 
7
10
  this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  /**
4
6
  * Redpanda Connect Category Aggregation Extension
5
7
  *
@@ -11,6 +13,7 @@
11
13
  * Ensure generate-rp-connect-info is listed BEFORE this extension in your playbook.
12
14
  */
13
15
  module.exports.register = function ({ config }) {
16
+ raiseListenerLimit(this)
14
17
  const logger = this.getLogger('redpanda-connect-category-aggregation-extension')
15
18
 
16
19
  this.on('contentClassified', ({ contentCatalog }) => {
@@ -1,4 +1,6 @@
1
1
  'use strict'
2
+
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
2
4
  const fs = require('fs')
3
5
  const path = require('path')
4
6
  const Papa = require('papaparse')
@@ -11,6 +13,7 @@ const DEFAULTS = {
11
13
  }
12
14
 
13
15
  module.exports.register = function ({ config }) {
16
+ raiseListenerLimit(this)
14
17
  const logger = this.getLogger('redpanda-connect-info-extension')
15
18
  const { getAntoraValue } = require('../cli-utils/antora-utils')
16
19
 
@@ -1,8 +1,11 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const { execSync } = require('child_process')
4
6
  const fs = require('fs')
5
7
  const path = require('path')
8
+ const { getGitHubToken } = require('../cli-utils/github-token')
6
9
 
7
10
  /**
8
11
  * Configure Antora to use full git clones instead of shallow clones.
@@ -32,6 +35,7 @@ const path = require('path')
32
35
  */
33
36
 
34
37
  module.exports.register = function ({ config, playbook }) {
38
+ raiseListenerLimit(this)
35
39
  const logger = this.getLogger('git-full-clone-extension')
36
40
 
37
41
  logger.info('✓ git-full-clone extension loaded')
@@ -66,6 +70,30 @@ module.exports.register = function ({ config, playbook }) {
66
70
  let unshallowedCount = 0
67
71
  const unshallowTimeout = config?.unshallowTimeout || 60000 // Default 60 seconds per repo
68
72
 
73
+ // Private repos need credentials: the git CLI does not share Antora's
74
+ // built-in credential manager, so resolve a token (GIT_CREDENTIALS first,
75
+ // then the common token env vars) and hand it to git through a credential
76
+ // helper. Both the config and the token travel via environment variables
77
+ // (GIT_CONFIG_* and GIT_FULL_CLONE_TOKEN), so nothing touches the command
78
+ // line, the remote URL, or the cached .git/config, and there is no shell
79
+ // quoting to break on other platforms. Config entry 0 clears any inherited
80
+ // helpers; entry 1 registers a helper scoped to github.com so no other
81
+ // host is ever offered the token.
82
+ const token = getGitHubToken()
83
+ const gitCommand = 'git fetch --unshallow'
84
+ const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0' }
85
+ if (token) {
86
+ logger.info(' → Using GitHub token for unshallow fetches')
87
+ gitEnv.GIT_FULL_CLONE_TOKEN = token
88
+ gitEnv.GIT_CONFIG_COUNT = '2'
89
+ gitEnv.GIT_CONFIG_KEY_0 = 'credential.helper'
90
+ gitEnv.GIT_CONFIG_VALUE_0 = ''
91
+ gitEnv.GIT_CONFIG_KEY_1 = 'credential.https://github.com.helper'
92
+ gitEnv.GIT_CONFIG_VALUE_1 = '!f() { echo "username=x-access-token"; echo "password=$GIT_FULL_CLONE_TOKEN"; }; f'
93
+ } else {
94
+ logger.info(' → No GitHub token found; unshallow may fail for private repos')
95
+ }
96
+
69
97
  for (const aggregate of contentAggregate) {
70
98
  for (const origin of aggregate.origins || []) {
71
99
  const gitdir = origin.gitdir
@@ -80,11 +108,11 @@ module.exports.register = function ({ config, playbook }) {
80
108
  logger.info(` → Unshallowing ${path.basename(gitdir)}...`)
81
109
 
82
110
  // Use git fetch --unshallow to convert to full clone
83
- execSync('git fetch --unshallow', {
111
+ execSync(gitCommand, {
84
112
  cwd: gitdir,
85
113
  stdio: 'pipe',
86
114
  timeout: unshallowTimeout,
87
- env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }
115
+ env: gitEnv
88
116
  })
89
117
 
90
118
  const duration = Date.now() - startTime
@@ -1,8 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const GetLatestConnectTag = require('./version-fetcher/get-latest-connect');
4
6
 
5
7
  module.exports.register = function ({ config }) {
8
+ raiseListenerLimit(this)
6
9
  const logger = this.getLogger('modify-connect-tag-playbook-extension');
7
10
 
8
11
  this.on('contextStarted', async ({ playbook }) => {
@@ -17,7 +17,10 @@
17
17
 
18
18
  'use strict';
19
19
 
20
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
21
+
20
22
  module.exports.register = function ({ config }) {
23
+ raiseListenerLimit(this)
21
24
  const logger = this.getLogger('context-switcher-extension');
22
25
 
23
26
  this.on('documentsConverted', async ({ contentCatalog }) => {
@@ -1,11 +1,14 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const File = require('vinyl')
4
6
  const { posix: path } = require('path')
5
7
 
6
8
  const ENCODED_SPACE_RX = /%20/g
7
9
 
8
10
  module.exports.register = function () {
11
+ raiseListenerLimit(this)
9
12
  this.once('contextStarted', () => {
10
13
  const { publishFiles: produceRedirectsDelegate } = this.getFunctions()
11
14
  this.replaceFunctions({
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const semver = require('semver');
4
6
  const micromatch = require('micromatch');
5
7
  const formatVersion = require('./util/format-version.js');
@@ -24,6 +26,7 @@ const sanitize = require('./util/sanitize-attributes.js');
24
26
  * - ...
25
27
  */
26
28
  module.exports.register = function ({ config }) {
29
+ raiseListenerLimit(this)
27
30
  const logger = this.getLogger('replace-attributes-extension');
28
31
  const replacements = config.data?.replacements || [];
29
32
 
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  /**
4
6
  * Resolves AsciiDoc xrefs in JSON attachment files to HTML links.
5
7
  *
@@ -19,6 +21,7 @@
19
21
  */
20
22
 
21
23
  module.exports.register = function () {
24
+ raiseListenerLimit(this)
22
25
  const logger = this.getLogger('resolve-xrefs-in-attachments')
23
26
 
24
27
  this.on('contentClassified', ({ contentCatalog }) => {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const semver = require('semver')
4
6
 
5
7
  /**
@@ -34,6 +36,7 @@ const PROPERTIES_JSON_RX = /^redpanda-properties-(v\d+\.\d+\.\d+(?:-[\w.]+)?)\.j
34
36
  const CONNECT_JSON_RX = /^connect-(\d+\.\d+\.\d+(?:-[\w.]+)?)\.json$/
35
37
 
36
38
  module.exports.register = function () {
39
+ raiseListenerLimit(this)
37
40
  const logger = this.getLogger('set-available-attachment-versions-extension')
38
41
 
39
42
  this.once('contentClassified', ({ contentCatalog }) => {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  const yaml = require('js-yaml')
4
6
 
5
7
  /**
@@ -35,6 +37,7 @@ const yaml = require('js-yaml')
35
37
  */
36
38
 
37
39
  module.exports.register = function () {
40
+ raiseListenerLimit(this)
38
41
  const logger = this.getLogger('unified-navigation-extension')
39
42
 
40
43
  this.on('navigationBuilt', ({ contentCatalog }) => {
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  module.exports.register = function ({ config }) {
6
+ raiseListenerLimit(this)
4
7
  const { addToNavigation, unlistedPagesHeading = 'Unlisted Pages' } = config;
5
8
  const logger = this.getLogger('unlisted-pages-extension');
6
9
 
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
4
+
3
5
  module.exports.register = function () {
6
+ raiseListenerLimit(this)
4
7
  const logger = this.getLogger('unpublish-pages-extension');
5
8
 
6
9
  this.on('documentsConverted', ({ siteCatalog, contentCatalog }) => {
@@ -0,0 +1,28 @@
1
+ 'use strict'
2
+
3
+ // Antora's GeneratorContext is one shared EventEmitter for every registered
4
+ // extension, and Redpanda playbooks register enough of them that per-event
5
+ // listener counts legitimately exceed Node's default threshold of 10. Node
6
+ // then prints MaxListenersExceededWarning ("Possible EventEmitter memory
7
+ // leak detected. 11 contentClassified listeners added to [GeneratorContext]")
8
+ // in build logs even though each extension adds exactly one listener per
9
+ // event per build.
10
+ //
11
+ // Every extension in this package raises the limit before subscribing, so
12
+ // the suppression holds no matter which subset of extensions a playbook
13
+ // registers or in what order. The cap is bounded rather than unlimited (0)
14
+ // to keep Node's leak detection meaningful for pathological cases.
15
+ const GENERATOR_CONTEXT_MAX_LISTENERS = 64
16
+
17
+ function raiseListenerLimit (context) {
18
+ if (
19
+ typeof context.getMaxListeners === 'function' &&
20
+ typeof context.setMaxListeners === 'function' &&
21
+ context.getMaxListeners() !== 0 &&
22
+ context.getMaxListeners() < GENERATOR_CONTEXT_MAX_LISTENERS
23
+ ) {
24
+ context.setMaxListeners(GENERATOR_CONTEXT_MAX_LISTENERS)
25
+ }
26
+ }
27
+
28
+ module.exports = { raiseListenerLimit, GENERATOR_CONTEXT_MAX_LISTENERS }
@@ -6,7 +6,10 @@
6
6
 
7
7
  'use strict';
8
8
 
9
+ const { raiseListenerLimit } = require('./util/raise-listener-limit')
10
+
9
11
  module.exports.register = function ({ config }) {
12
+ raiseListenerLimit(this)
10
13
  const logger = this.getLogger('attribute-validation-extension');
11
14
 
12
15
  this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ const { raiseListenerLimit } = require('../util/raise-listener-limit')
4
+
3
5
  module.exports.register = function ({ config }) {
6
+ raiseListenerLimit(this)
4
7
  const GetLatestRedpandaVersion = require('./get-latest-redpanda-version');
5
8
  const GetLatestConsoleVersion = require('./get-latest-console-version');
6
9
  const GetLatestDockerTag = require('./fetch-latest-docker-tag');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "5.3.7",
3
+ "version": "5.7.1",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",