diff --git a/.github/javadoc/javadoc-footer.html b/.github/javadoc/javadoc-footer.html
new file mode 100644
index 0000000..487326d
--- /dev/null
+++ b/.github/javadoc/javadoc-footer.html
@@ -0,0 +1,44 @@
+
diff --git a/.github/javadoc/javadoc-header.html b/.github/javadoc/javadoc-header.html
new file mode 100644
index 0000000..2c86e91
--- /dev/null
+++ b/.github/javadoc/javadoc-header.html
@@ -0,0 +1,11 @@
+
diff --git a/.github/javadoc/javadoc-theme.css b/.github/javadoc/javadoc-theme.css
new file mode 100644
index 0000000..3f691d8
--- /dev/null
+++ b/.github/javadoc/javadoc-theme.css
@@ -0,0 +1,954 @@
+/* ============================================================
+ CustomNPC+ DBC Addon — Javadoc Theme (Javadoc 11)
+ Tokyo Night — Styled Edition
+ ============================================================ */
+
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
+
+:root {
+ /* ── Tokyo Night palette ── */
+ --bg: #1a1b26;
+ --bg2: #1f2335;
+ --bg3: #24283b;
+ --bg-elevated: #292e42;
+ --border: #3b4261;
+ --border2: #414868;
+ --text: #c0caf5;
+ --text-mid: #a9b1d6;
+ --text-dim: #565f89;
+ --green: #9ece6a;
+ --green-dim: rgba(158, 206, 106, 0.12);
+ --blue: #7aa2f7;
+ --blue-dim: rgba(122, 162, 247, 0.12);
+ --amber: #e0af68;
+ --amber-dim: rgba(224, 175, 104, 0.10);
+ --purple: #bb9af7;
+ --purple-dim: rgba(187, 154, 247, 0.10);
+ --cyan: #7dcfff;
+ --cyan-dim: rgba(125, 207, 255, 0.10);
+ --red: #f7768e;
+ --highlight-bg: rgba(122, 162, 247, 0.08);
+ --hover-bg: rgba(187, 154, 247, 0.08);
+ --nav-h: 44px;
+ --subnav-h: 36px;
+
+ /* ── Font stacks ── */
+ --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ --font-mono: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace;
+}
+
+* { box-sizing: border-box !important; }
+
+html, body {
+ height: 100%;
+}
+
+body {
+ background: var(--bg) !important;
+ color: var(--text) !important;
+ font-family: var(--font-mono) !important;
+ font-size: 13px !important;
+ line-height: 1.6 !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ min-height: 100vh !important;
+ display: flex !important;
+ flex-direction: column !important;
+}
+
+.skipNav { display: none !important; }
+
+/* ══════════════════════════════════════════════
+ NAVIGATION
+ ══════════════════════════════════════════════ */
+
+.fixedNav {
+ position: fixed !important;
+ top: 0 !important; left: 0 !important; right: 0 !important;
+ z-index: 100 !important;
+}
+
+/* Top bar — gradient accent stripe on top */
+.topNav {
+ position: relative !important;
+ background: var(--bg2) !important;
+ border-bottom: 1px solid var(--border) !important;
+ height: var(--nav-h) !important;
+ margin: 0 !important; padding: 0 !important;
+ display: flex !important;
+ align-items: stretch !important;
+ overflow: visible !important;
+}
+
+/* Gradient accent line across the very top */
+.topNav::before {
+ content: '' !important;
+ position: absolute !important;
+ top: 0 !important; left: 0 !important; right: 0 !important;
+ height: 2px !important;
+ background: linear-gradient(90deg, var(--blue), var(--purple), var(--cyan)) !important;
+ z-index: 10 !important;
+}
+
+/* Nav list — leave room on right for brand */
+.topNav > ul.navList {
+ list-style: none !important;
+ margin: 0 !important;
+ padding: 2px 0 0 8px !important;
+ padding-right: 320px !important;
+ display: flex !important;
+ align-items: stretch !important;
+ flex-shrink: 0 !important;
+}
+
+.topNav > ul.navList > li {
+ display: flex !important;
+ align-items: center !important;
+ margin: 0 !important;
+ padding: 0 16px !important;
+ height: var(--nav-h) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 12px !important;
+ font-weight: 500 !important;
+ white-space: nowrap !important;
+ text-transform: none !important;
+ letter-spacing: 0.01em !important;
+ color: var(--text-dim) !important;
+ border-bottom: 2px solid transparent !important;
+ transition: color 0.2s !important;
+}
+
+.topNav > ul.navList > li > a {
+ display: flex !important;
+ align-items: center !important;
+ height: var(--nav-h) !important;
+ margin: 0 -16px !important;
+ padding: 0 16px !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 12px !important;
+ font-weight: 500 !important;
+ text-decoration: none !important;
+ text-transform: none !important;
+ letter-spacing: 0.01em !important;
+ white-space: nowrap !important;
+ border-bottom: 2px solid transparent !important;
+ transition: color 0.2s, border-color 0.2s !important;
+}
+
+.topNav > ul.navList > li > a:hover {
+ color: var(--text) !important;
+ border-bottom-color: var(--purple) !important;
+ background: transparent !important;
+ text-shadow: none !important;
+ text-decoration: none !important;
+}
+
+/* Active item — gradient underline */
+.topNav > ul.navList > li.navBarCell1Rev {
+ color: var(--text) !important;
+ border-image: linear-gradient(90deg, var(--blue), var(--purple)) 1 !important;
+ border-bottom-width: 2px !important;
+ border-bottom-style: solid !important;
+}
+
+/* ── Brand — pinned to far right of topNav ── */
+.topNav > .aboutLanguage {
+ position: absolute !important;
+ top: 0 !important; right: 0 !important;
+ height: var(--nav-h) !important;
+ display: flex !important;
+ align-items: center !important;
+ gap: 12px !important;
+ padding: 0 16px !important;
+ background: var(--bg2) !important;
+ border-left: 1px solid var(--border) !important;
+ z-index: 5 !important;
+}
+
+/* Hide the duplicate in bottom nav */
+.bottomNav > .aboutLanguage,
+.bottomNav .aboutLanguage {
+ display: none !important;
+}
+
+#javadoc-header {
+ display: flex !important;
+ align-items: center !important;
+ gap: 12px !important;
+}
+
+.header-brand { text-decoration: none !important; }
+
+/* Brand title — gradient text */
+.header-title {
+ font-family: var(--font-ui) !important;
+ font-size: 14px !important;
+ font-weight: 700 !important;
+ background: linear-gradient(135deg, var(--blue), var(--purple)) !important;
+ -webkit-background-clip: text !important;
+ -webkit-text-fill-color: transparent !important;
+ background-clip: text !important;
+ line-height: 1.4 !important;
+ white-space: nowrap !important;
+}
+
+.header-title span {
+ display: block !important;
+ font-family: var(--font-mono) !important;
+ font-size: 9px !important;
+ font-weight: 400 !important;
+ background: none !important;
+ -webkit-text-fill-color: var(--text-dim) !important;
+ color: var(--text-dim) !important;
+ margin-top: 1px !important;
+ letter-spacing: 0.1em !important;
+ text-transform: uppercase !important;
+}
+
+.header-back {
+ display: inline-flex !important;
+ align-items: center !important;
+ text-decoration: none !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 11px !important;
+ font-weight: 500 !important;
+ padding: 5px 12px !important;
+ border: 1px solid var(--border2) !important;
+ border-radius: 6px !important;
+ white-space: nowrap !important;
+ transition: all 0.2s !important;
+}
+
+.header-back:hover {
+ color: var(--text) !important;
+ border-color: var(--purple) !important;
+ background: var(--purple-dim) !important;
+ text-decoration: none !important;
+ text-shadow: none !important;
+}
+
+/* ── Sub nav ── */
+.subNav {
+ background: var(--bg3) !important;
+ border-bottom: 1px solid var(--border) !important;
+ height: var(--subnav-h) !important;
+ margin: 0 !important;
+ padding: 0 14px !important;
+ display: flex !important;
+ align-items: center !important;
+ gap: 12px !important;
+ overflow: hidden !important;
+}
+
+/* Search first */
+.subNav > ul.navListSearch {
+ order: -1 !important;
+}
+
+.subNav ul,
+.subNav ul.navList,
+.subNav ul.subNavList,
+.subNav ul.navListSearch {
+ list-style: none !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ display: flex !important;
+ align-items: center !important;
+ gap: 0 !important;
+}
+
+.subNav li {
+ display: flex !important;
+ align-items: center !important;
+ font-family: var(--font-ui) !important;
+ font-size: 11px !important;
+ color: var(--text-dim) !important;
+ padding: 0 6px !important;
+ white-space: nowrap !important;
+ border: none !important;
+ height: auto !important;
+ text-transform: none !important;
+}
+
+.subNav a {
+ color: var(--blue) !important;
+ text-decoration: none !important;
+ font-size: 11px !important;
+ font-family: var(--font-ui) !important;
+ transition: color 0.15s !important;
+}
+
+.subNav a:hover { color: var(--purple) !important; text-shadow: none !important; }
+
+.subNav label {
+ font-family: var(--font-ui) !important;
+ font-size: 11px !important;
+ color: var(--text-dim) !important;
+ text-transform: none !important;
+ margin-right: 4px !important;
+}
+
+/* ══════════════════════════════════════════════
+ CONTENT
+ ══════════════════════════════════════════════ */
+
+main {
+ background: var(--bg) !important;
+ padding: 28px !important;
+ flex: 1 0 auto !important;
+}
+
+.contentContainer, div.contentContainer {
+ background: var(--bg) !important;
+ padding: 0 28px 0px !important;
+}
+
+.header {
+ padding: 0 28px 0 !important;
+ margin-bottom: 20px !important;
+}
+
+/* Subtitle under h1 on help/overview pages */
+.header .subTitle,
+div.subTitle {
+ color: var(--text-mid) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 13px !important;
+ line-height: 1.7 !important;
+ margin-top: 8px !important;
+}
+
+.packageLabelInType {
+ font-family: var(--font-mono) !important;
+ font-size: 11px !important;
+ color: var(--text-dim) !important;
+}
+
+/* ── Headings ── */
+h1, h2, h3, h4, h5, h6 {
+ font-family: var(--font-ui) !important;
+ font-weight: 600 !important;
+ line-height: 1.5 !important;
+ text-transform: none !important;
+ letter-spacing: -0.01em !important;
+}
+
+/* Page title — gradient accent bar */
+h1.title, h2.title {
+ font-size: 22px !important;
+ font-weight: 700 !important;
+ color: var(--text) !important;
+ border-bottom: none !important;
+ padding-bottom: 16px !important;
+ padding-left: 16px !important;
+ margin-bottom: 24px !important;
+ margin-top: 0 !important;
+ border-left: 4px solid transparent !important;
+ border-image: linear-gradient(180deg, var(--blue), var(--purple)) 1 !important;
+}
+
+/* Section h2 — colored panel */
+section > h2,
+li.blockList > section > h2 {
+ font-size: 14px !important;
+ color: var(--green) !important;
+ border-left: 3px solid var(--green) !important;
+ border-bottom: none !important;
+ padding: 10px 14px !important;
+ margin: 0 !important;
+ background: var(--green-dim) !important;
+}
+
+/* Generic h2 (table section headers like "Method Summary") */
+h2 {
+ font-size: 14px !important;
+ color: var(--amber) !important;
+ border-bottom: none !important;
+ border-left: 3px solid var(--amber) !important;
+ padding: 8px 12px !important;
+ margin-top: 28px !important;
+ margin-bottom: 12px !important;
+ background: var(--amber-dim) !important;
+}
+
+/* h3 — table section headers inside blockList */
+h3 {
+ font-size: 12px !important;
+ color: var(--text-mid) !important;
+ margin: 0 !important;
+ padding: 10px 14px !important;
+ background: var(--bg3) !important;
+ border-bottom: 1px solid var(--border) !important;
+}
+
+/* h4 — method detail names */
+h4 {
+ font-size: 13px !important;
+ font-weight: 600 !important;
+ color: var(--cyan) !important;
+ margin: 0 !important;
+ padding: 10px 14px !important;
+ background: var(--bg3) !important;
+ border-bottom: 1px solid var(--border) !important;
+ border-left: 3px solid var(--cyan) !important;
+}
+
+/* ── blockList sections — card-like containers ── */
+ul.blockList > li.blockList,
+ul.blockListLast > li.blockList {
+ border: 1px solid var(--border) !important;
+ border-radius: 6px !important;
+ margin-bottom: 14px !important;
+ padding: 0 !important;
+ background: var(--bg2) !important;
+ overflow: hidden !important;
+}
+
+/* Help page: section cards with padding around their content */
+ul.blockList > li.blockList > section {
+ padding: 0 !important;
+}
+
+ul.blockList > li.blockList > section > p,
+ul.blockList > li.blockList > section > ul:not(.blockList):not(.blockListLast) {
+ padding: 14px 18px !important;
+ margin: 0 !important;
+ color: var(--text-mid) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 13px !important;
+ line-height: 1.7 !important;
+}
+
+/* Nested lists inside section content */
+ul.blockList > li.blockList > section > ul:not(.blockList):not(.blockListLast) > li {
+ color: var(--text-mid) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 13px !important;
+ padding: 3px 0 !important;
+ list-style: none !important;
+}
+
+ul.blockList > li.blockList > section > ul:not(.blockList):not(.blockListLast) > li::before {
+ content: '\203A' !important;
+ color: var(--purple) !important;
+ margin-right: 8px !important;
+ font-weight: 700 !important;
+}
+
+/* ── Inherited methods block ── */
+ul.blockList > li.blockList > h3,
+ul.blockList > li.blockList > ul.blockList > li.blockList > h3 {
+ font-size: 11px !important;
+ color: var(--text-dim) !important;
+ padding: 8px 14px !important;
+ background: var(--bg3) !important;
+ border-bottom: 1px solid var(--border) !important;
+ margin: 0 !important;
+}
+
+/* The comma-separated code block of inherited method names */
+ul.blockList > li.blockList > code,
+li.blockList > code {
+ display: block !important;
+ padding: 10px 16px !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ background: var(--bg) !important;
+ border: none !important;
+ line-height: 1.8 !important;
+}
+
+/* ── Inheritance chain ── */
+ul.inheritance {
+ list-style: none !important;
+ padding: 0 !important;
+ margin: 0 0 16px !important;
+ font-size: 12px !important;
+ color: var(--text-dim) !important;
+}
+ul.inheritance li { padding-left: 16px !important; }
+ul.inheritance li:first-child { padding-left: 0 !important; }
+
+/* ── General content lists (help page) ── */
+main ul:not(.blockList):not(.blockListLast):not(.navList):not(.subNavList):not(.navListSearch):not(.inheritance) {
+ padding-left: 0 !important;
+ margin: 4px 0 4px 12px !important;
+ list-style: none !important;
+}
+main ul:not(.blockList):not(.blockListLast):not(.navList):not(.subNavList):not(.navListSearch):not(.inheritance) > li {
+ color: var(--text-mid) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 13px !important;
+ padding: 3px 0 !important;
+ line-height: 1.7 !important;
+}
+main ul:not(.blockList):not(.blockListLast):not(.navList):not(.subNavList):not(.navListSearch):not(.inheritance) > li::before {
+ content: '\203A' !important;
+ color: var(--purple) !important;
+ margin-right: 8px !important;
+ font-weight: 700 !important;
+}
+
+/* General paragraphs in content */
+main > div p, .contentContainer p {
+ color: var(--text-mid) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 13px !important;
+ line-height: 1.7 !important;
+ margin: 8px 0 !important;
+}
+
+/* Emphasized phrase */
+.emphasizedPhrase {
+ display: block !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ font-style: italic !important;
+ border-left: 2px solid var(--purple) !important;
+ padding: 8px 14px !important;
+ margin-top: 16px !important;
+ background: var(--purple-dim) !important;
+ border-radius: 0 4px 4px 0 !important;
+}
+
+/* Bottom footer subNav */
+footer {
+ /*margin-top: auto;*/
+}
+footer .subNav {
+ background: var(--bg3) !important;
+ border-top: 1px solid var(--border) !important;
+ border-bottom: none !important;
+ height: var(--subnav-h) !important;
+ padding: 0 14px !important;
+ display: flex !important;
+ align-items: center !important;
+ gap: 12px !important;
+ overflow: hidden !important;
+}
+
+/* ══════════════════════════════════════════════
+ TABLES
+ ══════════════════════════════════════════════ */
+
+table {
+ width: 100% !important;
+ border-collapse: collapse !important;
+ border: 1px solid var(--border) !important;
+ border-radius: 6px !important;
+ margin: 16px 0 !important;
+ font-size: 13px !important;
+ overflow: hidden !important;
+}
+
+caption {
+ background: var(--bg3) !important;
+ padding: 8px 14px !important;
+ text-align: left !important;
+ border-bottom: 1px solid var(--border2) !important;
+ caption-side: top !important;
+}
+
+/* Table tabs — pill style */
+.activeTableTab, .tableTab {
+ font-family: var(--font-ui) !important;
+ font-size: 11px !important;
+ font-weight: 500 !important;
+ text-transform: none !important;
+ padding: 4px 12px !important;
+ border: 1px solid var(--border2) !important;
+ border-radius: 20px !important;
+ display: inline-block !important;
+ margin-right: 6px !important;
+ cursor: pointer !important;
+ transition: all 0.2s !important;
+}
+
+.activeTableTab {
+ color: var(--text) !important;
+ border-color: var(--blue) !important;
+ background: var(--blue-dim) !important;
+}
+
+.tableTab { color: var(--text-dim) !important; background: var(--bg3) !important; }
+.tableTab a { color: var(--text-dim) !important; text-decoration: none !important; }
+.tableTab a:hover { color: var(--text) !important; text-shadow: none !important; }
+
+/* Column headers */
+th[scope="col"] {
+ background: var(--bg-elevated) !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 10px !important;
+ font-weight: 600 !important;
+ letter-spacing: 0.06em !important;
+ text-transform: uppercase !important;
+ padding: 10px 14px !important;
+ border-bottom: 2px solid var(--border2) !important;
+ text-align: left !important;
+}
+
+/* Data cells */
+th[scope="row"], td {
+ background: var(--bg2) !important;
+ color: var(--text) !important;
+ padding: 10px 14px !important;
+ border-bottom: 1px solid var(--border) !important;
+ vertical-align: top !important;
+ text-align: left !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ font-weight: 400 !important;
+ text-transform: none !important;
+ letter-spacing: 0 !important;
+ transition: background 0.15s !important;
+}
+
+/* Stronger alternating row contrast */
+tr.altColor > td, tr.altColor > th[scope="row"] { background: var(--bg) !important; }
+tr.rowColor > td, tr.rowColor > th[scope="row"] { background: var(--bg2) !important; }
+
+tr:hover > td, tr:hover > th[scope="row"] {
+ background: var(--purple-dim) !important;
+ border-bottom-color: rgba(187, 154, 247, 0.25) !important;
+}
+tr:hover > td a, tr:hover > th[scope="row"] a {
+ color: var(--purple) !important;
+}
+
+/* ── Links ── */
+a, a:visited { color: var(--blue) !important; text-decoration: none !important; transition: color 0.15s !important; }
+a:hover { color: var(--purple) !important; text-decoration: none !important; }
+.memberNameLink a { color: var(--cyan) !important; font-weight: 500 !important; }
+.memberNameLink a:hover { color: var(--purple) !important; }
+.externalLink { color: var(--blue) !important; }
+
+/* ── Description blocks ── */
+div.block {
+ color: var(--text-mid) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 13px !important;
+ line-height: 1.7 !important;
+ padding: 4px 0 !important;
+}
+ul.blockList > li.blockList > div.block{ padding: 12px 16px !important; margin: 0 !important; }
+
+/* ── Method detail ── */
+ul.blockList, ul.blockListLast { list-style: none !important; padding: 0 !important; margin: 0 !important; }
+ul.blockList > li.blockList, ul.blockListLast > li.blockList {
+ border: 1px solid var(--border) !important;
+ border-radius: 6px !important;
+ margin-bottom: 12px !important;
+ padding: 0 !important;
+ overflow: hidden !important;
+}
+
+/* Method/type signatures — accent left bar */
+pre.methodSignature, pre.typeSignature {
+ background: var(--bg2) !important;
+ border: none !important;
+ border-bottom: 1px solid var(--border) !important;
+ border-left: 3px solid var(--cyan) !important;
+ margin: 0 !important;
+ padding: 14px 18px !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ color: var(--text) !important;
+ overflow-x: auto !important;
+ white-space: pre-wrap !important;
+}
+
+pre {
+ background: var(--bg2) !important;
+ border: 1px solid var(--border) !important;
+ border-left: 3px solid var(--blue) !important;
+ border-radius: 6px !important;
+ padding: 14px 18px !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ color: var(--text) !important;
+ overflow-x: auto !important;
+ margin: 0 !important;
+ white-space: pre-wrap !important;
+}
+
+code {
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ color: var(--cyan) !important;
+ background: var(--bg3) !important;
+ padding: 2px 6px !important;
+ border-radius: 4px !important;
+}
+
+dl { padding: 12px 16px !important; margin: 0 !important; }
+dt { margin-bottom: 4px !important; }
+dd { margin: 0 0 8px 16px !important; color: var(--text-mid) !important; font-size: 12px !important; }
+
+.paramLabel, .returnLabel, .throwsLabel, .seeLabel, .simpleTagLabel {
+ font-family: var(--font-ui) !important;
+ font-size: 10px !important;
+ font-weight: 600 !important;
+ color: var(--purple) !important;
+ text-transform: uppercase !important;
+ letter-spacing: 0.06em !important;
+}
+
+.typeNameLabel { color: var(--cyan) !important; }
+
+.deprecationBlock {
+ background: var(--amber-dim) !important;
+ border-left: 3px solid var(--amber) !important;
+ border-radius: 0 6px 6px 0 !important;
+ padding: 10px 14px !important;
+ color: var(--amber) !important;
+ font-size: 12px !important;
+}
+
+/* ── Inputs ── */
+input[type="text"] {
+ background: var(--bg) !important;
+ border: 1px solid var(--border2) !important;
+ color: var(--text) !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ padding: 5px 12px !important;
+ outline: none !important;
+ border-radius: 6px !important;
+ transition: border-color 0.2s, box-shadow 0.2s !important;
+}
+input[type="text"]:focus {
+ border-color: var(--blue) !important;
+ box-shadow: 0 0 0 2px var(--blue-dim) !important;
+}
+input[type="reset"] {
+ background: var(--bg3) !important;
+ border: 1px solid var(--border2) !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 11px !important;
+ padding: 5px 12px !important;
+ cursor: pointer !important;
+ border-radius: 6px !important;
+ transition: all 0.2s !important;
+}
+input[type="reset"]:hover {
+ border-color: var(--text-dim) !important;
+ color: var(--text-mid) !important;
+}
+
+/* ══════════════════════════════════════════════
+ BOTTOM NAV
+ ══════════════════════════════════════════════ */
+
+.bottomNav {
+ background: var(--bg2) !important;
+ border-top: 1px solid var(--border) !important;
+ min-height: var(--nav-h) !important;
+ padding: 0 !important;
+ margin-top: 32px !important;
+ overflow: hidden !important;
+ position: relative !important;
+}
+
+/* Gradient accent line on bottom nav too */
+.bottomNav::after {
+ content: '' !important;
+ position: absolute !important;
+ bottom: 0 !important; left: 0 !important; right: 0 !important;
+ height: 2px !important;
+ background: linear-gradient(90deg, var(--blue), var(--purple), var(--cyan)) !important;
+}
+
+.bottomNav ul.navList[title="Navigation"] {
+ list-style: none !important;
+ margin: 0 !important;
+ padding: 0 0 0 8px !important;
+ display: flex !important;
+ align-items: stretch !important;
+ height: var(--nav-h) !important;
+}
+
+.bottomNav ul.navList[title="Navigation"] li {
+ display: flex !important;
+ align-items: center !important;
+ margin: 0 !important;
+ padding: 0 16px !important;
+ height: var(--nav-h) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 12px !important;
+ font-weight: 500 !important;
+ white-space: nowrap !important;
+ text-transform: none !important;
+ letter-spacing: 0.01em !important;
+ color: var(--text-dim) !important;
+ border-top: 2px solid transparent !important;
+ transition: color 0.2s !important;
+}
+
+.bottomNav ul.navList[title="Navigation"] li > a {
+ display: flex !important;
+ align-items: center !important;
+ height: var(--nav-h) !important;
+ margin: 0 -16px !important;
+ padding: 0 16px !important;
+ color: var(--text-dim) !important;
+ text-decoration: none !important;
+ font-family: var(--font-ui) !important;
+ font-size: 12px !important;
+ font-weight: 500 !important;
+ transition: color 0.2s !important;
+}
+
+.bottomNav ul.navList[title="Navigation"] li > a:hover {
+ color: var(--text) !important;
+ text-shadow: none !important;
+}
+
+.bottomNav ul.navList[title="Navigation"] li.navBarCell1Rev {
+ color: var(--text) !important;
+ border-image: linear-gradient(90deg, var(--blue), var(--purple)) 1 !important;
+ border-top-width: 2px !important;
+ border-top-style: solid !important;
+}
+
+.bottomNav .aboutLanguage {
+ display: none !important;
+}
+
+.legalCopy {
+ background: var(--bg2) !important;
+ color: var(--text-dim) !important;
+ font-size: 11px !important;
+ font-family: var(--font-ui) !important;
+ padding: 14px 18px !important;
+ text-align: center !important;
+ border-top: 1px solid var(--border) !important;
+}
+
+/* ══════════════════════════════════════════════
+ SEARCH RESULTS DROPDOWN (jQuery UI Autocomplete)
+ ══════════════════════════════════════════════ */
+
+.ui-autocomplete {
+ background: var(--bg2) !important;
+ border: 1px solid var(--border2) !important;
+ border-radius: 8px !important;
+ max-height: 400px !important;
+ overflow-y: auto !important;
+ overflow-x: hidden !important;
+ z-index: 9999 !important;
+ list-style: none !important;
+ padding: 4px 0 !important;
+ margin: 4px 0 0 !important;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(122, 162, 247, 0.05) !important;
+}
+
+/* Category headers */
+.ui-autocomplete .ui-autocomplete-category {
+ background: var(--bg-elevated) !important;
+ color: var(--text-dim) !important;
+ font-family: var(--font-ui) !important;
+ font-size: 10px !important;
+ font-weight: 600 !important;
+ text-transform: uppercase !important;
+ letter-spacing: 0.06em !important;
+ padding: 6px 14px !important;
+ border-bottom: 1px solid var(--border) !important;
+ border-top: 1px solid var(--border) !important;
+ cursor: default !important;
+}
+
+/* Individual result items */
+.ui-autocomplete .ui-menu-item {
+ background: var(--bg2) !important;
+ margin: 0 !important;
+ list-style: none !important;
+}
+
+.ui-autocomplete .ui-menu-item > div,
+.ui-autocomplete .ui-menu-item-wrapper {
+ background: var(--bg2) !important;
+ color: var(--text) !important;
+ font-family: var(--font-mono) !important;
+ font-size: 12px !important;
+ padding: 7px 14px !important;
+ border: none !important;
+ border-left: 2px solid transparent !important;
+ cursor: pointer !important;
+ line-height: 1.5 !important;
+ transition: all 0.1s !important;
+}
+
+/* Hover / focus state */
+.ui-autocomplete .ui-menu-item > div.ui-state-active,
+.ui-autocomplete .ui-menu-item > div.ui-state-focus,
+.ui-autocomplete .ui-menu-item-wrapper.ui-state-active,
+.ui-autocomplete .ui-menu-item-wrapper.ui-state-focus,
+.ui-autocomplete .ui-state-active,
+.ui-autocomplete .ui-state-focus {
+ background: var(--purple-dim) !important;
+ color: var(--text) !important;
+ border: none !important;
+ border-left: 2px solid var(--purple) !important;
+ margin: 0 !important;
+}
+
+/* Highlighted matching text */
+.resultHighlight {
+ color: var(--cyan) !important;
+ font-weight: 600 !important;
+}
+
+/* Search tag result extras */
+.searchTagHolderResult {
+ color: var(--text-dim) !important;
+ font-size: 11px !important;
+}
+
+.searchTagDescResult {
+ color: var(--text-dim) !important;
+ font-size: 11px !important;
+ font-style: italic !important;
+}
+
+/* "No results found" */
+.ui-autocomplete .ui-menu-item:only-child > div {
+ color: var(--text-dim) !important;
+ font-style: italic !important;
+}
+
+/* Override jQuery UI defaults */
+.ui-widget {
+ font-family: var(--font-mono) !important;
+}
+
+.ui-widget-content {
+ background: var(--bg2) !important;
+ color: var(--text) !important;
+ border-color: var(--border2) !important;
+}
+
+.ui-menu .ui-menu-item {
+ padding: 0 !important;
+}
+
+/* Watermark style for search input placeholder */
+.watermark {
+ color: var(--text-dim) !important;
+}
+
+/* ══════════════════════════════════════════════
+ MISC
+ ══════════════════════════════════════════════ */
+
+::-webkit-scrollbar { width: 8px; height: 8px; }
+::-webkit-scrollbar-track { background: var(--bg); }
+::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; }
+::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
+::selection { background: rgba(187, 154, 247, 0.25); color: var(--text); }
+hr { border: none !important; border-top: 1px solid var(--border) !important; margin: 24px 0 !important; }
diff --git a/.github/pages/index.html b/.github/pages/index.html
new file mode 100644
index 0000000..5e467c9
--- /dev/null
+++ b/.github/pages/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Javadoc Index
+
+
+
+
+
+
+
+
diff --git a/.github/pages/package-lock.json b/.github/pages/package-lock.json
new file mode 100644
index 0000000..037a565
--- /dev/null
+++ b/.github/pages/package-lock.json
@@ -0,0 +1,1794 @@
+{
+ "name": "javadoc-index",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "javadoc-index",
+ "version": "1.0.0",
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.2.1",
+ "vite": "^7.3.1"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.1",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
+ "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
+ "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
+ "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
+ "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
+ "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
+ "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
+ "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
+ "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
+ "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
+ "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
+ "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
+ "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
+ "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
+ "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
+ "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
+ "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
+ "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
+ "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
+ "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
+ "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
+ "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
+ "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
+ "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
+ "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
+ "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
+ "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
+ "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
+ "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
+ "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
+ "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
+ "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
+ "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
+ "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
+ "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
+ "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
+ "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
+ "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
+ "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
+ "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
+ "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
+ "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
+ "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
+ "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
+ "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
+ "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
+ "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
+ "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
+ "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
+ "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz",
+ "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.9.0",
+ "caniuse-lite": "^1.0.30001759",
+ "electron-to-chromium": "^1.5.263",
+ "node-releases": "^2.0.27",
+ "update-browserslist-db": "^1.2.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001777",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz",
+ "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.307",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz",
+ "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
+ "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.3",
+ "@esbuild/android-arm": "0.27.3",
+ "@esbuild/android-arm64": "0.27.3",
+ "@esbuild/android-x64": "0.27.3",
+ "@esbuild/darwin-arm64": "0.27.3",
+ "@esbuild/darwin-x64": "0.27.3",
+ "@esbuild/freebsd-arm64": "0.27.3",
+ "@esbuild/freebsd-x64": "0.27.3",
+ "@esbuild/linux-arm": "0.27.3",
+ "@esbuild/linux-arm64": "0.27.3",
+ "@esbuild/linux-ia32": "0.27.3",
+ "@esbuild/linux-loong64": "0.27.3",
+ "@esbuild/linux-mips64el": "0.27.3",
+ "@esbuild/linux-ppc64": "0.27.3",
+ "@esbuild/linux-riscv64": "0.27.3",
+ "@esbuild/linux-s390x": "0.27.3",
+ "@esbuild/linux-x64": "0.27.3",
+ "@esbuild/netbsd-arm64": "0.27.3",
+ "@esbuild/netbsd-x64": "0.27.3",
+ "@esbuild/openbsd-arm64": "0.27.3",
+ "@esbuild/openbsd-x64": "0.27.3",
+ "@esbuild/openharmony-arm64": "0.27.3",
+ "@esbuild/sunos-x64": "0.27.3",
+ "@esbuild/win32-arm64": "0.27.3",
+ "@esbuild/win32-ia32": "0.27.3",
+ "@esbuild/win32-x64": "0.27.3"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.36",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
+ "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.8",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
+ "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
+ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.59.0",
+ "@rollup/rollup-android-arm64": "4.59.0",
+ "@rollup/rollup-darwin-arm64": "4.59.0",
+ "@rollup/rollup-darwin-x64": "4.59.0",
+ "@rollup/rollup-freebsd-arm64": "4.59.0",
+ "@rollup/rollup-freebsd-x64": "4.59.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.59.0",
+ "@rollup/rollup-linux-arm64-musl": "4.59.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.59.0",
+ "@rollup/rollup-linux-loong64-musl": "4.59.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.59.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.59.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.59.0",
+ "@rollup/rollup-linux-x64-gnu": "4.59.0",
+ "@rollup/rollup-linux-x64-musl": "4.59.0",
+ "@rollup/rollup-openbsd-x64": "4.59.0",
+ "@rollup/rollup-openharmony-arm64": "4.59.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.59.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.59.0",
+ "@rollup/rollup-win32-x64-gnu": "4.59.0",
+ "@rollup/rollup-win32-x64-msvc": "4.59.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.27.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ }
+ }
+}
diff --git a/.github/pages/package.json b/.github/pages/package.json
new file mode 100644
index 0000000..c7ccaf3
--- /dev/null
+++ b/.github/pages/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "javadoc-index",
+ "private": true,
+ "version": "1.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.2.1",
+ "vite": "^7.3.1"
+ }
+}
diff --git a/.github/pages/public/manifest.json b/.github/pages/public/manifest.json
new file mode 100644
index 0000000..9c2e85b
--- /dev/null
+++ b/.github/pages/public/manifest.json
@@ -0,0 +1,6 @@
+{
+ "releases": [],
+ "experimental": [],
+ "generated": "",
+ "source": "manifest"
+}
diff --git a/.github/pages/src/App.jsx b/.github/pages/src/App.jsx
new file mode 100644
index 0000000..b306112
--- /dev/null
+++ b/.github/pages/src/App.jsx
@@ -0,0 +1,64 @@
+import styles from './App.module.css'
+import { useDocs } from './useDocs'
+import TerminalHeader from './components/TerminalHeader'
+import Section from './components/Section'
+import { ReleaseCard, ExperimentalCard } from './components/Card'
+import { LoadingState, ErrorState, EmptyState } from './components/States'
+import Footer from './components/Footer'
+
+export default function App() {
+ const { data, loading, error } = useDocs()
+
+ const releases = data?.releases || []
+ const experimental = data?.experimental || []
+
+ return (
+
+
+
+ {/* ── Releases ── */}
+
+ {loading ? (
+
+ ) : error ? (
+
+ ) : releases.length === 0 ? (
+
+ ) : (
+
+ {releases.map((r, i) => (
+
+ ))}
+
+ )}
+
+
+ {/* ── Experimental ── */}
+
+ {loading ? (
+
+ ) : error ? null : experimental.length === 0 ? (
+
+ ) : (
+
+ {experimental.map((b, i) => (
+
+ ))}
+
+ )}
+
+
+ {!loading && !error && (
+
+ )}
+
+ )
+}
diff --git a/.github/pages/src/App.module.css b/.github/pages/src/App.module.css
new file mode 100644
index 0000000..395790d
--- /dev/null
+++ b/.github/pages/src/App.module.css
@@ -0,0 +1,16 @@
+.root {
+ max-width: 1100px;
+ margin: 0 auto;
+ padding: 48px 32px 96px;
+}
+
+.grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ gap: 10px;
+}
+
+@media (max-width: 600px) {
+ .root { padding: 24px 16px 64px; }
+ .grid { grid-template-columns: 1fr; }
+}
diff --git a/.github/pages/src/components/Card.jsx b/.github/pages/src/components/Card.jsx
new file mode 100644
index 0000000..73b1f7c
--- /dev/null
+++ b/.github/pages/src/components/Card.jsx
@@ -0,0 +1,97 @@
+import styles from './Card.module.css'
+import { REPO_NAME } from '../config'
+
+const BASE_PATH = `/${REPO_NAME}`
+
+function formatDate(iso) {
+ if (!iso) return null
+ try {
+ return new Intl.DateTimeFormat('en-GB', {
+ day: '2-digit', month: 'short', year: 'numeric'
+ }).format(new Date(iso))
+ } catch (e) { return null }
+}
+
+export function ReleaseCard({ release, index }) {
+ const isLatest = release.isLatest
+ const date = formatDate(release.date)
+ const cardClass = isLatest
+ ? styles.card + ' ' + styles.latest
+ : styles.card + ' ' + styles.release
+
+ return (
+
+
+
+ {isLatest && (
+ ● latest
+ )}
+ release
+
+
→
+
+
+
+ v{release.version}
+
+
+ {date && (
+
+ date
+ {date}
+
+ )}
+
+ path
+ {release.path}/
+
+
+
+ )
+}
+
+export function ExperimentalCard({ branch, index }) {
+ const date = formatDate(branch.date)
+
+ return (
+
+
+
+ experimental
+
+ →
+
+
+
+ {branch.branch}
+
+
+
+ {date && (
+
+ date
+ {date}
+
+ )}
+ {branch.hash && (
+
+ sha
+ {branch.hash}
+
+ )}
+
+ path
+ {branch.path}/
+
+
+
+ )
+}
diff --git a/.github/pages/src/components/Card.module.css b/.github/pages/src/components/Card.module.css
new file mode 100644
index 0000000..b19f37f
--- /dev/null
+++ b/.github/pages/src/components/Card.module.css
@@ -0,0 +1,143 @@
+.card {
+ display: block;
+ text-decoration: none;
+ background: var(--bg2);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ padding: 20px 22px;
+ transition: border-color 0.15s, background 0.15s, transform 0.15s;
+ position: relative;
+ overflow: hidden;
+ animation: fadeUp 0.35s ease both;
+}
+
+.card::before {
+ content: '';
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ height: 2px;
+ opacity: 0;
+ transition: opacity 0.15s;
+}
+
+.release::before { background: var(--green); }
+.latest::before { background: linear-gradient(90deg, var(--green), var(--blue)); }
+.experimental::before { background: var(--amber); }
+
+.card:hover {
+ border-color: var(--border2);
+ background: var(--bg3);
+ transform: translateY(-2px);
+}
+
+.card:hover::before { opacity: 1; }
+
+/* ── Header ── */
+.header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 14px;
+}
+
+.badges {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.badge {
+ font-size: 9px;
+ font-weight: 600;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ padding: 2px 8px;
+ border-radius: 2px;
+ border: 1px solid;
+}
+
+.badgeLatest {
+ color: var(--green);
+ border-color: var(--green-dim);
+ background: rgba(57, 211, 83, 0.08);
+ animation: pulseBorder 2s ease infinite;
+}
+
+.badgeRelease {
+ color: var(--text-dim);
+ border-color: var(--border2);
+ background: transparent;
+}
+
+.badgeExperimental {
+ color: var(--amber);
+ border-color: var(--amber-dim);
+ background: rgba(240, 160, 48, 0.08);
+}
+
+.arrow {
+ font-size: 14px;
+ color: var(--border2);
+ transition: color 0.15s, transform 0.15s;
+}
+
+.card:hover .arrow {
+ color: var(--text-mid);
+ transform: translateX(3px);
+}
+
+/* ── Version ── */
+.version {
+ font-size: 20px;
+ font-weight: 500;
+ color: var(--text);
+ margin-bottom: 4px;
+ letter-spacing: -0.01em;
+}
+
+.latest .version { color: var(--green); }
+.versionBranch { font-size: 16px; color: var(--amber); }
+
+/* ── Meta ── */
+.meta {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+ margin-top: 12px;
+ padding-top: 12px;
+ border-top: 1px solid var(--border);
+}
+
+.metaRow {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 10px;
+ color: var(--text-dim);
+}
+
+.metaKey {
+ min-width: 36px;
+ color: var(--text-dim);
+}
+
+.metaVal {
+ color: var(--text-mid);
+ font-family: 'IBM Plex Mono', monospace;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.hash { color: var(--blue); }
+
+/* ── Animations ── */
+@keyframes fadeUp {
+ from { opacity: 0; transform: translateY(10px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+@keyframes pulseBorder {
+ 0%, 100% { border-color: var(--green-dim); }
+ 50% { border-color: var(--green); }
+}
diff --git a/.github/pages/src/components/Footer.jsx b/.github/pages/src/components/Footer.jsx
new file mode 100644
index 0000000..503f5e0
--- /dev/null
+++ b/.github/pages/src/components/Footer.jsx
@@ -0,0 +1,29 @@
+import styles from './Footer.module.css'
+import { REPO_OWNER, REPO_NAME } from '../useDocs'
+
+export default function Footer({ source }) {
+ const now = new Intl.DateTimeFormat('en-GB', {
+ day: '2-digit', month: 'short', year: 'numeric',
+ hour: '2-digit', minute: '2-digit', timeZoneName: 'short'
+ }).format(new Date())
+
+ return (
+
+ )
+}
diff --git a/.github/pages/src/components/Footer.module.css b/.github/pages/src/components/Footer.module.css
new file mode 100644
index 0000000..26424d3
--- /dev/null
+++ b/.github/pages/src/components/Footer.module.css
@@ -0,0 +1,36 @@
+.footer {
+ margin-top: 64px;
+ padding-top: 20px;
+ border-top: 1px solid var(--border);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 8px;
+ font-size: 11px;
+ color: var(--text-dim);
+}
+
+.dot {
+ display: inline-block;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--green);
+ margin-right: 6px;
+ animation: blink 2s ease infinite;
+}
+
+.link {
+ color: var(--blue);
+ text-decoration: none;
+}
+
+.link:hover {
+ text-decoration: underline;
+}
+
+@keyframes blink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.3; }
+}
diff --git a/.github/pages/src/components/Section.jsx b/.github/pages/src/components/Section.jsx
new file mode 100644
index 0000000..dc28e1d
--- /dev/null
+++ b/.github/pages/src/components/Section.jsx
@@ -0,0 +1,18 @@
+import styles from './Section.module.css'
+
+export default function Section({ label, count, variant, children }) {
+ return (
+
+
+
{label}
+
+ {count !== undefined && (
+
+ {count} {label.toLowerCase()}{count !== 1 ? 's' : ''}
+
+ )}
+
+ {children}
+
+ )
+}
diff --git a/.github/pages/src/components/Section.module.css b/.github/pages/src/components/Section.module.css
new file mode 100644
index 0000000..00f90a8
--- /dev/null
+++ b/.github/pages/src/components/Section.module.css
@@ -0,0 +1,46 @@
+.section {
+ margin-top: 40px;
+ margin-bottom: 8px;
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 16px;
+}
+
+.tag {
+ font-size: 10px;
+ font-weight: 600;
+ letter-spacing: 0.15em;
+ text-transform: uppercase;
+ padding: 3px 10px;
+ border-radius: 3px;
+ border: 1px solid;
+ white-space: nowrap;
+}
+
+.releases {
+ color: var(--green);
+ border-color: var(--green-dim);
+ background: rgba(57, 211, 83, 0.06);
+}
+
+.experimental {
+ color: var(--amber);
+ border-color: var(--amber-dim);
+ background: rgba(240, 160, 48, 0.06);
+}
+
+.line {
+ flex: 1;
+ height: 1px;
+ background: var(--border);
+}
+
+.count {
+ font-size: 11px;
+ color: var(--text-dim);
+ white-space: nowrap;
+}
diff --git a/.github/pages/src/components/States.jsx b/.github/pages/src/components/States.jsx
new file mode 100644
index 0000000..2827d40
--- /dev/null
+++ b/.github/pages/src/components/States.jsx
@@ -0,0 +1,30 @@
+import styles from './States.module.css'
+
+export function LoadingState() {
+ return (
+
+
+
Fetching documentation index...
+
+ )
+}
+
+export function ErrorState({ message }) {
+ return (
+
+
⚠
+
{message}
+
+ Check that the gh-pages branch exists and is publicly accessible.
+
+
+ )
+}
+
+export function EmptyState({ label }) {
+ return (
+
+ )
+}
diff --git a/.github/pages/src/components/States.module.css b/.github/pages/src/components/States.module.css
new file mode 100644
index 0000000..319fc6e
--- /dev/null
+++ b/.github/pages/src/components/States.module.css
@@ -0,0 +1,47 @@
+.box {
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ padding: 48px;
+ text-align: center;
+ background: var(--bg2);
+}
+
+.empty {
+ padding: 24px;
+}
+
+.spinner {
+ width: 22px;
+ height: 22px;
+ border: 2px solid var(--border2);
+ border-top-color: var(--green);
+ border-radius: 50%;
+ animation: spin 0.75s linear infinite;
+ margin: 0 auto 14px;
+}
+
+.label {
+ font-size: 12px;
+ color: var(--text-dim);
+}
+
+.errorIcon {
+ font-size: 22px;
+ margin-bottom: 10px;
+ color: var(--red);
+}
+
+.errorMsg {
+ font-size: 13px;
+ color: var(--red);
+ margin-bottom: 6px;
+}
+
+.errorSub {
+ font-size: 11px;
+ color: var(--text-dim);
+}
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
diff --git a/.github/pages/src/components/TerminalHeader.jsx b/.github/pages/src/components/TerminalHeader.jsx
new file mode 100644
index 0000000..e2efb27
--- /dev/null
+++ b/.github/pages/src/components/TerminalHeader.jsx
@@ -0,0 +1,186 @@
+import { useState, useEffect } from 'react'
+import styles from './TerminalHeader.module.css'
+import { PROJECT_NAME, REPO_NAME, LINKS, AUTHORS } from '../config'
+
+function useGitHubProfile(username) {
+ const [profile, setProfile] = useState(null)
+ const [loading, setLoading] = useState(true)
+
+ useEffect(() => {
+ const cacheKey = 'gh-profile-' + username
+
+ // Check sessionStorage first — avoids hammering the API on every render
+ try {
+ const cached = sessionStorage.getItem(cacheKey)
+ if (cached) {
+ setProfile(JSON.parse(cached))
+ setLoading(false)
+ return
+ }
+ } catch (e) {}
+
+ fetch('https://api.github.com/users/' + username)
+ .then(r => {
+ if (!r.ok) throw new Error('HTTP ' + r.status)
+ return r.json()
+ })
+ .then(d => {
+ // Don't cache error responses like rate limit messages
+ if (!d.message) {
+ try { sessionStorage.setItem(cacheKey, JSON.stringify(d)) } catch (e) {}
+ }
+ setProfile(d)
+ setLoading(false)
+ })
+ .catch(() => setLoading(false))
+ }, [username])
+
+ return { profile, loading }
+}
+
+function AuthorTile({ username, active }) {
+ const { profile, loading } = useGitHubProfile(username)
+ const tileClass = styles.authorTile + (active ? ' ' + styles.authorTileActive : '')
+
+ if (loading) {
+ return (
+
+ )
+ }
+
+ if (!profile || profile.message) {
+ return (
+
+
+
+
{username}
+
@{username}
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
{profile.name || profile.login}
+
@{profile.login}
+ {profile.bio
+ ?
{profile.bio}
+ :
+ }
+
+
+ )
+}
+
+function AuthorsTiles() {
+ const [active, setActive] = useState(0)
+
+ useEffect(() => {
+ if (AUTHORS.length <= 1) return
+ const t = setInterval(() => {
+ setActive(i => (i + 1) % AUTHORS.length)
+ }, 4000)
+ return () => clearInterval(t)
+ }, [])
+
+ return (
+
+
+ › Authors:
+
+
+ {AUTHORS.map((username, i) => (
+
+ ))}
+
+
+ )
+}
+
+export default function TerminalHeader() {
+ return (
+
+
+
+
+
+
javadoc-index — bash
+
+
+
+ {PROJECT_NAME}
+
+
+
+ $
+ browse-docs
+ {REPO_NAME}
+ --all-versions
+
+
+
+ › Fetching available documentation builds...
+
+
+ › Found project links:
+
+
+
+
+
+
+
+ $
+
+
+
+
+ )
+}
diff --git a/.github/pages/src/components/TerminalHeader.module.css b/.github/pages/src/components/TerminalHeader.module.css
new file mode 100644
index 0000000..84853ab
--- /dev/null
+++ b/.github/pages/src/components/TerminalHeader.module.css
@@ -0,0 +1,303 @@
+.wrap {
+ margin-bottom: 48px;
+}
+
+.bar {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ background: var(--bg3);
+ border: 1px solid var(--border2);
+ border-bottom: none;
+ border-radius: 8px 8px 0 0;
+ padding: 10px 16px;
+}
+
+.dot {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+}
+.red { background: #ff5f57; }
+.amber { background: #febc2e; }
+.green { background: #28c840; }
+
+.title {
+ margin-left: 8px;
+ font-size: 11px;
+ color: var(--text-dim);
+ letter-spacing: 0.05em;
+}
+
+.body {
+ background: var(--bg2);
+ border: 1px solid var(--border2);
+ border-radius: 0 0 8px 8px;
+ padding: 16px 36px 36px;
+}
+
+/* ── Heading ── */
+.heading {
+ font-family: 'IBM Plex Sans', sans-serif;
+ font-size: clamp(28px, 5vw, 52px);
+ font-weight: 300;
+ letter-spacing: -0.02em;
+ color: var(--text);
+ line-height: 1.05;
+ margin-bottom: 20px;
+}
+
+.heading strong {
+ font-weight: 600;
+ color: var(--green);
+}
+
+/* ── Prompt ── */
+.promptLine {
+ display: flex;
+ align-items: baseline;
+ gap: 10px;
+ margin-bottom: 6px;
+ font-size: 13px;
+ flex-wrap: wrap;
+}
+
+.prompt { color: var(--green); font-weight: 600; }
+.cmd { color: var(--text); }
+.arg { color: var(--blue); }
+.flag { color: var(--amber); }
+
+/* ── Output lines ── */
+.outputLine {
+ font-size: 12px;
+ color: var(--text-dim);
+ line-height: 1.8;
+ padding-left: 20px;
+}
+
+.chevron {
+ color: var(--text-mid);
+ margin-right: 4px;
+}
+
+/* ── Links ── */
+.links {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ padding-left: 36px;
+ margin-top: 4px;
+ margin-bottom: 12px;
+}
+
+.link {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ text-decoration: none;
+ padding: 3px 0;
+ width: fit-content;
+ transition: opacity 0.15s;
+}
+
+.link:hover { opacity: 0.8; }
+
+.link:hover .linkLabel {
+ text-decoration: underline;
+ text-underline-offset: 3px;
+}
+
+.linkTag {
+ font-size: 9px;
+ font-weight: 600;
+ letter-spacing: 0.1em;
+ border: 1px solid;
+ border-radius: 2px;
+ padding: 1px 5px;
+ min-width: 28px;
+ text-align: center;
+ opacity: 0.9;
+ font-family: 'IBM Plex Mono', monospace;
+}
+
+.linkLabel {
+ font-size: 12px;
+ color: var(--text-mid);
+ font-family: 'IBM Plex Mono', monospace;
+}
+
+.linkArrow {
+ font-size: 11px;
+ opacity: 0.6;
+ transition: opacity 0.15s, transform 0.15s;
+}
+
+.link:hover .linkArrow {
+ opacity: 1;
+ transform: translate(2px, -2px);
+}
+
+/* ── Authors ── */
+.authors {
+ margin-bottom: 8px;
+}
+
+.authorRow {
+ display: flex;
+ flex-direction: row;
+ gap: 8px;
+ padding-left: 36px;
+ margin-top: 6px;
+ flex-wrap: wrap;
+}
+
+/* ── Author tile ── */
+.authorTile {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ background: var(--bg3);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ padding: 8px 12px;
+ text-decoration: none;
+ cursor: pointer;
+ /* width is dynamic — grows with content */
+ width: max-content;
+ min-width: 140px;
+ position: relative;
+ overflow: hidden;
+ transition: border-color 0.2s, background 0.2s, transform 0.2s;
+}
+
+.authorTile::before {
+ content: '';
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ height: 2px;
+ background: var(--green);
+ opacity: 0;
+ transition: opacity 0.2s;
+}
+
+.authorTileActive::before,
+.authorTile:hover::before {
+ opacity: 1;
+}
+
+.authorTileActive {
+ border-color: var(--green-dim);
+ background: rgba(57, 211, 83, 0.04);
+}
+
+.authorTile:hover {
+ border-color: var(--border2);
+ background: #161b22;
+ transform: translateY(-1px);
+}
+
+/* ── Author content ── */
+.authorAvatar {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ border: 1px solid var(--border2);
+ flex-shrink: 0;
+}
+
+.authorAvatarSkeleton {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background: var(--border2);
+ flex-shrink: 0;
+ animation: shimmer 1.5s ease infinite;
+}
+
+.authorInfo {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ min-width: 0;
+}
+
+.authorName {
+ font-size: 12px;
+ font-weight: 500;
+ color: var(--text);
+ font-family: 'IBM Plex Sans', sans-serif;
+ white-space: nowrap;
+}
+
+.authorLogin {
+ font-size: 10px;
+ color: var(--blue);
+ font-family: 'IBM Plex Mono', monospace;
+ white-space: nowrap;
+}
+
+/* Bio — always reserves vertical height, width animates open */
+.authorBio {
+ display: block;
+ font-size: 10px;
+ color: var(--text-dim);
+ font-family: 'IBM Plex Sans', sans-serif;
+ margin-top: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ /* always reserve vertical space */
+ height: 14px;
+ /* collapsed horizontally */
+ width: 0;
+ opacity: 0;
+ transition: opacity 0.25s ease, width 0.3s ease;
+}
+
+.authorTileActive .authorBio,
+.authorTile:hover .authorBio {
+ width: 200px;
+ opacity: 1;
+}
+
+/* Placeholder for loading/no-profile/no-bio states */
+.authorBioPlaceholder {
+ height: 14px;
+ margin-top: 2px;
+ width: 0; /* never takes horizontal space, never expands */
+}
+
+.authorSkeleton {
+ height: 9px;
+ border-radius: 4px;
+ background: var(--border2);
+ animation: shimmer 1.5s ease infinite;
+}
+
+/* ── Cursor ── */
+.cursor {
+ display: inline-block;
+ width: 8px;
+ height: 13px;
+ background: var(--green);
+ margin-left: 2px;
+ vertical-align: text-bottom;
+ animation: blink 1s step-end infinite;
+}
+
+/* ── Animations ── */
+@keyframes blink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+@keyframes shimmer {
+ 0%, 100% { opacity: 0.4; }
+ 50% { opacity: 0.8; }
+}
+
+@media (max-width: 600px) {
+ .body { padding: 20px; }
+ .links { padding-left: 20px; }
+ .authorRow { padding-left: 20px; }
+}
diff --git a/.github/pages/src/config.js b/.github/pages/src/config.js
new file mode 100644
index 0000000..41525f3
--- /dev/null
+++ b/.github/pages/src/config.js
@@ -0,0 +1,38 @@
+// ─── Project Configuration ───────────────────────────────────
+// This is the ONLY file that should differ between projects.
+// Everything else in the pages app is generic.
+// ─────────────────────────────────────────────────────────────
+
+export const PROJECT_NAME = 'CustomNPC+ Gecko Addon'
+export const REPO_OWNER = 'KAMKEEL'
+export const REPO_NAME = 'CustomNPC-Gecko-Addon'
+
+export const LINKS = [
+ {
+ tag: 'GH',
+ label: 'github.com/KAMKEEL/CustomNPC-Gecko-Addon',
+ href: 'https://github.com/KAMKEEL/CustomNPC-Gecko-Addon',
+ color: '#e6edf3',
+ },
+ {
+ tag: 'DC',
+ label: 'discord.gg/94qmjEDxkp',
+ href: 'https://discord.gg/94qmjEDxkp',
+ color: '#5865f2',
+ },
+ {
+ tag: 'MR',
+ label: 'modrinth.com/mod/customnpc-plus-gecko-addon',
+ href: 'https://modrinth.com/mod/customnpc-plus-gecko-addon',
+ color: '#1bd96a',
+ },
+ {
+ tag: 'CF',
+ label: 'curseforge.com/minecraft/mc-mods/cnpc-custom-model-addon',
+ href: 'https://www.curseforge.com/minecraft/mc-mods/cnpc-custom-model-addon',
+ color: '#f16436',
+ },
+]
+
+// GitHub usernames — profiles are fetched at runtime
+export const AUTHORS = ['goodbird-git', 'kamkeel']
diff --git a/.github/pages/src/index.css b/.github/pages/src/index.css
new file mode 100644
index 0000000..fef4fe1
--- /dev/null
+++ b/.github/pages/src/index.css
@@ -0,0 +1,50 @@
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+
+:root {
+ --bg: #080b0f;
+ --bg2: #0d1117;
+ --bg3: #131920;
+ --border: #1e2936;
+ --border2: #253040;
+ --green: #39d353;
+ --green-dim: #1a6b2a;
+ --amber: #f0a030;
+ --amber-dim: #7a4e10;
+ --blue: #58a6ff;
+ --blue-dim: #1a3a6b;
+ --text: #cdd9e5;
+ --text-dim: #636e7b;
+ --text-mid: #8b949e;
+ --red: #f85149;
+}
+
+html, body {
+ height: 100%;
+ background: var(--bg);
+ color: var(--text);
+ font-family: 'IBM Plex Mono', monospace;
+ overflow-x: hidden;
+}
+
+/* Scanlines */
+body::after {
+ content: '';
+ position: fixed;
+ inset: 0;
+ background: repeating-linear-gradient(
+ 0deg,
+ transparent,
+ transparent 2px,
+ rgba(0,0,0,0.025) 2px,
+ rgba(0,0,0,0.025) 4px
+ );
+ pointer-events: none;
+ z-index: 9999;
+}
+
+a { color: inherit; text-decoration: none; }
+
+::-webkit-scrollbar { width: 6px; }
+::-webkit-scrollbar-track { background: var(--bg2); }
+::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 3px; }
+::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
diff --git a/.github/pages/src/main.jsx b/.github/pages/src/main.jsx
new file mode 100644
index 0000000..22bbe14
--- /dev/null
+++ b/.github/pages/src/main.jsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App'
+import { PROJECT_NAME } from './config'
+import './index.css'
+
+document.title = `${PROJECT_NAME} — Javadoc Index`
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+)
diff --git a/.github/pages/src/useDocs.js b/.github/pages/src/useDocs.js
new file mode 100644
index 0000000..1c8c5b8
--- /dev/null
+++ b/.github/pages/src/useDocs.js
@@ -0,0 +1,94 @@
+import { useState, useEffect } from 'react'
+import { REPO_OWNER, REPO_NAME } from './config'
+
+const BASE_PATH = `/${REPO_NAME}`
+const API_BASE = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}`
+
+// Cache bust on every page load — appends current timestamp to manifest URL
+// so the browser never serves a stale manifest.json
+async function fetchFromManifest() {
+ const bust = `?t=${Date.now()}`
+ const res = await fetch(`${BASE_PATH}/manifest.json${bust}`, {
+ cache: 'no-store', // tells browser not to cache this request at all
+ })
+ if (!res.ok) throw new Error('No manifest')
+ return res.json()
+}
+
+async function fetchFromGitHubAPI() {
+ const refRes = await fetch(`${API_BASE}/git/ref/heads/gh-pages`)
+ if (!refRes.ok) throw new Error('gh-pages branch not found')
+ const refData = await refRes.json()
+ const sha = refData.object.sha
+
+ const treeRes = await fetch(`${API_BASE}/git/trees/${sha}?recursive=1`)
+ if (!treeRes.ok) throw new Error('Could not fetch tree')
+ const treeData = await treeRes.json()
+
+ const commitsRes = await fetch(`${API_BASE}/commits?sha=gh-pages&per_page=100`)
+ const commits = commitsRes.ok ? await commitsRes.json() : []
+
+ const commitMap = {}
+ commits.forEach(c => {
+ const date = c.commit?.committer?.date || c.commit?.author?.date || ''
+ const hash = c.sha?.slice(0, 7) || ''
+ const msg = c.commit?.message || ''
+ const vMatch = msg.match(/releases\/([\d.]+)/)
+ if (vMatch) commitMap[`releases/${vMatch[1]}`] = { date, hash }
+ const eMatch = msg.match(/experimental\/([\w-]+)/)
+ if (eMatch) commitMap[`experimental/${eMatch[1]}`] = { date, hash }
+ })
+
+ const releaseDirs = new Set()
+ const experimentalDirs = new Set()
+
+ treeData.tree.forEach(item => {
+ if (item.type !== 'tree') return
+ const parts = item.path.split('/')
+ if (parts[0] === 'releases' && parts.length === 2) releaseDirs.add(parts[1])
+ if (parts[0] === 'experimental' && parts.length === 2) experimentalDirs.add(parts[1])
+ })
+
+ // Sort releases newest first, mark first as latest
+ const sortedReleases = [...releaseDirs]
+ .sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))
+
+ const releases = sortedReleases.map((v, i) => {
+ const c = commitMap[`releases/${v}`] || {}
+ return {
+ id: v,
+ version: v,
+ path: `releases/${v}`,
+ date: c.date,
+ hash: c.hash,
+ isLatest: i === 0, // newest version is always latest
+ }
+ })
+
+ const experimental = [...experimentalDirs].sort().map(b => {
+ const c = commitMap[`experimental/${b}`] || {}
+ return { id: b, branch: b, path: `experimental/${b}`, date: c.date, hash: c.hash }
+ })
+
+ return { releases, experimental, source: 'api' }
+}
+
+export function useDocs() {
+ const [data, setData] = useState(null)
+ const [loading, setLoading] = useState(true)
+ const [error, setError] = useState(null)
+
+ useEffect(() => {
+ fetchFromManifest()
+ .then(d => { setData(d); setLoading(false) })
+ .catch(() =>
+ fetchFromGitHubAPI()
+ .then(d => { setData(d); setLoading(false) })
+ .catch(e => { setError(e.message); setLoading(false) })
+ )
+ }, [])
+
+ return { data, loading, error }
+}
+
+export { BASE_PATH, REPO_OWNER, REPO_NAME }
diff --git a/.github/pages/vite.config.js b/.github/pages/vite.config.js
new file mode 100644
index 0000000..1b00c45
--- /dev/null
+++ b/.github/pages/vite.config.js
@@ -0,0 +1,12 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import { REPO_NAME } from './src/config.js'
+
+export default defineConfig({
+ plugins: [react()],
+ base: `/${REPO_NAME}/`,
+ build: {
+ outDir: '../../.github/pages-dist',
+ emptyOutDir: true,
+ }
+})
diff --git a/.github/scripts/doc-config.sh b/.github/scripts/doc-config.sh
new file mode 100644
index 0000000..8289bbe
--- /dev/null
+++ b/.github/scripts/doc-config.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# -----------------------------------------------
+# doc-config.sh — shared config for javadoc deploy
+#
+# Sourced by:
+# - resolve-doc-path.sh
+# - javadoc.yml (via sanity-check job)
+#
+# ADD WHITELISTED BRANCHES HERE AND NOWHERE ELSE.
+# main is always handled automatically.
+# -----------------------------------------------
+
+MAIN_BRANCH_NAME="main"
+
+EXPERIMENTAL_WHITELIST=(
+ "dev"
+ # "new-branch"
+)
diff --git a/.github/scripts/generate-index.sh b/.github/scripts/generate-index.sh
new file mode 100644
index 0000000..7651a80
--- /dev/null
+++ b/.github/scripts/generate-index.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+set -e
+
+RELEASES=()
+EXPERIMENTAL=()
+
+# Collect releases
+if [ -d "./releases" ]; then
+ for dir in ./releases/*/; do
+ [ -d "$dir" ] || continue
+ name=$(basename "$dir")
+ RELEASES+=("$name")
+ done
+fi
+
+# Collect experimental branches
+if [ -d "./experimental" ]; then
+ for dir in ./experimental/*/; do
+ [ -d "$dir" ] || continue
+ name=$(basename "$dir")
+ EXPERIMENTAL+=("$name")
+ done
+fi
+
+# Sort releases in reverse semver order (newest first)
+if [ ${#RELEASES[@]} -gt 0 ]; then
+ IFS=$'\n' RELEASES=($(sort -rV <<< "${RELEASES[*]}")); unset IFS
+fi
+
+# ── Store source commit metadata for this deploy ───────────────
+# DEPLOY_PATH, SOURCE_HASH, SOURCE_DATE are passed in as env vars from the workflow
+if [ -n "$DEPLOY_PATH" ] && [ -n "$SOURCE_HASH" ]; then
+ mkdir -p ".doc-meta"
+ META_KEY="${DEPLOY_PATH//\//_}"
+ cat > ".doc-meta/${META_KEY}.json" << JSON
+{"hash":"${SOURCE_HASH}","date":"${SOURCE_DATE}"}
+JSON
+ echo "Stored source metadata for $DEPLOY_PATH → $SOURCE_HASH @ $SOURCE_DATE"
+fi
+
+# ── Helper: get source commit hash + date for a path ──────────
+get_commit_info() {
+ local path="$1"
+
+ # If this is the path we just deployed, use the injected source commit
+ if [ "$path" = "$DEPLOY_PATH" ] && [ -n "$SOURCE_HASH" ]; then
+ echo "${SOURCE_HASH} ${SOURCE_DATE}"
+ return
+ fi
+
+ # Try reading from stored metadata file (set by previous deploys)
+ local meta=".doc-meta/${path//\//_}.json"
+ if [ -f "$meta" ]; then
+ local hash date
+ hash=$(python3 -c "import json,sys; d=json.load(open('$meta')); print(d.get('hash',''))" 2>/dev/null || grep -o '"hash":"[^"]*"' "$meta" | cut -d'"' -f4)
+ date=$(python3 -c "import json,sys; d=json.load(open('$meta')); print(d.get('date',''))" 2>/dev/null || grep -o '"date":"[^"]*"' "$meta" | cut -d'"' -f4)
+ echo "${hash:-} ${date:-}"
+ return
+ fi
+
+ # Last resort: gh-pages git log (hash will be wrong but better than empty)
+ local hash date
+ hash=$(git log --oneline -1 -- "$path" 2>/dev/null | awk '{print $1}')
+ date=$(git log --format="%cI" -1 -- "$path" 2>/dev/null)
+ echo "${hash:-} ${date:-}"
+}
+
+# ── Build releases JSON ────────────────────────────────────────
+RELEASES_JSON="["
+
+for i in "${!RELEASES[@]}"; do
+ version="${RELEASES[$i]}"
+ read -r HASH DATE <<< "$(get_commit_info "releases/$version")"
+ if [ "$i" -eq 0 ]; then
+ IS_LATEST="true"
+ else
+ IS_LATEST="false"
+ fi
+ RELEASES_JSON+="{\"id\":\"${version}\",\"version\":\"${version}\",\"path\":\"releases/${version}\",\"date\":\"${DATE}\",\"isLatest\":${IS_LATEST}},"
+done
+
+RELEASES_JSON="${RELEASES_JSON%,}]"
+
+# ── Build experimental JSON ────────────────────────────────────
+EXPERIMENTAL_JSON="["
+
+for branch in "${EXPERIMENTAL[@]}"; do
+ read -r HASH DATE <<< "$(get_commit_info "experimental/$branch")"
+ EXPERIMENTAL_JSON+="{\"id\":\"${branch}\",\"branch\":\"${branch}\",\"path\":\"experimental/${branch}\",\"hash\":\"${HASH}\",\"date\":\"${DATE}\"},"
+done
+
+EXPERIMENTAL_JSON="${EXPERIMENTAL_JSON%,}]"
+
+# ── Write manifest.json ────────────────────────────────────────
+cat > manifest.json << JSON
+{
+ "releases": ${RELEASES_JSON},
+ "experimental": ${EXPERIMENTAL_JSON},
+ "generated": "$(date -u '+%Y-%m-%dT%H:%M:%SZ')",
+ "source": "manifest"
+}
+JSON
+
+echo "manifest.json generated:"
+cat manifest.json
+echo ""
+echo "Done."
diff --git a/.github/scripts/resolve-doc-path.sh b/.github/scripts/resolve-doc-path.sh
new file mode 100644
index 0000000..92ad7ac
--- /dev/null
+++ b/.github/scripts/resolve-doc-path.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "$SCRIPT_DIR/doc-config.sh"
+
+BRANCH="${GITHUB_REF#refs/heads/}"
+SAFE_BRANCH="${BRANCH//\//-}"
+
+if [ "$BRANCH" = "$MAIN_BRANCH_NAME" ]; then
+ # Version resolution order:
+ # -> check if gradle.properties has a `modVersion` tag. If it does, just grab it.
+ # -> check if it has the `version` tag. Grab it if it does
+ # -> check build.gradle for the version tag.
+ if [ -f "gradle.properties" ] && grep -q "^modVersion=" gradle.properties; then
+ VERSION=$(grep "^modVersion=" gradle.properties | cut -d'=' -f2 | tr -d '[:space:]')
+ elif [ -f "gradle.properties" ] && grep -q "^version=" gradle.properties; then
+ VERSION=$(grep "^version=" gradle.properties | cut -d'=' -f2 | tr -d '[:space:]')
+ elif [ -f "build.gradle" ]; then
+ VERSION=$(grep "^version" build.gradle | head -1 | sed "s/version\s*=\s*['\"]//;s/['\"].*//;s/\s//g")
+ elif [ -f "build.gradle.kts" ]; then
+ VERSION=$(grep "^version" build.gradle.kts | head -1 | sed "s/version\s*=\s*\"//;s/\".*//;s/\s//g")
+ else
+ echo "Could not find version. Defaulting to 'unknown'."
+ VERSION="unknown"
+ fi
+
+ echo "Resolved version: $VERSION"
+
+ # Only deploy to releases/ — isLatest is handled by generate-index.sh
+ echo "path=releases/$VERSION" >> $GITHUB_OUTPUT
+ echo "extra_path=" >> $GITHUB_OUTPUT
+
+else
+ MATCHED=false
+ for ALLOWED in "${EXPERIMENTAL_WHITELIST[@]}"; do
+ if [ "$BRANCH" = "$ALLOWED" ]; then
+ MATCHED=true
+ break
+ fi
+ done
+
+ if [ "$MATCHED" = true ]; then
+ echo "path=experimental/$SAFE_BRANCH" >> $GITHUB_OUTPUT
+ echo "extra_path=" >> $GITHUB_OUTPUT
+ echo "Branch '$BRANCH' is whitelisted, deploying to experimental/$SAFE_BRANCH"
+ else
+ echo "path=" >> $GITHUB_OUTPUT
+ echo "extra_path=" >> $GITHUB_OUTPUT
+ echo "Branch '$BRANCH' is not whitelisted. Skipping deploy."
+ fi
+fi
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 3ee2f68..a5e8bb4 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -1,4 +1,3 @@
-
name: Build and test
on:
@@ -9,5 +8,140 @@ on:
jobs:
build-and-test:
- uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/build-and-test.yml@master
- secrets: inherit
+ runs-on: ubuntu-24.04
+ env:
+ WORKSPACE_TASK: ${{ vars.WORKSPACE_TASK || 'setupCIWorkspace' }}
+ RUN_SERVER_TIMEOUT: ${{ vars.RUN_SERVER_TIMEOUT || 90 }}
+ RUN_SERVER_ENABLED: ${{ vars.RUN_SERVER_ENABLED || 'true' }}
+ steps:
+ - name: Install Ubuntu dependencies
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y mesa-utils xvfb x11-xserver-utils
+
+ - name: Checkout mod repo
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Initialize submodules
+ run: git submodule update --init --recursive
+
+ - name: Checkout workflows repo
+ uses: actions/checkout@v4
+ with:
+ repository: GTNewHorizons/GTNH-Actions-Workflows
+ path: .gtnh-workflows
+ fetch-depth: 0
+
+ - name: Set up JDK versions
+ uses: actions/setup-java@v4
+ with:
+ java-version: |
+ 8
+ 17
+ 21
+ distribution: 'zulu'
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v4
+ with:
+ build-scan-publish: true
+ build-scan-terms-of-use-url: "https://gradle.com/terms-of-service"
+ build-scan-terms-of-use-agree: "yes"
+ validate-wrappers: true
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+
+ - name: Setup the workspace
+ run: ./gradlew --build-cache --info --stacktrace "${WORKSPACE_TASK}"
+
+ - name: Compile the mod
+ run: ./gradlew --build-cache --info --stacktrace assemble
+
+ - name: Attach compilation artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ github.repository_id }}-build-libs
+ path: build/libs/
+ retention-days: 90
+
+ - name: Run post-build checks
+ id: build_mod
+ run: xvfb-run --server-args="-screen 0 1366x768x24" ./gradlew --build-cache --info --stacktrace build
+
+ - name: Attach gradle reports
+ if: failure() && steps.build_mod.conclusion == 'failure'
+ uses: actions/upload-artifact@v4
+ continue-on-error: true
+ with:
+ name: ${{ github.repository_id }}-reports
+ path: build/reports/
+ retention-days: 31
+
+ - name: Attempt to make a PR fixing spotless errors
+ if: >-
+ ${{ failure() && steps.build_mod.conclusion == 'failure'
+ && github.event_name == 'pull_request'
+ && !github.event.pull_request.draft
+ && github.event.pull_request.head.repo.full_name == github.repository }}
+ run: |
+ git reset --hard
+ git checkout "${PR_BRANCH}"
+ ./gradlew --build-cache --info --stacktrace spotlessApply || exit 1
+ git diff --exit-code && exit 1
+ git config user.name "GitHub GTNH Actions"
+ git config user.email "<>"
+ git switch -c "${FIXED_BRANCH}"
+ git commit -am "spotlessApply"
+ git push --force-with-lease origin "${FIXED_BRANCH}"
+ gh pr create \
+ --head "${FIXED_BRANCH}" \
+ --base "${PR_BRANCH}" \
+ --title "Spotless apply for branch ${PR_BRANCH} for #${{ github.event.pull_request.number }}" \
+ --body "Automatic spotless apply to fix formatting errors, applies to PR #${{ github.event.pull_request.number }}" \
+ 2>&1 | tee pr-message.log || true
+ gh pr comment "${PR_BRANCH}" -F pr-message.log || true
+ shell: bash
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_BRANCH: ${{ github.head_ref }}
+ FIXED_BRANCH: ${{ github.head_ref }}-spotless-fixes
+
+ - name: Run server for up to ${{ env.RUN_SERVER_TIMEOUT }} seconds
+ if: ${{ env.RUN_SERVER_ENABLED == 'true' }}
+ run: |
+ mkdir -p run
+ echo "eula=true" > run/eula.txt
+ echo "level-seed=-6202107849386030209\nonline-mode=true\n" > run/server.properties
+ echo "stop" > run/stop.txt
+ timeout "${RUN_SERVER_TIMEOUT}" ./gradlew --build-cache --info --stacktrace runServer 2>&1 < run/stop.txt | tee -a server.log || true
+
+ - name: Test no errors reported during server run
+ if: ${{ env.RUN_SERVER_ENABLED == 'true' }}
+ run: |
+ chmod +x .gtnh-workflows/scripts/test_no_error_reports
+ .gtnh-workflows/scripts/test_no_error_reports
+
+ - name: Test no prerelease dependencies used
+ run: |
+ ! grep -P -- "-pre(?!shadow)" dependencies.gradle*
+
+ - name: Make sure asset files are not overoptimized
+ if: github.event_name == 'pull_request'
+ run: |
+ echo "Checking for grayscale asset files which are not supported by the java8 image loader"
+ fail=0
+ set -o pipefail
+ while IFS= read -r -d $'\n' file; do
+ if $(file --brief -- "$file" | grep -q grayscale); then
+ printf "found grayscale image '%s'\n" "$file"
+ fail=1
+ fi
+ done < <(gh pr diff --name-only "${PR_NUMBER}" | grep 'src/main/resources/.*\.png$')
+
+ exit $fail
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_NUMBER: ${{ github.event.number }}
diff --git a/.github/workflows/buildscript-maintenance.yml b/.github/workflows/buildscript-maintenance.yml
deleted file mode 100644
index a9d5486..0000000
--- a/.github/workflows/buildscript-maintenance.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# This workflow only meant for the source mod you shouldn't bring it into your own project
-
-name: Buildscript maintenance
-
-on:
- push:
- branches: [ master, main ]
- paths:
- - build.gradle
- workflow_dispatch: { }
-
-jobs:
- buildscript-maintenance:
- runs-on: ubuntu-latest
- # Avoid running this workflow on forks
- if: github.repository == 'GTNewHorizons/ExampleMod1.7.10'
- permissions:
- contents: write
- pull-requests: write
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Ensure build script version is up to date
- id: update-buildscript
- run: |
- new_version="$(date +%s)"
- sed --in-place "1s!^//version:.*!//version: $new_version!g" build.gradle
- echo "::set-output name=new_version::$new_version"
-
- - name: Create Pull Request
- id: create-pull-request
- uses: peter-evans/create-pull-request@v4
- with:
- add-paths: build.gradle
- commit-message: '[ci skip] update build script version to ${{ steps.update-buildscript.outputs.new_version }}'
- branch: buildscript-maintenance
- title: Update build script version to ${{ steps.update-buildscript.outputs.new_version }}
- body: This pull request is created by the buildscript-maintenance workflow
diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml
new file mode 100644
index 0000000..f0f767f
--- /dev/null
+++ b/.github/workflows/javadoc.yml
@@ -0,0 +1,260 @@
+name: Generate and Deploy Javadoc
+
+on:
+ push:
+ branches:
+ - main
+ - '**'
+ delete:
+ workflow_dispatch:
+ inputs:
+ force_deploy:
+ description: 'Force redeploy Javadocs without a new commit'
+ required: false
+ default: 'true'
+
+jobs:
+ sanity-check:
+ runs-on: ubuntu-latest
+ outputs:
+ should_deploy: ${{ steps.deploy_check.outputs.should_deploy }}
+ steps:
+ - uses: actions/checkout@v4
+ - name: Check for deploy tag
+ id: deploy_check
+ run: |
+ source .github/scripts/doc-config.sh
+
+ BRANCH="${GITHUB_REF#refs/heads/}"
+
+ # Always deploy on manual trigger
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
+ echo "should_deploy=true" >> $GITHUB_OUTPUT
+ echo "Reason: workflow_dispatch"
+ exit 0
+ fi
+
+ # Main branch: only deploy if commit message contains [deploy-docs]
+ if [ "$BRANCH" = "$MAIN_BRANCH_NAME" ]; then
+ if echo "${{ github.event.head_commit.message }}" | grep -q "\[deploy-docs\]"; then
+ echo "should_deploy=true" >> $GITHUB_OUTPUT
+ echo "Reason: main branch with [deploy-docs] tag"
+ else
+ echo "should_deploy=false" >> $GITHUB_OUTPUT
+ echo "Reason: main branch without [deploy-docs] tag, skipping"
+ fi
+ exit 0
+ fi
+
+ # Experimental branches: only deploy if whitelisted
+ for ALLOWED in "${EXPERIMENTAL_WHITELIST[@]}"; do
+ if [ "$BRANCH" = "$ALLOWED" ]; then
+ echo "should_deploy=true" >> $GITHUB_OUTPUT
+ echo "Reason: branch '$BRANCH' is whitelisted"
+ exit 0
+ fi
+ done
+
+ echo "should_deploy=false" >> $GITHUB_OUTPUT
+ echo "Reason: branch '$BRANCH' is not whitelisted, skipping"
+
+ build-and-deploy-javadoc:
+ needs: sanity-check
+ if: needs.sanity-check.outputs.should_deploy == 'true'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout source branch
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: Setup JDK 8 (compile)
+ uses: actions/setup-java@v4
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+
+ - name: Setup JDK 11 (javadoc)
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Extract convention plugin version
+ id: convention
+ run: |
+ VERSION=$(grep "id 'com.gtnewhorizons.gtnhsettingsconvention'" settings.gradle settings.gradle.kts 2>/dev/null | grep -o "version '[0-9]\+\.[0-9]\+\.[0-9]\+'" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
+ echo "Detected convention version: $VERSION"
+
+ - name: Get source commit info
+ id: source_commit
+ run: |
+ echo "hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
+ echo "date=$(git log -1 --format='%cI')" >> $GITHUB_OUTPUT
+
+ - name: Cache Gradle wrapper
+ uses: actions/cache@v4
+ with:
+ path: ~/.gradle/wrapper
+ key: gradle-wrapper-${{ hashFiles('**/gradle-wrapper.properties') }}
+
+ - name: Cache Gradle dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/caches/modules-*
+ ~/.gradle/caches/jars-*
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/gradle.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+
+ - name: Cache RFG
+ uses: actions/cache@v4
+ with:
+ path: |
+ build/rfg
+ build/tmp/.cache/expanded
+ build/tmp/deobfuscateMergedJarToSrg
+ key: ${{ runner.os }}-rfg-convention${{ steps.convention.outputs.version }}
+ restore-keys: |
+ ${{ runner.os }}-rfg-
+
+ - name: Cache Node modules
+ uses: actions/cache@v4
+ with:
+ path: .github/pages/node_modules
+ key: ${{ runner.os }}-node-${{ hashFiles('.github/pages/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+
+ - name: Resolve CNPC+ Javadoc URL
+ id: cnpc_docs
+ run: |
+ BRANCH="${GITHUB_REF#refs/heads/}"
+ CNPC_BASE="https://kamkeel.github.io/CustomNPC-Plus"
+
+ if [ "$BRANCH" = "main" ]; then
+ # Main branch links to CNPC+ master (releases/)
+ cd CustomNPC-Plus
+ if [ -f "gradle.properties" ] && grep -q "^modVersion=" gradle.properties; then
+ CNPC_VER=$(grep "^modVersion=" gradle.properties | cut -d'=' -f2 | tr -d '[:space:]')
+ elif [ -f "gradle.properties" ] && grep -q "^version=" gradle.properties; then
+ CNPC_VER=$(grep "^version=" gradle.properties | cut -d'=' -f2 | tr -d '[:space:]')
+ elif [ -f "build.gradle" ]; then
+ CNPC_VER=$(grep "^version" build.gradle | head -1 | sed "s/version\s*=\s*['\"]//;s/['\"].*//;s/\s//g")
+ else
+ CNPC_VER="unknown"
+ fi
+ cd ..
+ CNPC_DOC_URL="${CNPC_BASE}/releases/${CNPC_VER}"
+ echo "Linking Gecko main -> CNPC+ releases/${CNPC_VER}"
+ else
+ # Dev / experimental branches link to CNPC+ experimental/
+ SAFE_BRANCH="${BRANCH//\//-}"
+ CNPC_DOC_URL="${CNPC_BASE}/experimental/${SAFE_BRANCH}"
+ echo "Linking Gecko ${BRANCH} -> CNPC+ experimental/${SAFE_BRANCH}"
+ fi
+
+ # Download the element-list so javadoc can resolve cross-references
+ mkdir -p build/cnpc-element-list
+ if curl -fsSL "${CNPC_DOC_URL}/element-list" -o build/cnpc-element-list/element-list; then
+ echo "Downloaded element-list from ${CNPC_DOC_URL}"
+ elif curl -fsSL "${CNPC_DOC_URL}/package-list" -o build/cnpc-element-list/element-list; then
+ echo "Downloaded package-list (JDK 8 format) from ${CNPC_DOC_URL}"
+ else
+ echo "::warning::Could not download element-list from ${CNPC_DOC_URL}. Cross-links to CNPC+ will not work."
+ fi
+
+ echo "url=${CNPC_DOC_URL}" >> $GITHUB_OUTPUT
+
+ - name: Generate Javadoc
+ run: |
+ ./gradlew javadoc \
+ -PcnpcDocUrl=${{ steps.cnpc_docs.outputs.url }} \
+ -PcnpcDocElementList=build/cnpc-element-list
+
+ - name: Get deploy path
+ id: deploy_path
+ run: bash .github/scripts/resolve-doc-path.sh
+
+ - name: Deploy to gh-pages
+ if: steps.deploy_path.outputs.path != ''
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./build/docs/javadoc
+ destination_dir: ${{ steps.deploy_path.outputs.path }}
+ keep_files: true
+
+ # Give GitHub a moment to settle after the peaceiris push
+ - name: Wait for gh-pages to settle
+ run: sleep 10
+
+ - name: Checkout gh-pages
+ uses: actions/checkout@v4
+ with:
+ ref: gh-pages
+ path: gh-pages-index
+
+ - name: Generate manifest
+ run: |
+ cd gh-pages-index
+ SOURCE_HASH="${{ steps.source_commit.outputs.hash }}" \
+ SOURCE_DATE="${{ steps.source_commit.outputs.date }}" \
+ DEPLOY_PATH="${{ steps.deploy_path.outputs.path }}" \
+ bash ../.github/scripts/generate-index.sh
+
+ - name: Install page dependencies
+ run: npm ci --prefix .github/pages
+
+ - name: Build index page
+ run: |
+ mkdir -p .github/pages/public
+ cp gh-pages-index/manifest.json .github/pages/public/manifest.json
+ npm run build --prefix .github/pages
+
+ - name: Deploy index to gh-pages
+ run: |
+ cp -r .github/pages-dist/* gh-pages-index/
+ cd gh-pages-index
+ git config user.name "github-actions"
+ git config user.email "github-actions@github.com"
+ git add -A
+ git commit -m "Regenerate index and manifest [skip ci]" || echo "Unchanged"
+ git push
+
+ cleanup-on-delete:
+ if: github.event_name == 'delete' && github.event.ref_type == 'branch'
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout gh-pages
+ uses: actions/checkout@v4
+ with:
+ ref: 'gh-pages'
+
+ - name: Remove deleted branch docs
+ run: |
+ BRANCH="${{ github.event.ref }}"
+ SAFE="experimental/${BRANCH//\//-}"
+ if [ -d "./$SAFE" ]; then
+ rm -rf "./$SAFE"
+ META_KEY="${SAFE//\//_}"
+ rm -f ".doc-meta/${META_KEY}.json"
+ git config user.name "github-actions"
+ git config user.email "github-actions@github.com"
+ git add -A
+ git commit -m "Remove docs for deleted branch: $BRANCH"
+ git push
+ else
+ echo "No docs found for $SAFE, skipping."
+ fi
diff --git a/.gitignore b/.gitignore
index c14be0d..da701c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,7 @@ layout.json
# Generated D.TS files (rebuilt by gradle on every build)
src/main/resources/assets/npcgecko/api
+
+# GitHub Pages build output
+.github/pages-dist/
+.github/pages/node_modules/
diff --git a/build.gradle b/build.gradle
index dcec51b..c682bd9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,3 +29,32 @@ tasks.named("generateTypeScriptDefinitions").configure {
}
processResources.dependsOn generateTypeScriptDefinitions
sourcesJar.dependsOn generateTypeScriptDefinitions
+
+// ============================================================================
+// Javadoc Generation (for GitHub Pages deployment)
+// ============================================================================
+javadoc {
+ options.encoding = 'UTF-8'
+ options.charSet = 'UTF-8'
+ options.docEncoding = 'UTF-8'
+
+ options.stylesheetFile = file('.github/javadoc/javadoc-theme.css')
+ options.header = file('.github/javadoc/javadoc-header.html').text
+ options.footer = file('.github/javadoc/javadoc-footer.html').text
+
+ options.addBooleanOption('-allow-script-in-comments', true)
+
+ // Only document public API
+ include 'com/goodbird/npcgecko/api/**'
+
+ options.links('https://docs.oracle.com/en/java/javase/11/docs/api/')
+
+ // Cross-link to CNPC+ javadoc (URL injected by CI workflow)
+ if (project.hasProperty('cnpcDocUrl') && project.hasProperty('cnpcDocElementList')) {
+ options.linksOffline(project.property('cnpcDocUrl'), project.property('cnpcDocElementList'))
+ }
+
+ javadocTool = javaToolchains.javadocToolFor {
+ languageVersion = JavaLanguageVersion.of(11)
+ }
+}
diff --git a/gradle.properties b/gradle.properties
index 9d0a507..6e726ac 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,7 +3,7 @@ modName = CustomNPC-Plus-Gecko-Addon
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
modId = npcgecko
modGroup = com.goodbird.npcgecko
-modVersion = 1.3
+modVersion = 1.4
gtnh.modules.codeStyle=true
gtnh.modules.gitVersion=false
diff --git a/src/main/java/com/goodbird/npcgecko/CustomNpcPlusGecko.java b/src/main/java/com/goodbird/npcgecko/CustomNpcPlusGecko.java
index cd04e5e..11f4525 100644
--- a/src/main/java/com/goodbird/npcgecko/CustomNpcPlusGecko.java
+++ b/src/main/java/com/goodbird/npcgecko/CustomNpcPlusGecko.java
@@ -4,10 +4,11 @@ import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
+import noppes.npcs.controllers.APIRegistry;
@Mod(modid = "npcgecko",
name = "CustomNPC+ Gecko Addon",
- version = "1.3",
+ version = "1.4",
dependencies = "required-after:customnpcs;required-after:geckolib3")
public class CustomNpcPlusGecko {
@@ -25,5 +26,6 @@ public class CustomNpcPlusGecko {
@Mod.EventHandler
public void init(FMLInitializationEvent ev) {
proxy.init(ev);
+ APIRegistry.Instance.register("Gecko Addon API", "https://kamkeel.github.io/CustomNPC-Gecko-Addon/");
}
}