diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cada55b..c7eafff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,7 @@ name: CI on: push: + branches: [main] pull_request: workflow_dispatch: {} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..ad7b31e --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,56 @@ +name: docs + +on: + push: + branches: [main] + paths: + - "docs/**" + - ".github/workflows/docs.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + env: + BASE_PATH: /${{ github.event.repository.name }}/ + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + with: + node-version: "24" + cache: npm + cache-dependency-path: docs/package-lock.json + + - uses: actions/configure-pages@v5 + + - name: Install docs dependencies + working-directory: docs + run: npm ci + + - name: Build site + working-directory: docs + run: npm run build + + - uses: actions/upload-pages-artifact@v5 + with: + path: docs/.vitepress/dist + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v5 diff --git a/.gitignore b/.gitignore index df4a039..7e8e06b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,9 +32,13 @@ dependency-reduced-pom.xml *.log .env .env.* -harness/configs/.env -!harness/configs/.env.example +!.env.example ### Conformance / temp ### server/conformance-run.log **/node_modules/ + +### Docs ### +/docs/node_modules/ +/docs/.vitepress/cache/ +/docs/.vitepress/dist/ diff --git a/README.md b/README.md index bef1a2f..3216704 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ A durable stream engine on object storage, with storage, metadata, and protocol

- - Stream Stack architecture + + Stream Stack architecture

@@ -20,34 +20,48 @@ mvn clean package ## Quickstart ```bash -docker compose --env-file harness/configs/minio.env \ - -f harness/docker/docker-compose.minio.yml \ - -f harness/docker/docker-compose.ds.yml \ +cp harness/local/.env.example harness/local/.env +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.ds.yml \ up -d --build ``` -Node listens on `127.0.0.1:4437`. MinIO, cluster, and topo files: [harness/README.md](harness/README.md). +Node listens on `127.0.0.1:4437`. MinIO, cluster, AWS, and Fly: [harness/README.md](harness/README.md). ## Deployment -Create data and WAL S3 buckets. Copy `harness/configs/.env.example` to `harness/configs/.env` and fill `AWS_*`, `DATA_BUCKET`, and `WAL_BUCKET`. +Create data and WAL S3 buckets. Copy `harness/aws/.env.example` to `harness/aws/.env` and fill `AWS_*`, `DATA_BUCKET`, and `WAL_BUCKET`. ```bash -docker compose --env-file harness/configs/.env \ - -f harness/docker/docker-compose.ds.yml \ +docker compose --env-file harness/aws/.env \ + -f harness/aws/docker-compose.ds.yml \ up -d --build ``` -Swap `docker-compose.ds.yml` for `docker-compose.s2.yml` to run S2 facade. Node listens on `127.0.0.1:4437`. +Swap `docker-compose.ds.yml` for `docker-compose.s2.yml` to run S2 facade. Node listens on `127.0.0.1:4437`. Three nodes: `harness/aws/docker-compose.cluster.ds.yml`. -Multi-Node (3 nodes) cluster (ports 4437–4439): +Multi-node (3 nodes) local cluster (ports 4437–4439): ```bash -docker compose --env-file harness/configs/.env \ - -f harness/docker/docker-compose.cluster.ds.yml \ +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.cluster.ds.yml \ up -d --build ``` +## Documentation + +The documentation source is in [`docs/pages`](docs/pages). + +```bash +cd docs +npm install +npm run dev +``` + +Open http://localhost:5173. + ## License Apache 2.0. diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 0000000..4523c23 --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,74 @@ +import { defineConfig } from 'vitepress'; + +function sideItem(label: string, link: string, path: string) { + return { + text: `${label}`, + link, + }; +} + +export default defineConfig({ + title: 'Stream Stack', + description: 'A durable stream engine on object storage.', + base: process.env.BASE_PATH ?? '/', + cleanUrls: true, + appearance: 'force-dark', + srcDir: 'pages', + vite: { + publicDir: 'assets', + }, + markdown: { + theme: 'github-dark', + }, + head: [ + ['link', { rel: 'icon', href: '/images/favicon.ico', sizes: 'any' }], + ['link', { rel: 'icon', type: 'image/svg+xml', href: '/images/logo.svg' }], + [ + 'script', + {}, + `(function(){function m(h,a){var n=parseInt(h.slice(1),16),r=n>>16,g=n>>8&255,b=n&255;return'#'+[r,g,b].map(function(c){c=Math.round(c+(255-c)*a);return c.toString(16).padStart(2,'0')}).join('')}try{var h=localStorage.getItem('ss-accent-hex-v2');if(h&&/^#[0-9a-fA-F]{6}$/.test(h)){var s=document.documentElement.style;var n=parseInt(h.slice(1),16);s.setProperty('--vp-c-brand-1',h);s.setProperty('--vp-c-brand-2',m(h,.18));s.setProperty('--vp-c-brand-3',m(h,.36));s.setProperty('--vp-c-brand-soft','rgb('+(n>>16)+' '+(n>>8&255)+' '+(n&255)+' / 0.14)')}}catch(e){}})();`, + ], + ], + themeConfig: { + siteTitle: false, + nav: [ + { text: 'Home', link: '/' }, + { text: 'Docs', link: '/introduction' }, + ], + sidebar: [ + sideItem( + 'Introduction', + '/introduction', + '', + ), + sideItem( + 'Quickstart', + '/quickstart', + '', + ), + sideItem( + 'Benchmark', + '/benchmark', + '', + ), + sideItem( + 'Deployment', + '/deployment', + '', + ), + ], + search: { + provider: 'local', + }, + socialLinks: [ + { icon: 'github', link: 'https://github.com/Modak-Labs/streamstack' }, + ], + outline: { + level: [1, 3], + label: 'On this page', + }, + footer: { + copyright: '© 2026 Modak Labs. Apache 2.0.', + }, + }, +}); diff --git a/docs/.vitepress/theme/ColorSwitch.vue b/docs/.vitepress/theme/ColorSwitch.vue new file mode 100644 index 0000000..bafefea --- /dev/null +++ b/docs/.vitepress/theme/ColorSwitch.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/docs/.vitepress/theme/HeroDither.vue b/docs/.vitepress/theme/HeroDither.vue new file mode 100644 index 0000000..021d08e --- /dev/null +++ b/docs/.vitepress/theme/HeroDither.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/docs/.vitepress/theme/HomeBento.vue b/docs/.vitepress/theme/HomeBento.vue new file mode 100644 index 0000000..3f84cac --- /dev/null +++ b/docs/.vitepress/theme/HomeBento.vue @@ -0,0 +1,248 @@ + + + diff --git a/docs/.vitepress/theme/HomeChips.vue b/docs/.vitepress/theme/HomeChips.vue new file mode 100644 index 0000000..7ae7a19 --- /dev/null +++ b/docs/.vitepress/theme/HomeChips.vue @@ -0,0 +1,183 @@ + + + diff --git a/docs/.vitepress/theme/SiteLogo.vue b/docs/.vitepress/theme/SiteLogo.vue new file mode 100644 index 0000000..25dce63 --- /dev/null +++ b/docs/.vitepress/theme/SiteLogo.vue @@ -0,0 +1,28 @@ + + + diff --git a/docs/.vitepress/theme/accent.ts b/docs/.vitepress/theme/accent.ts new file mode 100644 index 0000000..d619e2f --- /dev/null +++ b/docs/.vitepress/theme/accent.ts @@ -0,0 +1,68 @@ +const KEY = 'ss-accent-hex-v2'; +export const DEFAULT_ACCENT = '#ffffff'; + +export const SWATCHES = [ + '#ffffff', + '#8096ff', + '#cc8b00', + '#80ff96', + '#ff6b6b', + '#f97316', + '#a78bfa', + '#22d3ee', +] as const; + +function safeGet(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } +} + +function isHex(value: string): boolean { + return /^#[0-9a-fA-F]{6}$/.test(value); +} + +function parseRgb(hex: string): [number, number, number] { + const n = parseInt(hex.slice(1), 16); + + return [n >> 16, (n >> 8) & 255, n & 255]; +} + +function toHex(r: number, g: number, b: number): string { + return `#${[r, g, b] + .map((c) => Math.round(c).toString(16).padStart(2, '0')) + .join('')}`; +} + +function mixWhite(hex: string, amount: number): string { + const [r, g, b] = parseRgb(hex); + + return toHex(r + (255 - r) * amount, g + (255 - g) * amount, b + (255 - b) * amount); +} + +export function readAccentHex(): string { + const stored = safeGet(KEY); + + return stored && isHex(stored) ? stored : DEFAULT_ACCENT; +} + +export function applyAccentHex(hex: string) { + const value = isHex(hex) ? hex : DEFAULT_ACCENT; + const [r, g, b] = parseRgb(value); + const root = document.documentElement.style; + + root.setProperty('--vp-c-brand-1', value); + root.setProperty('--vp-c-brand-2', mixWhite(value, 0.18)); + root.setProperty('--vp-c-brand-3', mixWhite(value, 0.36)); + root.setProperty('--vp-c-brand-soft', `rgb(${r} ${g} ${b} / 0.14)`); + + try { + localStorage.setItem(KEY, value); + } catch { + // ignore + } + + window.dispatchEvent(new CustomEvent('ss-accent', { detail: value })); +} diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css new file mode 100644 index 0000000..22326c2 --- /dev/null +++ b/docs/.vitepress/theme/custom.css @@ -0,0 +1,430 @@ +:root { + --vp-font-family-base: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", + sans-serif; + --vp-font-family-mono: + "JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", monospace; + --vp-c-brand-1: #ffffff; + --vp-c-brand-2: #ffffff; + --vp-c-brand-3: #ffffff; + --vp-c-brand-soft: rgb(255 255 255 / 0.14); + --vp-c-bg: #0c0c0d; + --vp-c-bg-alt: #141416; + --vp-c-bg-elv: #19191c; + --vp-c-divider: #2b2b2f; + --vp-c-gutter: #202024; + --vp-c-text-1: #f5f5f3; + --vp-c-text-2: #a7a7a1; + --vp-nav-bg-color: rgb(12 12 13 / 0.9); + --vp-sidebar-bg-color: var(--vp-c-bg); + --vp-code-color: var(--vp-c-brand-2); + --vp-code-bg: rgb(20 20 22 / 0.85); + --vp-code-block-bg: #141416; + --vp-code-block-color: #c8c8c2; + --vp-code-block-divider-color: #2b2b2f; + --vp-code-copy-code-bg: #19191c; + --vp-code-copy-code-hover-bg: #0c0c0d; + --vp-home-hero-name-color: #f5f5f3; + --vp-home-hero-name-background: none; + --ss-content-max: 1180px; + --ss-content-pad: 24px; + --ss-radius: 2px; + --vp-sidebar-width: 320px; + --ss-outline-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M8 6.5h12M8 12h12M8 17.5h12' stroke='black' stroke-width='1.7' stroke-linecap='round'/%3E%3Cpath d='M4 6.5h.01M4 12h.01M4 17.5h.01' stroke='black' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E"); +} + +@media (min-width: 640px) { + :root { + --ss-content-pad: 48px; + } +} + +@media (min-width: 960px) { + :root { + --ss-content-pad: 64px; + } +} + +.ss-wrap, +.VPFooter .container { + box-sizing: border-box; + width: min(var(--ss-content-max), calc(100% - (2 * var(--ss-content-pad)))); + margin-inline: auto; +} + +.VPNav { + backdrop-filter: blur(14px); +} + +.VPNavBar, +.VPNavBar.home, +.VPNavBar.home.top, +.VPNavBar .content-body { + background-color: var(--vp-nav-bg-color) !important; +} + +.VPNavBar .wrapper { + padding-left: var(--ss-content-pad) !important; + padding-right: var(--ss-content-pad) !important; +} + +.VPNavBar .container { + max-width: var(--ss-content-max) !important; + width: 100%; +} + +.VPNavBar .title { + width: auto !important; +} + +.VPNavBar .title svg { + width: 32px !important; + height: 32px !important; + max-height: 32px !important; + flex: none; +} + +@media (min-width: 960px) { + .VPNavBar.has-sidebar .title { + position: static !important; + width: auto !important; + padding: 0 !important; + height: calc(var(--vp-nav-height) - 1px) !important; + } + + .VPNavBar.has-sidebar .content { + padding-left: 0 !important; + padding-right: 0 !important; + } + + .VPNavBar.has-sidebar .divider { + padding-left: 0 !important; + } + + .VPNavBarTitle.has-sidebar .title { + border-bottom-color: transparent !important; + } +} + +.VPHome, +.VPContent.is-home { + overflow: visible; +} + +.VPHome { + position: relative; +} + +.VPHero { + position: relative; + isolation: isolate; + overflow: visible; + padding-top: clamp(5rem, 12vw, 9rem) !important; + padding-bottom: clamp(4rem, 8vw, 7rem) !important; +} + +.VPHero .container { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + max-width: var(--ss-content-max); +} + +.VPHero .main { + width: 100% !important; + max-width: 900px; +} + +.VPHero .name { + margin-bottom: 0.85rem; + font-size: clamp(1rem, 1.55vw, 1.15rem); + font-weight: 400; + line-height: 1.2; + letter-spacing: 0.02em; + color: var(--vp-c-text-1); +} + +.VPHero .text { + max-width: 900px; + font-size: clamp(3rem, 7vw, 6.5rem); + line-height: 0.96; + letter-spacing: -0.065em; + color: var(--vp-c-text-1); +} + +.VPHero .tagline { + max-width: 650px; + margin-top: 2rem; + font-size: clamp(1.1rem, 2vw, 1.4rem); + line-height: 1.55; +} + +.VPHero .actions { + padding-top: 2rem; +} + +.VPButton { + display: inline-flex !important; + align-items: center; + justify-content: center; + min-height: 46px; + padding: 0 22px !important; + border-radius: var(--ss-radius) !important; + font-size: 15px !important; + line-height: 1 !important; +} + +.VPButton.brand { + border-color: var(--vp-c-text-1) !important; + background: var(--vp-c-text-1) !important; + color: var(--vp-c-bg) !important; +} + +.VPButton.brand:hover { + opacity: 0.82; +} + +.VPButton.alt { + border-color: var(--vp-c-divider) !important; + background: transparent !important; +} + +.VPDoc h1, +.VPDoc h2, +.VPDoc h3 { + letter-spacing: -0.035em; +} + +.VPDoc h1 { + font-size: clamp(2.25rem, 5vw, 3.5rem); + line-height: 1.05; +} + +.vp-doc h2:first-of-type { + margin-top: 1.25rem; + padding-top: 0; + border-top: none; +} + +.vp-doc div[class*="language-"] { + border: 1px solid var(--vp-c-divider); + border-radius: var(--ss-radius) !important; + background: var(--vp-code-block-bg) !important; +} + +.vp-doc div[class*="language-"] pre, +.vp-doc div[class*="language-"] code, +.vp-doc div[class*="language-"] .shiki { + background: transparent !important; +} + +.DocSearch-Button, +.vp-doc .custom-block, +.vp-doc [class*="language-"] > button.copy, +.vp-code-group, +.vp-code-group .tabs, +.VPDocFooter .pager-link, +.VPLocalNavOutlineDropdown .items, +.VPLocalSearchBox .shell, +.VPLocalSearchBox input, +.VPLocalSearchBox div[class*="language-"], +.VPMenu, +.VPFlyout, +.vp-doc :not(pre) > code, +.vp-doc kbd { + border-radius: var(--ss-radius) !important; +} + +.DocSearch-Button .DocSearch-Button-Key { + border-radius: var(--ss-radius) 0 0 var(--ss-radius) !important; +} + +.DocSearch-Button .DocSearch-Button-Key + .DocSearch-Button-Key { + border-radius: 0 var(--ss-radius) var(--ss-radius) 0 !important; +} + +.VPFooter { + padding: 0 0 2rem !important; + border-top: none !important; + background: transparent !important; +} + +.VPFooter .container { + max-width: none; + margin-top: 0; + padding: 1.25rem 0 0; + border-top: 1px solid rgb(255 255 255 / 0.08); + text-align: left; +} + +.VPFooter .copyright, +.ss-doc-copyright { + font-size: 0.8rem; + font-weight: 500; + color: var(--vp-c-text-2); +} + +.VPDocFooter .ss-side-ico { + display: none; +} + +@media (min-width: 960px) { + .VPDoc.has-sidebar { + padding-left: 16px !important; + } + + .VPDoc.has-sidebar .content { + padding-bottom: 2.5rem; + padding-left: 16px; + } + + .VPSidebar { + padding-top: calc(var(--vp-nav-height) + 48px) !important; + padding-right: 20px !important; + } +} + +.VPSidebarItem.level-0 { + padding-bottom: 4px !important; +} + +.VPSidebarItem.level-0.is-link .text { + font-weight: 500; + color: var(--vp-c-text-2); +} + +.VPSidebarItem .item { + border-radius: var(--ss-radius); +} + +.VPSidebarItem .link { + min-height: 2.15rem; + padding: 0.35rem 0.65rem; + border-radius: var(--ss-radius); +} + +.VPSidebarItem .text { + display: flex; + align-items: center; + gap: 0.55rem; +} + +.VPSidebarItem .link:hover { + background: rgb(255 255 255 / 0.04); +} + +.VPSidebarItem .link:hover .text, +.VPSidebarItem .link:hover .ss-side-ico { + color: var(--vp-c-brand-1) !important; +} + +.VPSidebarItem.is-active > .item > .link { + background: var(--vp-c-brand-soft); +} + +.VPSidebarItem.is-active > .item .link > .text, +.VPSidebarItem.is-active .ss-side-ico { + color: var(--vp-c-brand-1) !important; +} + +.ss-side-ico { + display: inline-flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 1.05rem; + height: 1.05rem; + color: var(--vp-c-text-2); +} + +.ss-side-ico svg { + width: 100%; + height: 100%; +} + +.VPDocAsideOutline { + display: block !important; +} + +.VPDocAsideOutline .outline-title { + display: flex; + align-items: center; + gap: 0.55rem; + letter-spacing: -0.02em; + color: var(--vp-c-text-1); +} + +.VPDocAsideOutline .outline-title::before { + flex-shrink: 0; + width: 1.05rem; + height: 1.05rem; + background-color: currentColor; + -webkit-mask: var(--ss-outline-ico) center / contain no-repeat; + mask: var(--ss-outline-ico) center / contain no-repeat; + content: ""; +} + +.ss-cli { + display: grid; + gap: 0.75rem; + margin: 1.1rem 0 1.35rem; +} + +.ss-cli__row { + display: grid; + grid-template-columns: 5.5rem minmax(0, 1fr); + align-items: stretch; + gap: 0.65rem; +} + +.ss-cli__row > p { + display: flex; + align-items: center; + margin: 0; +} + +.ss-cli__label { + font-size: 0.72rem; + font-weight: 600; + letter-spacing: 0.04em; + line-height: 1.2; + text-transform: uppercase; + color: var(--vp-c-text-2); +} + +.vp-doc .ss-cli div[class*="language-"] { + margin: 0; +} + +@media (max-width: 639px) { + .ss-cli__row { + grid-template-columns: minmax(0, 1fr); + gap: 0.35rem; + } +} + +.VPNavBar .social-links { + margin-right: 0 !important; +} + +.VPNavBar .VPSocialLinks { + height: var(--vp-nav-height); +} + +.VPNavBar .VPSocialLink { + width: 36px; + height: 36px; +} + +.VPNavBar .VPSocialLink > * { + display: block; + flex-shrink: 0; +} + +.VPNavBar .VPSocialLink svg, +.VPNavBar .VPSocialLink [class^="vpi-social-"] { + display: block; + width: 20px; + height: 20px; +} diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..2300b26 --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,24 @@ +import DefaultTheme from 'vitepress/theme'; +import { h } from 'vue'; +import type { Theme } from 'vitepress'; +import ColorSwitch from './ColorSwitch.vue'; +import HeroDither from './HeroDither.vue'; +import HomeChips from './HomeChips.vue'; +import HomeBento from './HomeBento.vue'; +import SiteLogo from './SiteLogo.vue'; +import './custom.css'; + +export default { + extends: DefaultTheme, + Layout: () => { + return h(DefaultTheme.Layout, null, { + 'nav-bar-title-before': () => h(SiteLogo), + 'nav-bar-content-after': () => h(ColorSwitch), + 'home-hero-before': () => h(HeroDither), + 'home-hero-after': () => h(HomeChips), + 'home-features-after': () => h(HomeBento), + 'doc-after': () => + h('p', { class: 'ss-doc-copyright' }, '© 2026 Modak Labs. Apache 2.0.'), + }); + }, +} satisfies Theme; diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 0000000..ba85e1c --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,2544 @@ +{ + "name": "streamstack-docs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "streamstack-docs", + "dependencies": { + "@paper-design/shaders": "0.0.80" + }, + "devDependencies": { + "vitepress": "^1.6.4" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.22.0.tgz", + "integrity": "sha512-BFR6zNowNKcY7Ou7TaJc9QWexES4YKPbmf/OTFofpdsdhz4x6q0lbxp3duO0EHnyrN7rE4ba/TSXuY+BDGu4+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.56.0.tgz", + "integrity": "sha512-7r4Z3NC7yU1oAQVWJNA2HX7tX481F3pJvCGyLIXiTdBcthz4Q/o21jwcMYDFkuI92UWTNBQQmHYgwHo1zS5dzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.56.0.tgz", + "integrity": "sha512-avmjXQSq+jadFO8Xl2em05/uQdQnEmHsJyOAdVbZkmVgpMfxL12aJwVVfGNwYr9nulcpuJN1X0lTaQ5wxuNGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.56.0.tgz", + "integrity": "sha512-v2TPStUhY//ripPjIVclZ8AWc7DEGooXULZGFlFu37zNatgHjw34oZZ+OSbbc/YHO+xZwPl62I1k8xH1m4S2eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.56.0.tgz", + "integrity": "sha512-P0ehROpM4Sem3Sqo5x2cKPgj67D3G3jy0rh1Amwkcvsfr6tkvIcdCmerieanqTF7NxUMPNFLkpIFeMO8Rpa50w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.56.0.tgz", + "integrity": "sha512-SXK3Vn3WVxyzbm31oePZBJkp1wpOyuWdd4B/Pv7n0aXDxmeSWhC1R1FC1517mMrFAIaPH4Rt0x6RUe7ZNjz8FA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.56.0.tgz", + "integrity": "sha512-5+ZdX8garFnmycnZgKhtXHePEaLj5zqDxI/0lkhhluzCcvTn0/PvvTirTg8hHYetQHvn7GDyeAiqTAieMvMW4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.56.0.tgz", + "integrity": "sha512-+mKUdYvqOi0BcvpAEyCEw49vSBptufIcfibtHz2bdr1pI789M46Yt0uQEk/sxtK3teh71OQvVFHaTDzShUWewQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.56.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.56.0.tgz", + "integrity": "sha512-9g/zj+AZx5moFcdFIrYQoVrueXivjUcc3MQHtCYT8WhIuk1lUh1AyEhvJCS0XBZld09cLvd1AZ3BvDBpVpX2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.56.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.56.0.tgz", + "integrity": "sha512-Qf3Sr6f9A9uxCZUf3MXS0d2b877uYzEB5yxqpVGXAhcJnBCQjrRRon0KvefpGkxy+BshrIJs96OUoMtGqXTFDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.56.0.tgz", + "integrity": "sha512-GXWG1rWc5wu8hY4N33Y3b6ernY6sAdAvmKWN/zHAiACOx40WnpG0TVX5YazCAr/9gOYGInSiM2A0y2jy2xbiDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.56.0.tgz", + "integrity": "sha512-7t24cBxaInS3mZb7ddEaZT/tp6q+/aR4YttsQVyP1/i+LmwPR34atO35KjaLFCcRVrlP7sYOAqkCfg6lIRB+ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.56.0.tgz", + "integrity": "sha512-R7ePHgVYmDFjZpvrsVAfbDz/d4RxKAYZ5/vgLfIsCVRZRryjWl/3INOxpOICzitehQ5FjNtNjcLQTrmHPTcHBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.56.0.tgz", + "integrity": "sha512-PIOUXlSnrqM0S+WOgDRb4RzotydJH7ZoT6tOyL7tAO7qJOfvX5wsEW8Pe+PMKMwvuI4/gIyK9cg2H7lJXqnc4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.93", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.93.tgz", + "integrity": "sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "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/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@paper-design/shaders": { + "version": "0.0.80", + "resolved": "https://registry.npmjs.org/@paper-design/shaders/-/shaders-0.0.80.tgz", + "integrity": "sha512-pcabvt5xDlFoEhpjUj4b1tGJMfqb0i5mXifWMNQf6z7FoOJYxYDo7F8R6k0JAh5D/7ouxjX5+N0cIq5WURyQ1Q==", + "license": "Apache-2.0" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", + "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", + "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", + "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", + "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", + "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", + "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", + "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", + "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", + "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", + "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", + "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", + "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", + "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", + "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", + "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", + "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", + "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", + "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", + "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", + "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", + "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", + "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", + "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", + "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", + "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz", + "integrity": "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.41", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz", + "integrity": "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.41", + "@vue/shared": "3.5.41" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz", + "integrity": "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.41", + "@vue/compiler-dom": "3.5.41", + "@vue/compiler-ssr": "3.5.41", + "@vue/shared": "3.5.41", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.19", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz", + "integrity": "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.41", + "@vue/shared": "3.5.41" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz", + "integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.10" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz", + "integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.10", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz", + "integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz", + "integrity": "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.41" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.41.tgz", + "integrity": "sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.41", + "@vue/shared": "3.5.41" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.41.tgz", + "integrity": "sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.41", + "@vue/runtime-core": "3.5.41", + "@vue/shared": "3.5.41", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.41.tgz", + "integrity": "sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.41", + "@vue/runtime-dom": "3.5.41", + "@vue/shared": "3.5.41" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz", + "integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/algoliasearch": { + "version": "5.56.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.56.0.tgz", + "integrity": "sha512-PrqppUmhT4ENdas2pH9caE7efUcxy6EcSFhWzosiVuQBzu2tQ5yLTI6jwomT/1cuBnivzGfxiJCqDNN9FRRh+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.22.0", + "@algolia/client-abtesting": "5.56.0", + "@algolia/client-analytics": "5.56.0", + "@algolia/client-common": "5.56.0", + "@algolia/client-insights": "5.56.0", + "@algolia/client-personalization": "5.56.0", + "@algolia/client-query-suggestions": "5.56.0", + "@algolia/client-search": "5.56.0", + "@algolia/ingestion": "1.56.0", + "@algolia/monitoring": "1.56.0", + "@algolia/recommend": "5.56.0", + "@algolia/requester-browser-xhr": "5.56.0", + "@algolia/requester-fetch": "5.56.0", + "@algolia/requester-node-http": "5.56.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.4.0" + } + }, + "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/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "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/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "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/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "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.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", + "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.4", + "@rollup/rollup-android-arm64": "4.62.4", + "@rollup/rollup-darwin-arm64": "4.62.4", + "@rollup/rollup-darwin-x64": "4.62.4", + "@rollup/rollup-freebsd-arm64": "4.62.4", + "@rollup/rollup-freebsd-x64": "4.62.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", + "@rollup/rollup-linux-arm-musleabihf": "4.62.4", + "@rollup/rollup-linux-arm64-gnu": "4.62.4", + "@rollup/rollup-linux-arm64-musl": "4.62.4", + "@rollup/rollup-linux-loong64-gnu": "4.62.4", + "@rollup/rollup-linux-loong64-musl": "4.62.4", + "@rollup/rollup-linux-ppc64-gnu": "4.62.4", + "@rollup/rollup-linux-ppc64-musl": "4.62.4", + "@rollup/rollup-linux-riscv64-gnu": "4.62.4", + "@rollup/rollup-linux-riscv64-musl": "4.62.4", + "@rollup/rollup-linux-s390x-gnu": "4.62.4", + "@rollup/rollup-linux-x64-gnu": "4.62.4", + "@rollup/rollup-linux-x64-musl": "4.62.4", + "@rollup/rollup-openbsd-x64": "4.62.4", + "@rollup/rollup-openharmony-arm64": "4.62.4", + "@rollup/rollup-win32-arm64-msvc": "4.62.4", + "@rollup/rollup-win32-ia32-msvc": "4.62.4", + "@rollup/rollup-win32-x64-gnu": "4.62.4", + "@rollup/rollup-win32-x64-msvc": "4.62.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "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/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz", + "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.41.tgz", + "integrity": "sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.41", + "@vue/compiler-sfc": "3.5.41", + "@vue/runtime-dom": "3.5.41", + "@vue/server-renderer": "3.5.41", + "@vue/shared": "3.5.41" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..da61b3c --- /dev/null +++ b/docs/package.json @@ -0,0 +1,16 @@ +{ + "name": "streamstack-docs", + "private": true, + "type": "module", + "scripts": { + "dev": "vitepress dev", + "build": "vitepress build", + "preview": "vitepress preview" + }, + "devDependencies": { + "vitepress": "^1.6.4" + }, + "dependencies": { + "@paper-design/shaders": "0.0.80" + } +} diff --git a/docs/assets/architecture-dark.svg b/docs/pages/assets/images/architecture-dark.svg similarity index 100% rename from docs/assets/architecture-dark.svg rename to docs/pages/assets/images/architecture-dark.svg diff --git a/docs/assets/architecture-light.svg b/docs/pages/assets/images/architecture-light.svg similarity index 100% rename from docs/assets/architecture-light.svg rename to docs/pages/assets/images/architecture-light.svg diff --git a/docs/pages/assets/images/favicon.ico b/docs/pages/assets/images/favicon.ico new file mode 100644 index 0000000..e9b21d6 Binary files /dev/null and b/docs/pages/assets/images/favicon.ico differ diff --git a/docs/pages/assets/images/logo.svg b/docs/pages/assets/images/logo.svg new file mode 100644 index 0000000..4bc2882 --- /dev/null +++ b/docs/pages/assets/images/logo.svg @@ -0,0 +1,7 @@ + + + + diff --git a/docs/pages/benchmark.md b/docs/pages/benchmark.md new file mode 100644 index 0000000..c000c2f --- /dev/null +++ b/docs/pages/benchmark.md @@ -0,0 +1,69 @@ +# Benchmark + +Java 17+ (Java 21 recommended). Maven. [Docker](https://docs.docker.com/get-docker/). + +## Install + +```bash +mvn clean package +cp harness/local/.env.example harness/local/.env +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.ds.yml \ + up -d --build +``` + +The node listens on `127.0.0.1:4437`. CLI jar: `cli/target/streamstack.jar`. MinIO console: http://127.0.0.1:9001 (`minioadmin` / `minioadmin`). + +If the node comes up before the buckets exist (`NoSuchBucket`): + +```bash +docker restart local-node1-1 +``` + +If ports `9000-9001` are taken, stop leftover MinIO (`docker-minio-1` or similar) first. + +This bench can run against the Durable Streams protocol or the S2 protocol. Examples below use Durable Streams. + +## Smoke + +```bash +java -jar cli/target/streamstack.jar ds bench --endpoint http://127.0.0.1:4437 \ + -b 1024 -n 64 -w 8 -d 8 +``` + +Creates a temporary stream, pipelines 64-record JSON batches with 8 in-flight appends for 8s, live-reads them, then deletes. That path covers create, append, SSE read, and delete. + +`-b` is record size in bytes, `-n` records per append, `-w` concurrent appends, `-d` duration in seconds. `-t` throttles write MiB/s (`0` is unthrottled). + +## Load + +```bash +java -jar cli/target/streamstack.jar ds bench --endpoint http://127.0.0.1:4437 \ + -b 1024 -n 256 -w 32 -d 20 +``` + +Same path: 256 records per append, 32 in-flight, 20s. The node should sustain pipelined writes without 409s or timeouts. This is the run used on the homepage. + +```bash +java -jar cli/target/streamstack.jar ds bench --endpoint http://127.0.0.1:4437 \ + -b 1024 -n 512 -w 64 -d 60 +``` + +## Protocol + +The same runs work against S2. Stop the Durable Streams compose file, keep MinIO, bring S2 up on the same port. Basin names must be 8-48 characters. For S2, `-w` is in-flight MiB, not concurrent appends. + +```bash +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.ds.yml stop +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.s2.yml up -d --build +``` + +```bash +java -jar cli/target/streamstack.jar s2 bench --endpoint http://127.0.0.1:4437 demobasin \ + -b 1024 -n 64 -w 8 -d 8 +``` + +Creates basin `demobasin`, then a temp stream, producer-batches 64 records with an 8 MiB in-flight window, live-reads, then tears down. Heavier run: `-n 256 -w 16 -d 20`. A pass means no `SeqNumMismatch` or request-size errors. diff --git a/docs/pages/deployment.md b/docs/pages/deployment.md new file mode 100644 index 0000000..2d4efbb --- /dev/null +++ b/docs/pages/deployment.md @@ -0,0 +1,83 @@ +# Deployment + +`harness/docker` is the image. `local`, `aws`, and `fly` are how to run it. Each process is one node: raft, metadata, and the storage engine in one JVM. Durable Streams and S2 are protocol facades over that engine. Pick one per deployment. + +Storage comes from the topo file (`TOPO`). `DATA_BUCKET` / `WAL_BUCKET` / `BUCKET_NAME` override the topo S3 URIs. + +## Local cluster + +Three DS nodes on one host, ports `4437-4439` / `8091-8093`, against local MinIO. + +```bash +cp harness/local/.env.example harness/local/.env +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.cluster.ds.yml \ + up -d --build +``` + +Each service is a fixed `NODE_ID` (1 / 2 / 3). Host network so they bind the ports in `local/topo.cluster.yaml`. + +Bare JVM, same topo, one process per id: + +```bash +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.cluster.yaml --node-id 1 +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.cluster.yaml --node-id 2 +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.cluster.yaml --node-id 3 +``` + +## AWS + +Create data and WAL buckets. Copy `harness/aws/.env.example` to `harness/aws/.env` and fill `AWS_*`, `DATA_BUCKET`, and `WAL_BUCKET`. + +```bash +docker compose --env-file harness/aws/.env \ + -f harness/aws/docker-compose.ds.yml \ + up -d --build +``` + +Swap `docker-compose.ds.yml` for `docker-compose.s2.yml` to run the S2 facade. The node listens on `127.0.0.1:4437`. + +Three nodes on one host, ports `4437-4439`: + +```bash +docker compose --env-file harness/aws/.env \ + -f harness/aws/docker-compose.cluster.ds.yml \ + up -d --build +``` + +Bare JVM (creds from env / `~/.aws` / IAM): + +```bash +java -jar frontend/ds/server/target/ds-server.jar \ + --topo harness/aws/topo.yaml --node-id 1 \ + --storage "0@s3://${DATA_BUCKET}?region=${AWS_REGION}" \ + --wal "0@s3://${WAL_BUCKET}?region=${AWS_REGION}" +``` + +## Fly.io + +App name must stay `streamstack`. Storage is Tigris. + +```bash +fly launch --config harness/fly/fly.toml +fly storage create +fly deploy --config harness/fly/fly.toml +``` + +Three nodes: `--config harness/fly/fly.cluster.toml`. + +## Topology + +| File | Storage | +|------|---------| +| `local/topo.yaml` | MinIO via `host.docker.internal:9000` (container to host) | +| `local/topo.cluster.yaml` | Three nodes. MinIO via `127.0.0.1:9000` (host network / JVM) | +| `aws/topo.yaml` | Real `s3://` (no endpoint) | +| `aws/topo.cluster.yaml` | Three nodes on one host. Real `s3://` | +| `fly/topo.yaml` | One Fly Machine. Tigris (`region=auto`) | +| `fly/topo.cluster.yaml` | Three Fly process groups `n1-n3` | + +URI forms: `0@s3://bucket?region=us-east-1`, `-2@file:///path`, `0@mem://bucket` (tests). Omit `global.wal` to default WAL to the storage URI when storage is S3. + +`--topo` requires `--node-id`. CLI flags override topo values. Export credentials in the environment that starts the process. diff --git a/docs/pages/index.md b/docs/pages/index.md new file mode 100644 index 0000000..cfa0ff4 --- /dev/null +++ b/docs/pages/index.md @@ -0,0 +1,15 @@ +--- +layout: home + +hero: + name: STREAM STACK + text: Durable streams on object storage + tagline: Storage, metadata, and protocol as decoupled layers. + actions: + - theme: brand + text: Get started + link: /quickstart + - theme: alt + text: Docs + link: /introduction +--- diff --git a/docs/pages/introduction.md b/docs/pages/introduction.md new file mode 100644 index 0000000..84c188a --- /dev/null +++ b/docs/pages/introduction.md @@ -0,0 +1,3 @@ +# Introduction + +A durable stream engine on object storage, with storage, metadata, and protocol as the three primary decoupled layers. diff --git a/docs/pages/quickstart.md b/docs/pages/quickstart.md new file mode 100644 index 0000000..4c3390b --- /dev/null +++ b/docs/pages/quickstart.md @@ -0,0 +1,78 @@ +# Quickstart + +Java 17+ (Java 21 recommended). Maven. [Docker](https://docs.docker.com/get-docker/). + +Each node includes the `S3Stream` storage engine, the WAL, `JRaft` metadata, and a protocol facade. All of that lives in the same server. + +## Start a node + +```bash +mvn clean package +cp harness/local/.env.example harness/local/.env +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.ds.yml \ + up -d --build +``` + +The node listens on `127.0.0.1:4437`. MinIO console: http://127.0.0.1:9001 (`minioadmin` / `minioadmin`). + +If the node comes up before the buckets exist (`NoSuchBucket`): + +```bash +docker restart local-node1-1 +``` + +## Append and tail + +Create a stream, then tail in one terminal and append in another. + +
+ +
+ +Create + +```bash +java -jar cli/target/streamstack.jar ds create \ + --endpoint http://127.0.0.1:4437 demo +``` + +
+ +
+ +Tail + +```bash +java -jar cli/target/streamstack.jar ds tail -f \ + --endpoint http://127.0.0.1:4437 demo +``` + +
+ +
+ +Append + +```bash +java -jar cli/target/streamstack.jar ds append \ + --endpoint http://127.0.0.1:4437 demo +``` + +
+ +
+ +`append` reads stdin. Type a line, press enter, repeat. `tail -f` prints each line as it lands. + +## Protocol + +This example speaks Durable Streams. Same MinIO and port, S2 instead: + +```bash +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.s2.yml \ + up -d --build +``` diff --git a/harness/BENCH.md b/harness/BENCH.md new file mode 100644 index 0000000..6dacdf5 --- /dev/null +++ b/harness/BENCH.md @@ -0,0 +1,64 @@ +# Bench + +CLI jar: `cli/target/streamstack.jar`. Node: `127.0.0.1:4437`. + +If ports 9000–9001 are taken, stop leftover MinIO (`docker-minio-1` or similar) first. + +## Start DS + Local MinIO + +```bash +cp harness/local/.env.example harness/local/.env +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.ds.yml \ + up -d --build +``` + +If the node starts before buckets exist (`NoSuchBucket`): + +```bash +docker restart local-node1-1 +``` + +## DS Server + +```bash +java -jar cli/target/streamstack.jar ds bench --endpoint http://127.0.0.1:4437 \ + -b 1024 -n 64 -w 8 -d 8 +``` + +Creates a temporary stream, pipelines 64-record JSON batches with 8 in-flight appends for 8s, live-reads them, then deletes. Verifies: create / appends / SSE read / delete on the durable-streams protocol. + +```bash +java -jar cli/target/streamstack.jar ds bench --endpoint http://127.0.0.1:4437 \ + -b 1024 -n 256 -w 32 -d 20 +``` + +Same path, but heavier: 256 records per append, 32 in-flight, 20s. Verifies: the node can sustain pipelined writes without 409s or timeouts (expect ~40–80 MiB/s). + +## Start S2 + Local MinIO + +```bash +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.ds.yml stop +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.s2.yml up -d --build +``` + +Note: `Basin` name must be 8–48 chars. + +## S2 Server + +```bash +java -jar cli/target/streamstack.jar s2 bench --endpoint http://127.0.0.1:4437 demobasin \ + -b 1024 -n 64 -w 8 -d 8 +``` + +Creates basin `demobasin`, then a temp stream, producer-batches 64 records with an 8 MiB in-flight window, live-reads, then tears down. Verifies: basin, stream, appends, live reads on S2 facade. + +```bash +java -jar cli/target/streamstack.jar s2 bench --endpoint http://127.0.0.1:4437 demobasin \ + -b 1024 -n 256 -w 16 -d 20 +``` + +Same path, but heavier: 256-record batches and a 16 MiB in-flight window. Verifies: a single S2 writer can pipeline without `SeqNumMismatch` or request-size errors. diff --git a/harness/README.md b/harness/README.md index c78ba27..ed7b61b 100644 --- a/harness/README.md +++ b/harness/README.md @@ -1,43 +1,36 @@ # Streamstack Harness -The server **is** also the node: `DurableStreamsServer` and `S2Server` each embed the full `StreamStackNode` (raft, metadata, storage engine) in one JVM. +The server **is** also the node: `DurableStreamsServer` and `S2Server` each embed the full `StreamStackNode` (raft, metadata, storage engine) in one JVM. Running streamstack means running one server process per node. DS and S2 are alternative protocol facades over the same engine, pick one per deployment. -Storage is chosen by the topo file (`TOPO`), not by the facade compose file. Stack compose files with `-f` to combine a node with MinIO. -For AWS, set `DATA_BUCKET` / `WAL_BUCKET` to override the topo's S3 URIs without editing YAML, that rewrite drops any MinIO `endpoint` / `pathStyle`. +`harness/docker` is the image. `local`, `aws`, and `fly` are how to run it. Storage is chosen by the topo file (`TOPO`). `DATA_BUCKET` / `WAL_BUCKET` / `BUCKET_NAME` override the topo S3 URIs. -## Docker Compose - -| Compose file | What it runs | -|--------------|--------------| -| `docker-compose.minio.yml` | MinIO + bucket init | -| `docker-compose.ds.yml` | one DS node (`NODE_ID` 1) | -| `docker-compose.s2.yml` | one S2 node (`NODE_ID` 1) | -| `docker-compose.cluster.ds.yml` | three DS nodes (`topo.cluster.yaml`) | - -## MinIO +## Local (MinIO) ```bash -docker compose --env-file harness/configs/minio.env \ - -f harness/docker/docker-compose.minio.yml \ - -f harness/docker/docker-compose.ds.yml \ +cp harness/local/.env.example harness/local/.env +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.ds.yml \ up -d --build ``` -Swap `docker-compose.ds.yml` for `docker-compose.s2.yml` to run S2 instead. Node listens on `127.0.0.1:4437`. -MinIO console: http://127.0.0.1:9001 (`minioadmin` / `minioadmin`). On Linux, add `extra_hosts: ["host.docker.internal:host-gateway"]` to the node service so `topo.minio.yaml` can reach MinIO on the host. +Swap `docker-compose.ds.yml` for `docker-compose.s2.yml` to run S2 instead. Node listens on `127.0.0.1:4437`. -Bare JVM (`topo.minio.yaml` uses `host.docker.internal` for Docker, override to `127.0.0.1` on the host): +[BENCH.md](BENCH.md) has DS and S2 smoke/load tests. +MinIO console: http://127.0.0.1:9001 (`minioadmin` / `minioadmin`). + +Bare JVM (`local/topo.yaml` uses `host.docker.internal` for Docker, override to `127.0.0.1` on the host): ```bash -docker compose -f harness/docker/docker-compose.minio.yml up -d +docker compose -f harness/local/docker-compose.minio.yml up -d export AWS_ACCESS_KEY_ID=minioadmin export AWS_SECRET_ACCESS_KEY=minioadmin export AWS_REGION=us-east-1 mvn -pl frontend/ds/server -am package -DskipTests -java -jar frontend/ds/server/target/ds-server.jar --topo harness/configs/topo.minio.yaml --node-id 1 \ +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.yaml --node-id 1 \ --storage "0@s3://streams-data?region=us-east-1&endpoint=http://127.0.0.1:9000&pathStyle=true" \ --wal "0@s3://streams-wal?region=us-east-1&endpoint=http://127.0.0.1:9000&pathStyle=true" ``` @@ -47,53 +40,74 @@ Swap `frontend/ds/server` / `ds-server.jar` for `frontend/s2/server` / `s2-serve ## AWS S3 1. Create data + WAL buckets. -2. `cp harness/configs/.env.example harness/configs/.env` and fill `AWS_*`, `DATA_BUCKET`, `WAL_BUCKET`. +2. `cp harness/aws/.env.example harness/aws/.env` and fill `AWS_*`, `DATA_BUCKET`, `WAL_BUCKET`. + +```bash +docker compose --env-file harness/aws/.env \ + -f harness/aws/docker-compose.ds.yml \ + up -d --build +``` + +Swap `docker-compose.ds.yml` for `docker-compose.s2.yml` to run S2. Three nodes (ports 4437–4439): ```bash -docker compose --env-file harness/configs/.env \ - -f harness/docker/docker-compose.ds.yml \ +docker compose --env-file harness/aws/.env \ + -f harness/aws/docker-compose.cluster.ds.yml \ up -d --build ``` -Or bare JVM (creds from env / `~/.aws` / IAM): +Bare JVM (creds from env / `~/.aws` / IAM): ```bash java -jar frontend/ds/server/target/ds-server.jar \ - --topo harness/configs/topo.aws.yaml --node-id 1 \ + --topo harness/aws/topo.yaml --node-id 1 \ --storage "0@s3://${DATA_BUCKET}?region=${AWS_REGION}" \ --wal "0@s3://${WAL_BUCKET}?region=${AWS_REGION}" ``` -## Multi-node +## Multi-node (local) -`docker-compose.cluster.ds.yml` starts three DS processes against `topo.cluster.yaml`. Each service is a fixed `NODE_ID` (1 / 2 / 3). Host network so they bind 4437–4439 / 8091–8093 as in the topo. +`docker-compose.cluster.ds.yml` starts three DS processes against `local/topo.cluster.yaml`. Each service is a fixed `NODE_ID` (1 / 2 / 3). Host network so they bind 4437–4439 / 8091–8093 as in the topo. ```bash -docker compose --env-file harness/configs/minio.env \ - -f harness/docker/docker-compose.minio.yml \ - -f harness/docker/docker-compose.cluster.ds.yml \ +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.cluster.ds.yml \ up -d --build ``` Bare JVM, same topo, one process per id: ```bash -java -jar frontend/ds/server/target/ds-server.jar --topo harness/configs/topo.cluster.yaml --node-id 1 -java -jar frontend/ds/server/target/ds-server.jar --topo harness/configs/topo.cluster.yaml --node-id 2 -java -jar frontend/ds/server/target/ds-server.jar --topo harness/configs/topo.cluster.yaml --node-id 3 +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.cluster.yaml --node-id 1 +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.cluster.yaml --node-id 2 +java -jar frontend/ds/server/target/ds-server.jar --topo harness/local/topo.cluster.yaml --node-id 3 ``` -`topo.cluster.yaml` defaults to MinIO storage; set `DATA_BUCKET` / `WAL_BUCKET` (compose) or `--storage` / `--wal` (JVM) for AWS. +## Fly.io + Tigris + +App name must stay `streamstack`. + +```bash +fly launch --config harness/fly/fly.toml +fly storage create +fly deploy --config harness/fly/fly.toml +``` + +Three nodes: `--config harness/fly/fly.cluster.toml`. ## Topology | File | Storage | |------|---------| -| `topo.minio.yaml` | MinIO via `host.docker.internal:9000` (container → host) | -| `topo.aws.yaml` | Real `s3://` (no endpoint) | -| `topo.cluster.yaml` | Three nodes; MinIO via `127.0.0.1:9000` (host network / JVM) | - -URI forms: `0@s3://bucket?region=…`, `-2@file:///path`, `0@mem://bucket` (tests). +| `local/topo.yaml` | MinIO via `host.docker.internal:9000` (container → host) | +| `local/topo.cluster.yaml` | Three nodes; MinIO via `127.0.0.1:9000` (host network / JVM) | +| `aws/topo.yaml` | Real `s3://` (no endpoint) | +| `aws/topo.cluster.yaml` | Three nodes on one host; real `s3://` | +| `fly/topo.yaml` | One Fly Machine; Tigris (`region=auto`) | +| `fly/topo.cluster.yaml` | Three Fly process groups `n1`–`n3` | + +URI forms: `0@s3://bucket?region=…`, `-2@file:///path`, `0@mem://bucket` (tests). Omit `global.wal` to default WAL to the storage URI when storage is S3. `--topo` requires `--node-id`. CLI flags override topo values. Topo `global.envs` are informational — export credentials in the environment that starts the process. @@ -101,8 +115,8 @@ Omit `global.wal` to default WAL to the storage URI when storage is S3. ## Clean up ```bash -docker compose --env-file harness/configs/minio.env \ - -f harness/docker/docker-compose.minio.yml \ - -f harness/docker/docker-compose.ds.yml \ +docker compose --env-file harness/local/.env \ + -f harness/local/docker-compose.minio.yml \ + -f harness/local/docker-compose.ds.yml \ down -v ``` diff --git a/harness/configs/.env.example b/harness/aws/.env.example similarity index 67% rename from harness/configs/.env.example rename to harness/aws/.env.example index 49b917a..c749fa8 100644 --- a/harness/configs/.env.example +++ b/harness/aws/.env.example @@ -2,6 +2,5 @@ AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_SESSION_TOKEN= AWS_REGION=us-east-1 -TOPO=/opt/streamstack/harness/configs/topo.aws.yaml DATA_BUCKET= WAL_BUCKET= diff --git a/harness/docker/docker-compose.cluster.ds.yml b/harness/aws/docker-compose.cluster.ds.yml similarity index 78% rename from harness/docker/docker-compose.cluster.ds.yml rename to harness/aws/docker-compose.cluster.ds.yml index fdaa6a1..8376274 100644 --- a/harness/docker/docker-compose.cluster.ds.yml +++ b/harness/aws/docker-compose.cluster.ds.yml @@ -3,7 +3,7 @@ x-env: &env AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-} AWS_REGION: ${AWS_REGION:-us-east-1} - TOPO: /opt/streamstack/harness/configs/topo.cluster.yaml + TOPO: /opt/streamstack/topo/topo.cluster.yaml DATA_BUCKET: ${DATA_BUCKET:-} WAL_BUCKET: ${WAL_BUCKET:-} @@ -15,7 +15,7 @@ x-node: &node MODULE: frontend/ds/server JAR: ds-server.jar env_file: - - path: ../configs/.env + - path: .env required: false network_mode: host restart: on-failure @@ -27,7 +27,7 @@ services: <<: *env NODE_ID: "1" volumes: - - ../configs:/opt/streamstack/harness/configs:ro + - .:/opt/streamstack/topo:ro - node1-data:/tmp/streamstack node2: <<: *node @@ -35,7 +35,7 @@ services: <<: *env NODE_ID: "2" volumes: - - ../configs:/opt/streamstack/harness/configs:ro + - .:/opt/streamstack/topo:ro - node2-data:/tmp/streamstack node3: <<: *node @@ -43,7 +43,7 @@ services: <<: *env NODE_ID: "3" volumes: - - ../configs:/opt/streamstack/harness/configs:ro + - .:/opt/streamstack/topo:ro - node3-data:/tmp/streamstack volumes: diff --git a/harness/docker/docker-compose.ds.yml b/harness/aws/docker-compose.ds.yml similarity index 86% rename from harness/docker/docker-compose.ds.yml rename to harness/aws/docker-compose.ds.yml index 9df9b72..bd22119 100644 --- a/harness/docker/docker-compose.ds.yml +++ b/harness/aws/docker-compose.ds.yml @@ -7,19 +7,19 @@ services: MODULE: frontend/ds/server JAR: ds-server.jar env_file: - - path: ../configs/.env + - path: .env required: false environment: AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-} AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-} AWS_REGION: ${AWS_REGION:-us-east-1} - TOPO: ${TOPO} + TOPO: /opt/streamstack/topo/topo.yaml NODE_ID: "1" DATA_BUCKET: ${DATA_BUCKET:-} WAL_BUCKET: ${WAL_BUCKET:-} volumes: - - ../configs:/opt/streamstack/harness/configs:ro + - .:/opt/streamstack/topo:ro - node1-data:/tmp/streamstack ports: - "4437:4437" diff --git a/harness/docker/docker-compose.s2.yml b/harness/aws/docker-compose.s2.yml similarity index 86% rename from harness/docker/docker-compose.s2.yml rename to harness/aws/docker-compose.s2.yml index 8ff9d56..fa6efae 100644 --- a/harness/docker/docker-compose.s2.yml +++ b/harness/aws/docker-compose.s2.yml @@ -7,19 +7,19 @@ services: MODULE: frontend/s2/server JAR: s2-server.jar env_file: - - path: ../configs/.env + - path: .env required: false environment: AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-} AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-} AWS_REGION: ${AWS_REGION:-us-east-1} - TOPO: ${TOPO} + TOPO: /opt/streamstack/topo/topo.yaml NODE_ID: "1" DATA_BUCKET: ${DATA_BUCKET:-} WAL_BUCKET: ${WAL_BUCKET:-} volumes: - - ../configs:/opt/streamstack/harness/configs:ro + - .:/opt/streamstack/topo:ro - node1-data:/tmp/streamstack ports: - "4437:4437" diff --git a/harness/aws/topo.cluster.yaml b/harness/aws/topo.cluster.yaml new file mode 100644 index 0000000..ba7eb15 --- /dev/null +++ b/harness/aws/topo.cluster.yaml @@ -0,0 +1,25 @@ +# Three nodes on one host (ports 4437–4439 / 8091–8093). Real S3. DATA_BUCKET / WAL_BUCKET override the URIs. +global: + clusterName: aws + storage: 0@s3://streamstack-data?region=us-east-1 + wal: 0@s3://streamstack-wal?region=us-east-1 + config: + routing: REDIRECT + walCacheSize: 209715200 + blockCacheSize: 104857600 +nodes: + - host: 127.0.0.1 + nodeId: 1 + httpPort: 4437 + raftPort: 8091 + dataDir: /tmp/streamstack/aws/n1 + - host: 127.0.0.1 + nodeId: 2 + httpPort: 4438 + raftPort: 8092 + dataDir: /tmp/streamstack/aws/n2 + - host: 127.0.0.1 + nodeId: 3 + httpPort: 4439 + raftPort: 8093 + dataDir: /tmp/streamstack/aws/n3 diff --git a/harness/configs/topo.aws.yaml b/harness/aws/topo.yaml similarity index 80% rename from harness/configs/topo.aws.yaml rename to harness/aws/topo.yaml index 1f2ba3e..ff8a08f 100644 --- a/harness/configs/topo.aws.yaml +++ b/harness/aws/topo.yaml @@ -1,3 +1,4 @@ +# Single node. Real S3 (no endpoint). DATA_BUCKET / WAL_BUCKET override the URIs. global: clusterName: aws storage: 0@s3://streamstack-data?region=us-east-1 diff --git a/harness/docker/Dockerfile b/harness/docker/Dockerfile index 56eaa7e..b1cee54 100644 --- a/harness/docker/Dockerfile +++ b/harness/docker/Dockerfile @@ -9,6 +9,12 @@ ARG MODULE=frontend/ds/server ARG JAR=ds-server.jar COPY --from=build /build/${MODULE}/target/${JAR} /opt/streamstack/server.jar COPY harness/docker/entrypoint.sh /opt/streamstack/entrypoint.sh +COPY harness/local/topo.yaml /opt/streamstack/topo/local.yaml +COPY harness/local/topo.cluster.yaml /opt/streamstack/topo/local.cluster.yaml +COPY harness/aws/topo.yaml /opt/streamstack/topo/aws.yaml +COPY harness/aws/topo.cluster.yaml /opt/streamstack/topo/aws.cluster.yaml +COPY harness/fly/topo.yaml /opt/streamstack/topo/fly.yaml +COPY harness/fly/topo.cluster.yaml /opt/streamstack/topo/fly.cluster.yaml WORKDIR /opt/streamstack RUN chmod +x /opt/streamstack/entrypoint.sh ENTRYPOINT ["/opt/streamstack/entrypoint.sh"] diff --git a/harness/docker/entrypoint.sh b/harness/docker/entrypoint.sh index 1c72a14..60ab46b 100755 --- a/harness/docker/entrypoint.sh +++ b/harness/docker/entrypoint.sh @@ -1,10 +1,46 @@ #!/bin/sh set -eu -set -- --topo "${TOPO:?}" --node-id "${NODE_ID:-1}" --http-host 0.0.0.0 -if [ -n "${DATA_BUCKET:-}" ]; then - set -- "$@" --storage "0@s3://${DATA_BUCKET}?region=${AWS_REGION:-us-east-1}" + +extra="$*" + +set -- --http-host 0.0.0.0 + +if [ -n "${TOPO:-}" ]; then + set -- "$@" --topo "$TOPO" fi -if [ -n "${WAL_BUCKET:-}" ]; then - set -- "$@" --wal "0@s3://${WAL_BUCKET}?region=${AWS_REGION:-us-east-1}" +if [ -n "${NODE_ID:-}" ]; then + set -- "$@" --node-id "$NODE_ID" fi +if [ -n "${DATA_DIR:-}" ]; then + set -- "$@" --data-dir "$DATA_DIR" +fi +if [ -n "${ROUTING:-}" ]; then + set -- "$@" --routing "$ROUTING" +fi + +bucket="${DATA_BUCKET:-${BUCKET_NAME:-}}" +if [ -n "$bucket" ]; then + region="${AWS_REGION:-us-east-1}" + endpoint="${AWS_ENDPOINT_URL_S3:-}" + endpoint="${endpoint%/}" + qs="region=${region}" + if [ -n "$endpoint" ]; then + qs="${qs}&endpoint=${endpoint}" + fi + if [ "${PATH_STYLE:-}" = "true" ]; then + qs="${qs}&pathStyle=true" + fi + wal="${WAL_BUCKET:-$bucket}" + set -- "$@" --storage "0@s3://${bucket}?${qs}" --wal "0@s3://${wal}?${qs}" +fi + +if [ -n "$extra" ]; then + set -- "$@" $extra +fi + +if [ -z "${TOPO:-}" ] && [ -z "$extra" ]; then + echo "TOPO or command args required" >&2 + exit 1 +fi + exec java -jar /opt/streamstack/server.jar "$@" diff --git a/harness/fly/fly.cluster.toml b/harness/fly/fly.cluster.toml new file mode 100644 index 0000000..8301c2b --- /dev/null +++ b/harness/fly/fly.cluster.toml @@ -0,0 +1,44 @@ +app = "streamstack" +primary_region = "iad" +kill_timeout = 30 + +[build] + dockerfile = "harness/docker/Dockerfile" + +[build.args] + MODULE = "frontend/ds/server" + JAR = "ds-server.jar" + +[deploy] + strategy = "rolling" + max_unavailable = 1 + +[env] + TOPO = "/opt/streamstack/topo/fly.cluster.yaml" + DATA_DIR = "/data" + ROUTING = "LOCAL_ALWAYS" + AWS_REGION = "auto" + JAVA_TOOL_OPTIONS = "-Djava.net.preferIPv6Addresses=true" + +[processes] + n1 = "--node-id 1" + n2 = "--node-id 2" + n3 = "--node-id 3" + +[http_service] + internal_port = 4437 + force_https = true + auto_stop_machines = "off" + auto_start_machines = false + min_machines_running = 3 + processes = ["n1", "n2", "n3"] + +[[mounts]] + source = "streamstack" + destination = "/data" + initial_size = "1gb" + processes = ["n1", "n2", "n3"] + +[[vm]] + size = "shared-cpu-2x" + memory = "2gb" diff --git a/harness/fly/fly.toml b/harness/fly/fly.toml new file mode 100644 index 0000000..a9aeacf --- /dev/null +++ b/harness/fly/fly.toml @@ -0,0 +1,38 @@ +app = "streamstack" +primary_region = "iad" +kill_timeout = 30 + +[build] + dockerfile = "harness/docker/Dockerfile" + +[build.args] + MODULE = "frontend/ds/server" + JAR = "ds-server.jar" + +[deploy] + strategy = "rolling" + max_unavailable = 1 + +[env] + TOPO = "/opt/streamstack/topo/fly.yaml" + NODE_ID = "1" + DATA_DIR = "/data" + ROUTING = "LOCAL_ALWAYS" + AWS_REGION = "auto" + JAVA_TOOL_OPTIONS = "-Djava.net.preferIPv6Addresses=true" + +[http_service] + internal_port = 4437 + force_https = true + auto_stop_machines = "off" + auto_start_machines = false + min_machines_running = 1 + +[mounts] + source = "streamstack" + destination = "/data" + initial_size = "1gb" + +[[vm]] + size = "shared-cpu-2x" + memory = "2gb" diff --git a/harness/fly/topo.cluster.yaml b/harness/fly/topo.cluster.yaml new file mode 100644 index 0000000..6d31e75 --- /dev/null +++ b/harness/fly/topo.cluster.yaml @@ -0,0 +1,25 @@ +# Three Fly process groups (n1–n3). App name must stay streamstack. BUCKET_NAME overrides the URIs. +global: + clusterName: streamstack + storage: 0@s3://streamstack-data?region=auto + wal: 0@s3://streamstack-wal?region=auto + config: + routing: LOCAL_ALWAYS + walCacheSize: 67108864 + blockCacheSize: 67108864 +nodes: + - host: n1.process.streamstack.internal + nodeId: 1 + httpPort: 4437 + raftPort: 8091 + dataDir: /data + - host: n2.process.streamstack.internal + nodeId: 2 + httpPort: 4437 + raftPort: 8091 + dataDir: /data + - host: n3.process.streamstack.internal + nodeId: 3 + httpPort: 4437 + raftPort: 8091 + dataDir: /data diff --git a/harness/fly/topo.yaml b/harness/fly/topo.yaml new file mode 100644 index 0000000..2d2f5ec --- /dev/null +++ b/harness/fly/topo.yaml @@ -0,0 +1,15 @@ +# Single Fly Machine. Tigris via AWS_ENDPOINT_URL_S3; BUCKET_NAME overrides the URIs. +global: + clusterName: streamstack + storage: 0@s3://streamstack-data?region=auto + wal: 0@s3://streamstack-wal?region=auto + config: + routing: LOCAL_ALWAYS + walCacheSize: 67108864 + blockCacheSize: 67108864 +nodes: + - host: fly-local-6pn + nodeId: 1 + httpPort: 4437 + raftPort: 8091 + dataDir: /data diff --git a/harness/configs/minio.env b/harness/local/.env.example similarity index 60% rename from harness/configs/minio.env rename to harness/local/.env.example index 9372933..08a9322 100644 --- a/harness/configs/minio.env +++ b/harness/local/.env.example @@ -1,4 +1,3 @@ AWS_ACCESS_KEY_ID=minioadmin AWS_SECRET_ACCESS_KEY=minioadmin AWS_REGION=us-east-1 -TOPO=/opt/streamstack/harness/configs/topo.minio.yaml diff --git a/harness/local/docker-compose.cluster.ds.yml b/harness/local/docker-compose.cluster.ds.yml new file mode 100644 index 0000000..5b4b5b5 --- /dev/null +++ b/harness/local/docker-compose.cluster.ds.yml @@ -0,0 +1,50 @@ +x-env: &env + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} + AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-} + AWS_REGION: ${AWS_REGION:-us-east-1} + TOPO: /opt/streamstack/topo/topo.cluster.yaml + +x-node: &node + build: + context: ../.. + dockerfile: harness/docker/Dockerfile + args: + MODULE: frontend/ds/server + JAR: ds-server.jar + env_file: + - path: .env + required: false + network_mode: host + restart: on-failure + +services: + node1: + <<: *node + environment: + <<: *env + NODE_ID: "1" + volumes: + - .:/opt/streamstack/topo:ro + - node1-data:/tmp/streamstack + node2: + <<: *node + environment: + <<: *env + NODE_ID: "2" + volumes: + - .:/opt/streamstack/topo:ro + - node2-data:/tmp/streamstack + node3: + <<: *node + environment: + <<: *env + NODE_ID: "3" + volumes: + - .:/opt/streamstack/topo:ro + - node3-data:/tmp/streamstack + +volumes: + node1-data: + node2-data: + node3-data: diff --git a/harness/local/docker-compose.ds.yml b/harness/local/docker-compose.ds.yml new file mode 100644 index 0000000..b968ba3 --- /dev/null +++ b/harness/local/docker-compose.ds.yml @@ -0,0 +1,28 @@ +services: + node1: + build: + context: ../.. + dockerfile: harness/docker/Dockerfile + args: + MODULE: frontend/ds/server + JAR: ds-server.jar + env_file: + - path: .env + required: false + environment: + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} + AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-} + AWS_REGION: ${AWS_REGION:-us-east-1} + TOPO: /opt/streamstack/topo/topo.yaml + NODE_ID: "1" + volumes: + - .:/opt/streamstack/topo:ro + - node1-data:/tmp/streamstack + ports: + - "4437:4437" + - "8091:8091" + restart: on-failure + +volumes: + node1-data: diff --git a/harness/docker/docker-compose.minio.yml b/harness/local/docker-compose.minio.yml similarity index 100% rename from harness/docker/docker-compose.minio.yml rename to harness/local/docker-compose.minio.yml diff --git a/harness/local/docker-compose.s2.yml b/harness/local/docker-compose.s2.yml new file mode 100644 index 0000000..aac08e1 --- /dev/null +++ b/harness/local/docker-compose.s2.yml @@ -0,0 +1,28 @@ +services: + node1: + build: + context: ../.. + dockerfile: harness/docker/Dockerfile + args: + MODULE: frontend/s2/server + JAR: s2-server.jar + env_file: + - path: .env + required: false + environment: + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-} + AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN:-} + AWS_REGION: ${AWS_REGION:-us-east-1} + TOPO: /opt/streamstack/topo/topo.yaml + NODE_ID: "1" + volumes: + - .:/opt/streamstack/topo:ro + - node1-data:/tmp/streamstack + ports: + - "4437:4437" + - "8091:8091" + restart: on-failure + +volumes: + node1-data: diff --git a/harness/configs/topo.cluster.yaml b/harness/local/topo.cluster.yaml similarity index 88% rename from harness/configs/topo.cluster.yaml rename to harness/local/topo.cluster.yaml index c8aaec7..9be11c2 100644 --- a/harness/configs/topo.cluster.yaml +++ b/harness/local/topo.cluster.yaml @@ -1,3 +1,4 @@ +# Three nodes on one host (ports 4437–4439 / 8091–8093). MinIO at 127.0.0.1:9000 (host network). global: clusterName: cluster storage: 0@s3://streams-data?region=us-east-1&endpoint=http://127.0.0.1:9000&pathStyle=true diff --git a/harness/configs/topo.minio.yaml b/harness/local/topo.yaml similarity index 88% rename from harness/configs/topo.minio.yaml rename to harness/local/topo.yaml index e68b8e4..e32e911 100644 --- a/harness/configs/topo.minio.yaml +++ b/harness/local/topo.yaml @@ -1,3 +1,4 @@ +# Single node. MinIO on the Docker host (container → host.docker.internal:9000). global: clusterName: minio storage: 0@s3://streams-data?region=us-east-1&endpoint=http://host.docker.internal:9000&pathStyle=true