feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: create announcements banner - #617

Merged
ovflowd merged 39 commits into
mainfrom
feat/banners
Apr 16, 2026
Merged

feat: create announcements banner#617
ovflowd merged 39 commits into
mainfrom
feat/banners

Conversation

@araujogui

Copy link
Copy Markdown
Member

Description

Create announcements banner component

Validation

image

Related Issues

Fixes#327

Check List

  • I have read the Contributing Guidelines and made commit messages that follow the guideline.
  • I have run node --run test and all tests passed.
  • I have check code formatting with node --run format & node --run lint.
  • I've covered new added functionality with unit tests if necessary.

@araujogui
araujogui requested a review from a team as a code ownerFebruary 20, 2026 19:56
CopilotAI review requested due to automatic review settings February 20, 2026 19:56
@vercel

vercelBot commented Feb 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
api-docs-toolingReadyReadyPreviewApr 14, 2026 4:24pm

Request Review

@codecov

codecovBot commented Feb 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.05263% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.95%. Comparing base (58d8571) to head (5243f37).
⚠️ Report is 3 commits behind head on main.

Files with missing linesPatch %Lines
e2e/announcement-banner.spec.js0.00%66 Missing ⚠️
playwright.config.js0.00%14 Missing ⚠️
src/generators/web/utils/generate.mjs0.00%7 Missing ⚠️
src/generators/web/utils/config.mjs0.00%5 Missing ⚠️
src/generators/web/utils/processing.mjs0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #617 +/- ##
==========================================
- Coverage 78.44% 77.95% -0.49% 
==========================================
Files 157 159 +2 Lines 13967 14055 +88 Branches 1152 1152 ==========================================
+ Hits 10956 10957 +1 - Misses 3006 3093 +87 
Partials 5 5 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actionsBot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

web Generator

FileBaseHeadDiff
styles.css137.49 KB139.42 KB+1.93 KB (+1.40%)
addons.html262.76 KB262.77 KB+11.00 B (+0.00%)
assert.html330.20 KB330.21 KB+11.00 B (+0.00%)
async_context.html187.77 KB187.78 KB+11.00 B (+0.01%)
async_hooks.html159.91 KB159.92 KB+11.00 B (+0.01%)
buffer.html908.43 KB908.44 KB+11.00 B (+0.00%)
child_process.html381.89 KB381.91 KB+11.00 B (+0.00%)
cli.html501.86 KB501.87 KB+11.00 B (+0.00%)
cluster.html196.50 KB196.51 KB+11.00 B (+0.01%)
console.html146.97 KB146.98 KB+11.00 B (+0.01%)
crypto.html1.09 MB1.09 MB+11.00 B (+0.00%)
debugger.html54.42 KB54.43 KB+11.00 B (+0.02%)
deprecations.html505.55 KB505.56 KB+11.00 B (+0.00%)
dgram.html194.56 KB194.58 KB+11.00 B (+0.01%)
diagnostics_channel.html303.62 KB303.63 KB+11.00 B (+0.00%)
dns.html296.01 KB296.02 KB+11.00 B (+0.00%)
documentation.html38.24 KB38.25 KB+11.00 B (+0.03%)
domain.html105.30 KB105.31 KB+11.00 B (+0.01%)
embedding.html59.62 KB59.63 KB+11.00 B (+0.02%)
environment_variables.html44.24 KB44.25 KB+11.00 B (+0.02%)
errors.html461.85 KB461.87 KB+11.00 B (+0.00%)
esm.html155.54 KB155.55 KB+11.00 B (+0.01%)
events.html455.47 KB455.48 KB+11.00 B (+0.00%)
ffi.html116.78 KB116.79 KB+11.00 B (+0.01%)
fs.html1.43 MB1.43 MB+11.00 B (+0.00%)
globals.html230.58 KB230.59 KB+11.00 B (+0.00%)
http.html746.36 KB746.37 KB+11.00 B (+0.00%)
http2.html768.79 KB768.80 KB+11.00 B (+0.00%)
https.html150.55 KB150.56 KB+11.00 B (+0.01%)
index.html36.48 KB36.49 KB+11.00 B (+0.03%)
inspector.html171.58 KB171.59 KB+11.00 B (+0.01%)
intl.html58.34 KB58.35 KB+11.00 B (+0.02%)
module.html326.86 KB326.87 KB+11.00 B (+0.00%)
modules.html178.85 KB178.86 KB+11.00 B (+0.01%)
n-api.html807.45 KB807.46 KB+11.00 B (+0.00%)
net.html382.49 KB382.50 KB+11.00 B (+0.00%)
os.html142.93 KB142.94 KB+11.00 B (+0.01%)
packages.html154.85 KB154.86 KB+11.00 B (+0.01%)
path.html139.46 KB139.47 KB+11.00 B (+0.01%)
perf_hooks.html381.69 KB381.70 KB+11.00 B (+0.00%)
permissions.html55.84 KB55.85 KB+11.00 B (+0.02%)
process.html676.41 KB676.42 KB+11.00 B (+0.00%)
punycode.html63.39 KB63.40 KB+11.00 B (+0.02%)
querystring.html64.05 KB64.06 KB+11.00 B (+0.02%)
quic.html375.40 KB375.41 KB+11.00 B (+0.00%)
readline.html252.37 KB252.38 KB+11.00 B (+0.00%)
repl.html183.54 KB183.55 KB+11.00 B (+0.01%)
report.html176.11 KB176.13 KB+11.00 B (+0.01%)
single-executable-applications.html107.16 KB107.17 KB+11.00 B (+0.01%)
sqlite.html284.68 KB284.69 KB+11.00 B (+0.00%)
stream.html863.42 KB863.43 KB+11.00 B (+0.00%)
stream_iter.html352.58 KB352.59 KB+11.00 B (+0.00%)
string_decoder.html55.59 KB55.60 KB+11.00 B (+0.02%)
synopsis.html42.87 KB42.88 KB+11.00 B (+0.03%)
test.html783.85 KB783.86 KB+11.00 B (+0.00%)
timers.html133.70 KB133.71 KB+11.00 B (+0.01%)
tls.html373.99 KB374.00 KB+11.00 B (+0.00%)
tracing.html84.36 KB84.37 KB+11.00 B (+0.01%)
tty.html95.49 KB95.50 KB+11.00 B (+0.01%)
typescript.html53.67 KB53.68 KB+11.00 B (+0.02%)
url.html347.87 KB347.88 KB+11.00 B (+0.00%)
util.html695.97 KB695.98 KB+11.00 B (+0.00%)
v8.html339.30 KB339.31 KB+11.00 B (+0.00%)
vm.html371.00 KB371.01 KB+11.00 B (+0.00%)
wasi.html69.57 KB69.58 KB+11.00 B (+0.02%)
webcrypto.html522.20 KB522.21 KB+11.00 B (+0.00%)
webstreams.html357.40 KB357.42 KB+11.00 B (+0.00%)
worker_threads.html370.80 KB370.81 KB+11.00 B (+0.00%)
zlib.html290.44 KB290.45 KB+11.00 B (+0.00%)
zlib_iter.html88.26 KB88.27 KB+11.00 B (+0.01%)

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements an announcement banner component that fetches configuration from a remote JSON endpoint to display global and version-specific banners on the API documentation pages. The banners support date-based activation/deactivation and can include links to relevant resources.

Changes:

  • Added AnnouncementBanner component that asynchronously fetches and displays banners from a remote config
  • Implemented isBannerActive utility function to filter banners based on date ranges
  • Added versionMajor and remoteConfig fields to static data passed from server to client

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/generators/web/index.mjsAdds remote config URL to web generator default configuration
src/generators/web/types.d.tsAdds remoteConfig type definition for the web generator
src/generators/web/utils/data.mjsExtracts version major and remote config URL from server config to client static data
src/generators/web/constants.mjsRegisters AnnouncementBanner component in JSX imports map
src/generators/jsx-ast/utils/buildContent.mjsAdds AnnouncementBanner to document layout above navigation bar
src/generators/web/ui/utils/banner.mjsImplements date range checking logic for banner activation
src/generators/web/ui/utils/__tests__/banner.test.mjsComprehensive tests for banner date range logic
src/generators/web/ui/components/AnnouncementBanner/types.d.tsType definitions for banner entries and remote config structure
src/generators/web/ui/components/AnnouncementBanner/index.jsxMain component that fetches config and renders active banners

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
<div>
{banners.map(banner => (
<Banner key={banner.link} type={banner.type}>
{banner.link ? <a href={banner.link}>{banner.text}</a> : banner.text}

CopilotAIFeb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

External URLs from the remote config are used directly in href attributes without validation. While React/Preact provides some protection against javascript: protocol URLs, there's still a potential security risk if the remote config source is compromised. Consider validating that banner.link uses an approved protocol (https://) or implementing an allowlist of acceptable domains to ensure only trusted URLs are rendered. This is especially important since the config is fetched from an external source.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller@ovflowd what do you think? is this necessary? We don't do this on nodejs website

Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/index.mjs Outdated
Comment threadsrc/generators/web/types.d.ts Outdated
Comment threadsrc/generators/web/ui/components/AnnouncementBanner/index.jsx Outdated
Comment threadsrc/generators/web/utils/data.mjs Outdated
Comment threadsrc/generators/jsx-ast/utils/buildContent.mjs Outdated
Comment threadsrc/generators/web/index.mjs Outdated
@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

@ovflowd

Copy link
Copy Markdown
Member

(this also means that this spec cannot ever change or needs to be forever retroactively compatible)

@avivkeller

Copy link
Copy Markdown
Member

please be aware this must 100% be a client-side only component

It is

@araujogui

araujogui commented Feb 21, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

@araujogui

araujogui commented Feb 25, 2026

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

@araujogui

Copy link
Copy Markdown
MemberAuthor

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

@ovflowd

Copy link
Copy Markdown
Member

@araujogui please be aware this must 100% be a client-side only component. Since the value of this comes from being able to fetch this at page load, as docs are built only once for each version.

uh, that also means we can't change the config url, so we should already create the config file on nodejs/node?

Yeah... So we need to be very careful here 😓

We already have a site.json on website repo, having another config file on nodejs/node looks like duplication?

We can use site.json, but note that it is not publicly available, the link would either need to be through raw.githubusercontent.com or we'd need to move the file to be publicly available.

I think raw.githubusercontent.com is good enough

IDK about that...

@MattIPv4

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

@ovflowd

Copy link
Copy Markdown
Member

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

@araujogui

Copy link
Copy Markdown
MemberAuthor

I'd be fine with using raw.githubusercontent.com at build time (like we do via nodevu on the site), but I don't think we should be reliant on hitting it client-side every time someone loads a page on the site, that feels like abuse of GitHub's service. Can we have a JSON file accessible via the site, or an API endpiont?

We won't be loading this at build-time, cause it is supposed to be a client-side only, so it would hit indeed on every page load. I don't think raw.githubusercontent.com has cache headers so it would not be good.

Okay, maybe we could expose site.json in an endpoint of the website

@ovflowdovflowd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put a block on this for now as this needs to be done thoughtfully

@ovflowd
ovflowd merged commit 3d75c7a into mainApr 16, 2026
22 of 23 checks passed
@ovflowd
ovflowd deleted the feat/banners branch April 16, 2026 11:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement real-time (on-load) updates to API docs live-environment

6 participants

@araujogui@ovflowd@avivkeller@MattIPv4@canerakdas