diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88ac01f6e..6625075d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,13 +26,13 @@ jobs: - name: Install run: npm ci - name: Build - run: npm run build + run: npm run build:vitepress # Deploy, limited to the main branch - name: Deploy if: success() && github.ref == 'refs/heads/main' uses: peaceiris/actions-gh-pages@v4 with: - publish_dir: ./docs/.vuepress/dist + publish_dir: ./docs/.vitepress/dist github_token: ${{ secrets.GITHUB_TOKEN }} cname: lightningdevkit.org user_name: 'github-actions[bot]' diff --git a/.gitignore b/.gitignore index 3cc642fc8..ce305284e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ # Production /docs/.vuepress/dist +/docs/.vitepress/dist +/docs/.vitepress/cache # Local planning artifacts (Claude /ce workflow) /docs/brainstorms diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 000000000..64913b8c1 --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,225 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { defineConfig, type DefaultTheme } from 'vitepress' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// VuePress 1 still occupies the top-level `node_modules/vue` slot (Vue 2.7.x). +// Force Vite to resolve `vue` and `vue/*` from VitePress's nested Vue 3. +// Remove this alias once VuePress is dropped in Phase 7b. +const vitepressVueDir = path.resolve( + __dirname, + '../../node_modules/vitepress/node_modules/vue', +) + +const githubUrl = 'https://github.com/lightningdevkit' +const discordUrl = 'https://discord.gg/5AcknnMfBw' + +const blogSidebar: DefaultTheme.SidebarItem[] = [ + { + text: 'Blog', + collapsed: false, + items: [ + { text: 'Articles', link: '/blog/' }, + { text: 'Tags', link: '/blog/tags/' }, + { text: 'Authors', link: '/blog/author/' }, + ], + }, +] + +const docsSidebar: DefaultTheme.SidebarItem[] = [ + { + text: 'Documentation', + collapsed: false, + items: [ + { + text: 'Introduction', + link: '/introduction/', + collapsed: true, + items: [ + { text: 'Use Cases', link: '/introduction/use-cases' }, + { text: 'Architecture', link: '/introduction/architecture' }, + { text: 'Peer Management', link: '/introduction/peer-management' }, + { text: 'Persistent Storage', link: '/introduction/persistent_storage' }, + { text: 'Blockchain Data', link: '/introduction/blockchain_data' }, + { text: 'Wallet Management', link: '/introduction/wallet_management' }, + { text: 'Networking', link: '/introduction/networking' }, + { text: 'Private Key Management', link: '/introduction/private_key_management' }, + { text: 'Transactions', link: '/introduction/transactions' }, + { text: 'Random Number Generation', link: '/introduction/random_number_generation' }, + ], + }, + { + text: 'Building a node with LDK', + collapsed: true, + items: [ + { text: 'Introduction', link: '/building-a-node-with-ldk/introduction' }, + { text: 'Installation', link: '/building-a-node-with-ldk/installation' }, + { text: 'Setting up a Channel Manager', link: '/building-a-node-with-ldk/setting-up-a-channel-manager' }, + { text: 'Handling Events', link: '/building-a-node-with-ldk/handling-events' }, + { text: 'Setting up a Peer Manager', link: '/building-a-node-with-ldk/setting-up-a-peer-manager' }, + { text: 'Connect to Peers', link: '/building-a-node-with-ldk/connect-to-peers' }, + { text: 'Opening a Channel', link: '/building-a-node-with-ldk/opening-a-channel' }, + { text: 'Sending Payments', link: '/building-a-node-with-ldk/sending-payments' }, + { text: 'Receiving Payments', link: '/building-a-node-with-ldk/receiving-payments' }, + { text: 'Closing a Channel', link: '/building-a-node-with-ldk/closing-a-channel' }, + ], + }, + { text: 'Running a sample LDK node', link: '/running-a-sample-ldk-node' }, + { + text: 'Advanced Guides', + collapsed: true, + items: [ + { text: 'Blockchain Data', link: '/blockchain_data/' }, + { text: 'Key Management', link: '/key_management' }, + { text: 'Fee Estimation', link: '/fee_estimation' }, + { text: 'Probing and Path Finding', link: '/probing' }, + ], + }, + { text: 'Examples', link: '/examples' }, + ], + }, + { + text: 'API Reference', + collapsed: false, + items: [ + { + text: 'Rust', + collapsed: true, + items: [ + { text: 'lightning', link: 'https://docs.rs/lightning/*/lightning/' }, + { text: 'lightning-background-processor', link: 'https://docs.rs/lightning-background-processor/*/lightning_background_processor/' }, + { text: 'lightning-block-sync', link: 'https://docs.rs/lightning-block-sync/*/lightning_block_sync/' }, + { text: 'lightning-invoice', link: 'https://docs.rs/lightning-invoice/*/lightning_invoice/' }, + { text: 'lightning-net-tokio', link: 'https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/' }, + { text: 'lightning-persister', link: 'https://docs.rs/lightning-persister/*/lightning_persister/' }, + { text: 'lightning-rapid-gossip-sync', link: 'https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/' }, + { text: 'lightning-transaction-sync', link: 'https://docs.rs/lightning-transaction-sync/*/lightning_transaction_sync/' }, + { text: 'lightning-custom-message', link: 'https://docs.rs/lightning-custom-message/*/lightning_custom_message/' }, + ], + }, + ], + }, +] + +export default defineConfig({ + title: 'Lightning Dev Kit Documentation', + description: 'LDK is a flexible lightning implementation with supporting batteries (or modules).', + + cleanUrls: true, + lastUpdated: true, + + srcExclude: [ + 'brainstorms/**', + 'plans/**', + 'todos/**', + 'README.md', + ], + + ignoreDeadLinks: true, + + head: [ + ['link', { rel: 'icon', href: '/favicon.ico' }], + ['link', { rel: 'apple-touch-icon', href: '/img/favicon/apple-touch-icon.png' }], + ['link', { rel: 'manifest', href: '/site.webmanifest' }], + ['link', { rel: 'preload', as: 'font', type: 'font/woff2', crossorigin: '', href: '/fonts/ibm-plex-mono-400.woff2' }], + ['meta', { name: 'msapplication-config', content: '/browserconfig.xml' }], + ['meta', { name: 'theme-color', content: '#ffffff' }], + ['meta', { property: 'og:type', content: 'website' }], + ['meta', { property: 'og:url', content: 'https://lightningdevkit.org/' }], + ['meta', { property: 'og:image', content: 'https://lightningdevkit.org/card.png' }], + ['meta', { name: 'twitter:card', content: 'summary_large_image' }], + ['meta', { name: 'twitter:image', content: 'https://lightningdevkit.org/card.png' }], + ], + + markdown: { + lineNumbers: false, + // Code blocks use a dark navy background in BOTH light and dark mode + // (--vp-code-block-bg is dark in :root and .dark alike), so both Shiki + // themes must be dark-on-navy. github-light/github-dark have muted tokens + // that disappear on the navy; one-dark-pro stays high-contrast and legible. + theme: { + light: 'one-dark-pro', + dark: 'one-dark-pro', + }, + }, + + themeConfig: { + // Hide the right-hand "On this page" outline on docs pages — + // not part of the LDK design. Can still be enabled per-page via + // frontmatter `outline: 'deep'` if a long page benefits from it. + outline: false, + + // Remove the "Previous/Next page" pager at the bottom of docs pages. + docFooter: { + prev: false, + next: false, + }, + + // Logo and wordmark are rendered together via `NavLogo.vue` in the + // `nav-bar-title-before` slot, which uses the original sprite at + // `/img/logo.svg` (with `#small` / `#large` symbols, each a + // composed bolt + wordmark). No `themeConfig.logo` needed; setting + // siteTitle to false hides the default plain-text title. + siteTitle: false, + + editLink: { + pattern: 'https://github.com/lightningdevkit/lightningdevkit.org/edit/main/docs/:path', + text: 'Edit this page on GitHub', + }, + + nav: [ + { text: 'Docs', link: '/introduction/' }, + { text: 'Case Studies', link: '/case-studies' }, + { text: 'Blog', link: '/blog/' }, + { text: 'Discord', link: discordUrl }, + { text: 'GitHub', link: githubUrl }, + ], + + sidebar: { + '/blog/': blogSidebar, + '/': docsSidebar, + }, + + // Search: VitePress's built-in local search (MiniSearch-powered) + // ships immediately and runs entirely client-side. Plan is to swap + // to DocSearch v3 once Algolia approves the application — the + // legacy v2 index (appId `BH4D9OD16A`, indexName `lightningdevkit`) + // is deprecated and not compatible with VitePress's search config + // shape. Apply at https://docsearch.algolia.com/apply (free for + // OSS docs sites; 1–2 week approval typical). + // + // To swap to v3 once credentials arrive, replace the block below + // with: + // + // search: { + // provider: 'algolia', + // options: { + // appId: '', + // apiKey: '', + // indexName: 'lightningdevkit', + // }, + // }, + search: { + provider: 'local', + }, + // No `footer` here: VitePress's default VPFooter would render its own + // copyright above our custom SiteFooter (layout-bottom slot). The + // SiteFooter carries the single copyright line. + }, + + vite: { + resolve: { + // Alias bare `vue` and subpaths to VitePress's nested Vue 3. + // Point at the PACKAGE DIRECTORY (not a specific file) so esbuild's + // prebundler can package-resolve via vue's own package.json + // exports map — pointing at index.mjs directly let the prebundler + // cache Vue 2 from top-level node_modules. + alias: [ + { find: /^vue$/, replacement: vitepressVueDir }, + { find: /^vue\/(.*)$/, replacement: path.join(vitepressVueDir, '$1') }, + ], + dedupe: ['vue'], + }, + }, +}) diff --git a/docs/.vitepress/theme/components/BlogPostHeader.vue b/docs/.vitepress/theme/components/BlogPostHeader.vue new file mode 100644 index 000000000..9b269e3ee --- /dev/null +++ b/docs/.vitepress/theme/components/BlogPostHeader.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/docs/.vitepress/theme/components/BlogPostList.vue b/docs/.vitepress/theme/components/BlogPostList.vue new file mode 100644 index 000000000..69ffccbdd --- /dev/null +++ b/docs/.vitepress/theme/components/BlogPostList.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/docs/.vitepress/theme/components/CaseStudiesPage.vue b/docs/.vitepress/theme/components/CaseStudiesPage.vue new file mode 100644 index 000000000..42d19b6f4 --- /dev/null +++ b/docs/.vitepress/theme/components/CaseStudiesPage.vue @@ -0,0 +1,442 @@ + + + + + diff --git a/docs/.vitepress/theme/components/HomeCaseStudies.vue b/docs/.vitepress/theme/components/HomeCaseStudies.vue new file mode 100644 index 000000000..34526f680 --- /dev/null +++ b/docs/.vitepress/theme/components/HomeCaseStudies.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/docs/.vitepress/theme/components/HomeCrossPromo.vue b/docs/.vitepress/theme/components/HomeCrossPromo.vue new file mode 100644 index 000000000..2f463890c --- /dev/null +++ b/docs/.vitepress/theme/components/HomeCrossPromo.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/docs/.vitepress/theme/components/HomeFeatures.vue b/docs/.vitepress/theme/components/HomeFeatures.vue new file mode 100644 index 000000000..44a38b3e0 --- /dev/null +++ b/docs/.vitepress/theme/components/HomeFeatures.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/docs/.vitepress/theme/components/HomePromo.vue b/docs/.vitepress/theme/components/HomePromo.vue new file mode 100644 index 000000000..27417c691 --- /dev/null +++ b/docs/.vitepress/theme/components/HomePromo.vue @@ -0,0 +1,107 @@ + + + diff --git a/docs/.vitepress/theme/components/HomeServerPromo.vue b/docs/.vitepress/theme/components/HomeServerPromo.vue new file mode 100644 index 000000000..b186cd237 --- /dev/null +++ b/docs/.vitepress/theme/components/HomeServerPromo.vue @@ -0,0 +1,271 @@ + + + diff --git a/docs/.vitepress/theme/components/NavLogo.vue b/docs/.vitepress/theme/components/NavLogo.vue new file mode 100644 index 000000000..12aa567c4 --- /dev/null +++ b/docs/.vitepress/theme/components/NavLogo.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/docs/.vitepress/theme/components/SiteFooter.vue b/docs/.vitepress/theme/components/SiteFooter.vue new file mode 100644 index 000000000..1269b6995 --- /dev/null +++ b/docs/.vitepress/theme/components/SiteFooter.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 000000000..f5b7587a3 --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,38 @@ +import DefaultTheme from 'vitepress/theme' +import type { Theme } from 'vitepress' +import { h } from 'vue' + +import './style.css' + +import HomeFeatures from './components/HomeFeatures.vue' +import HomeServerPromo from './components/HomeServerPromo.vue' +import HomeCaseStudies from './components/HomeCaseStudies.vue' +import HomeCrossPromo from './components/HomeCrossPromo.vue' +import SiteFooter from './components/SiteFooter.vue' +import BlogPostList from './components/BlogPostList.vue' +import BlogPostHeader from './components/BlogPostHeader.vue' +import CaseStudiesPage from './components/CaseStudiesPage.vue' +import NavLogo from './components/NavLogo.vue' + +export default { + extends: DefaultTheme, + Layout() { + return h(DefaultTheme.Layout, null, { + 'nav-bar-title-before': () => h(NavLogo), + 'doc-before': () => h(BlogPostHeader), + 'home-features-after': () => [ + h(HomeFeatures), + h(HomeServerPromo), + h(HomeCaseStudies), + h(HomeCrossPromo), + ], + 'layout-bottom': () => h(SiteFooter), + }) + }, + enhanceApp({ app }) { + // Register globally so blog markdown pages can use + // without per-file script setup imports. + app.component('BlogPostList', BlogPostList) + app.component('CaseStudiesPage', CaseStudiesPage) + }, +} satisfies Theme diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css new file mode 100644 index 000000000..b9491d3db --- /dev/null +++ b/docs/.vitepress/theme/style.css @@ -0,0 +1,727 @@ +/** + * LDK brand styles for VitePress's default theme. + * + * Brand colors ported from docs/public/css/variables.css (the v1 theme's + * source) into VitePress's --vp-c-brand-* tokens. The v1 theme used a + * single hue per mode; VitePress's default theme expects a 4-step ramp + * (1=base, 2=hover, 3=focus, soft=very-light backdrop) which we derive. + * + * Light mode primary: #0F31F7 (LDK blue) + * Dark mode primary: #76F3CD (LDK mint) + * + * Fonts: Manrope (body) + IBM Plex Mono (code), matching the v1 + * spiralbtc theme's pairing. + */ + +@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap'); + +@font-face { + font-family: 'IBM Plex Mono'; + src: url('/fonts/ibm-plex-mono-400.woff2') format('woff2'); + font-weight: 400; + font-display: swap; +} + +:root { + --vp-c-brand-1: #0f31f7; + --vp-c-brand-2: #2e48f8; + --vp-c-brand-3: #4d5ffa; + --vp-c-brand-soft: #f5f7ff; + + --vp-button-brand-bg: #0f31f7; + --vp-button-brand-hover-bg: #2e48f8; + --vp-button-brand-active-bg: #4d5ffa; + + --vp-code-block-bg: #020a36; + --vp-code-bg: #e6eafe; + + --vp-custom-block-tip-bg: #f5f7ff; + --vp-custom-block-tip-text: var(--vp-c-text-1); + + --vp-font-family-base: 'Manrope', -apple-system, BlinkMacSystemFont, + 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + --vp-font-family-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, + 'SF Mono', Menlo, Consolas, Liberation Mono, monospace; + + /* Custom tokens used by the inline SVG monograms (illustrations.svg). + Mirror the v1 spiralbtc theme's --docs-primary / --docs-border-color + so the sprite's `fill="var(--docs-primary)"` paths pick up the + brand color and switch with light/dark. */ + --docs-primary: var(--vp-c-brand-1); + --docs-border-color: var(--vp-c-text-1); + + /* Taller navbar for a bit more vertical padding around the logo and + nav items (VitePress default is 64px). */ + --vp-nav-height: 72px; + + /* White sidebar (VitePress default is the grey --vp-c-bg-alt) so docs + pages read on the same surface as the page frame. */ + --vp-sidebar-bg-color: var(--vp-c-bg); + + /* Shared layout widths. The dashed page frame sits at --ldk-frame-width + (centered), with the content column 48px narrower inside it (a 24px + gutter each side). Widen these to pull the frame closer to the window + edges; the navbar, home sections, dividers, footer, and cross-promo + all derive from them. */ + --ldk-content-width: 1320px; + --ldk-frame-width: 1368px; + --ldk-frame-half: 684px; /* --ldk-frame-width / 2 */ + + /* Docs layout matches the frame width so the sidebar + content sit + within the same frame. */ + --vp-layout-max-width: var(--ldk-frame-width); +} + +.dark { + --vp-c-brand-1: #76f3cd; + --vp-c-brand-2: #5bd9b3; + --vp-c-brand-3: #40bf99; + --vp-c-brand-soft: rgba(118, 243, 205, 0.14); + + --vp-button-brand-bg: #76f3cd; + --vp-button-brand-hover-bg: #5bd9b3; + --vp-button-brand-active-bg: #40bf99; + --vp-button-brand-text: #000628; + --vp-button-brand-hover-text: #000628; + + --vp-code-block-bg: #002547; + --vp-code-bg: #06463c; + + --vp-custom-block-tip-bg: rgba(118, 243, 205, 0.08); +} + +/* Slot-mounted home sections: keep them centered and consistent with + VitePress's home layout container width. Each section gets a dashed + bottom divider so the home page reads as a stack of cards inside the + page frame. */ +.vp-home-extras { + position: relative; + max-width: var(--ldk-content-width); + margin: 0 auto; + padding: 0 24px; +} + +/* Bottom divider. Rendered as a pseudo-element rather than a plain + `border-bottom` so it can reach the dashed page-frame lines. The + section is 1152px wide but the frame sits at calc(50% ± 600px) + (1200px apart), so a content-width border would stop 24px short of + each line and read as "cut off". Base spans the content width + (unchanged on mobile/tablet); once the frame is visible it widens to + the 1200px frame span and centers so its ends meet the lines. */ +.vp-home-extras::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + border-bottom: 1px dashed var(--vp-c-divider); + pointer-events: none; +} + +@media (min-width: 1241px) { + .vp-home-extras::after { + left: 50%; + right: auto; + width: var(--ldk-frame-width); + transform: translateX(-50%); + } +} + +/* Typography ramp for home section headings (case studies, etc.) + so they sit between the hero (44px) and body copy in a clean + ratio rather than landing at VitePress's default markdown h2. */ +.vp-home-extras h2 { + font-size: 28px; + font-weight: 600; + line-height: 1.2; + letter-spacing: -0.01em; +} + +/* Drop VitePress's default solid divider above each doc h2 — the design + relies on the dashed page frame, not solid section rules. Keep the + vertical rhythm via margin alone. */ +.vp-doc h2 { + margin-top: 48px; + padding-top: 0; + border-top: none; +} + +/* The default theme leaves the doc page's `.VPDoc .container` at + 1152px max-width too — keep our home content aligned with it so + the dashed frame visually wraps both. */ + +/* Dashed page frame: vertical lines flanking the centered content, + matching the v1 spiralbtc theme's `.wrap-border` aesthetic. + Implemented as `position: absolute` on the Layout root so the + lines extend with content height rather than viewport. Hidden + on narrow viewports where they'd overlap content. */ +.Layout { + position: relative; +} + +.Layout::before, +.Layout::after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + width: 0; + border-left: 1px dashed var(--vp-c-divider); + pointer-events: none; + /* Above the docs sidebar (z-index 28) and above the navbar (z-index 30) + so the frame lines run unbroken to the top of the window through the + navbar region. The navbar content is inset 16px from the frame width, + so the 1px lines clear the logo and nav items. */ + z-index: 31; + /* Hidden by default (narrow viewports where they'd overlap content); + revealed once there's room at the wide breakpoint below. */ + display: none; +} + +/* Frame the 1200px content column (center ± 600) — same on home and + docs now that the docs layout is also capped at 1200px. */ +.Layout::before { + left: calc(50% - var(--ldk-frame-half)); +} + +.Layout::after { + left: calc(50% + var(--ldk-frame-half)); +} + +@media (min-width: 1241px) { + .Layout::before, + .Layout::after { + display: block; + } +} + +/* VitePress adds a large bottom margin under the home content before the + footer. Drop it so the BDK cross-promo (our last home section) sits + flush at the bottom of the page frame with the footer directly below. */ +.VPHome { + margin-bottom: 0 !important; +} + +/* Dashed dividers on the structural elements VitePress renders by + default — navbar bottom and hero bottom. The home extras have their + own bottom-border rule above. */ +.VPNavBar { + border-bottom: 1px dashed var(--vp-c-divider); +} + +/* On desktop docs pages VitePress forces the navbar transparent via a + *scoped* rule — `.VPNavBar:not(.home)[data-v-hash]`, specificity + (0,3,0) — which lets the sidebar (z-index 28, below) show through and + overlap the logo as it scrolls. A plain class selector can't outrank + the scoped attribute selector, so use !important to re-assert an opaque + background and let the fixed navbar fully mask the sidebar beneath it. */ +@media (min-width: 960px) { + .VPNavBar.has-sidebar { + background-color: var(--vp-c-bg) !important; + } +} + +/* The content-body is explicitly `height: var(--vp-nav-height)`, but + border-box sizing + our 1px bottom border shrink the navbar's content + area by 1px — so the content-body overflows 1px and, on docs pages + where it has an opaque background, paints over the dashed border on the + nav-items side. Trim it so the border shows full width. */ +.VPNavBar .content-body { + height: calc(var(--vp-nav-height) - 1px); +} + +/* Align the navbar inner content with the dashed page-frame. + VitePress's default `.wrapper` has asymmetric padding (`0 8px 0 24px`) + that shifts the navbar right; zero it out so the container's own + padding is the only inset. The container is sized to the frame width + (1200px) so the logo and nav items sit a symmetric 24px inside the + frame lines — slightly closer to the border than the 1152px content + column below. */ +.VPNavBar .wrapper { + padding: 0 !important; +} + +.VPNavBar .wrapper > .container { + max-width: var(--ldk-frame-width) !important; + margin: 0 auto !important; + padding-left: 16px !important; + padding-right: 16px !important; +} + +/* Keep the navbar identical on docs (sidebar) pages. VitePress's + `has-sidebar` mode pulls the logo into an absolute sidebar-width box + and pads the nav content by the sidebar width; neutralize both so the + logo and nav items flow within the 1200px container exactly like + every other page. */ +@media (min-width: 960px) { + .VPNavBar.has-sidebar .title { + position: static !important; + width: auto !important; + padding: 0 !important; + background: transparent !important; + } + .VPNavBar.has-sidebar .content { + padding-left: 0 !important; + padding-right: 0 !important; + } +} + +/* The sidebar's "curtain" is the sticky mask at the top of the sidebar's + own scroll container — it hides links as they scroll up past the + navbar. Keep it (matched to the page background so it doesn't read as a + distinct box) so sidebar content never overlaps the fixed navbar/logo. */ +.VPSidebar .curtain { + background-color: var(--vp-c-bg); +} + +/* Sidebar sits above the doc content (so content scrolls under it), but + below the page-frame lines (z-index 29) so the left frame line stays + visible in the sidebar's left margin, and below the navbar. */ +@media (min-width: 960px) { + .VPSidebar { + z-index: 28 !important; + } +} + +/* Dashed divider between the sidebar and the content, matching the page + frame, so the docs grid reads as: left frame | sidebar | content | + right frame. */ +@media (min-width: 960px) { + .VPSidebar { + border-right: 1px dashed var(--vp-c-divider); + } +} + +/* Footer sits in the doc-content column on sidebar pages: mirror + VPContent.has-sidebar's sidebar offset and let the inner fill that + column, so the footer matches the VPDoc.has-sidebar.has-aside width and + never sits under the fixed sidebar. */ +@media (min-width: 960px) { + .VPContent.has-sidebar ~ .site-footer { + /* Offset past the fixed sidebar, plus a 32px gutter so the columns + aren't flush against the sidebar/frame edge. */ + padding-left: calc(var(--vp-sidebar-width) + 32px); + /* Padded divider separating the footer from the doc content above. */ + border-top: 1px dashed var(--vp-c-divider); + } + .VPContent.has-sidebar ~ .site-footer .site-footer-inner { + max-width: none; + margin: 0; + } +} + +@media (min-width: 1440px) { + .VPContent.has-sidebar ~ .site-footer { + padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width) + 32px); + padding-right: calc((100vw - var(--vp-layout-max-width)) / 2 + 32px); + } +} + +/* Plain pages (e.g. Case Studies) have no divider above the footer the + way docs pages (the sidebar rule above) and the home page (its last + section's divider) do. Give the footer a dashed top border there. + Drawn as a pseudo-element so it can reach the page-frame lines like + the home dividers, rather than spanning the full window width. */ +.VPContent:not(.has-sidebar):not(.is-home) ~ .site-footer { + position: relative; +} +.VPContent:not(.has-sidebar):not(.is-home) ~ .site-footer::before { + content: ''; + position: absolute; + top: 0; + left: 24px; + right: 24px; + border-top: 1px dashed var(--vp-c-divider); + pointer-events: none; +} + +@media (min-width: 1241px) { + .VPContent:not(.has-sidebar):not(.is-home) ~ .site-footer::before { + left: 50%; + right: auto; + width: var(--ldk-frame-width); + transform: translateX(-50%); + } +} + +/* Hero: tighten the default VitePress hero to read as a single + content column rather than the full-width centered ramp the + default theme produces. Padding lives on the container (not the + `.VPHero` outer) so the inner content edge matches the navbar + and home-extras sections. */ +.VPHome .VPHero { + border-bottom: 1px dashed var(--vp-c-divider); + /* VitePress's default uses a negative `margin-top` equal to the nav + height plus an asymmetric padding (`calc(... + 80px) 48px 64px`) + in media queries — both fight our symmetric layout. Override + fully with `!important` so the visible padding is what we set. */ + margin-top: 0 !important; + padding: 48px 0 !important; +} + +.VPHome .VPHero .container { + max-width: var(--ldk-content-width); + margin: 0 auto; + padding: 0 24px; +} + +.VPHome .VPHero .main { + text-align: left; + display: flex; + flex-direction: column; + gap: 32px; + align-items: flex-start; +} + +.VPHome .VPHero .name, +.VPHome .VPHero .text { + /* Mobile base: smaller heading that's allowed to wrap so it never + overflows on narrow viewports. */ + font-size: 32px; + line-height: 1.15; + font-weight: 700; + letter-spacing: -0.02em; + white-space: normal; +} + +@media (min-width: 961px) { + .VPHome .VPHero .name, + .VPHome .VPHero .text { + /* Wide enough to keep the heading on a single line. */ + font-size: 48px; + white-space: nowrap; + } +} + +.VPHome .VPHero .tagline { + font-size: 1.2rem; + line-height: 1.5; + color: var(--vp-c-text-2); + margin: 0 !important; + padding: 0 !important; + max-width: 48ch; +} + +@media (min-width: 961px) { + .VPHome .VPHero .tagline { + font-size: 1.6rem; + } +} + +.VPHome .VPHero .actions { + margin-top: 0 !important; + padding-top: 0 !important; +} + +.VPHome .VPHero .VPButton.brand { + display: inline-block; + font-size: 1.2rem; + padding: 10px 20px; + border-radius: 8px; + transition: background-color 0.1s ease; + box-sizing: border-box; + color: var(--vp-button-brand-text, var(--vp-c-white)); + background: var(--vp-button-brand-bg); + font-weight: 600; + line-height: 1.4; + height: auto; +} + +.VPHome .VPHero .VPButton.brand:hover { + background: var(--vp-button-brand-hover-bg); +} + +/* Wordmark + bolt rendered as a composed unit via `NavLogo.vue` in + the `nav-bar-title-before` slot. No extra title styling needed + beyond what the component scopes itself. */ + +/* Case studies is a landing-style page (no sidebar/aside), so VitePress + caps its doc column at ~784px and centers it. Let it break out to the + full frame content width instead, so the featured band and project + grids span the page and align with the home content. */ +.VPDoc:has(.cs-page) .container { + max-width: var(--ldk-content-width) !important; +} +.VPDoc:has(.cs-page) .content { + max-width: none !important; +} + +/* Case studies page layout. The page body is a series of inline + `
` grids containing `.case-study-item` + cards. Matching the v1 spiralbtc theme: three-column grid, centered + text, logo on top, title + description below, optional "View case + study" link at the bottom. */ +.case-studies { + display: grid; + grid-template-columns: 1fr; + gap: 24px; + margin-top: 24px; +} + +@media (min-width: 541px) { + .case-studies { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 961px) { + .case-studies { + grid-template-columns: repeat(3, 1fr); + } +} + +.case-study-item { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 24px 16px; +} + +/* Featured row: a dashed-bordered band (matching the page-frame + aesthetic) with dashed cell dividers between the three highlights, + rather than individual rounded cards. */ +.case-studies.cs-featured { + position: relative; + /* Featured highlights render 20% larger than the rest of the page. + zoom (not transform: scale) reflows, so the band still fills its + container width while logos, text, and padding all grow. This + compounds with .cs-page's own zoom:1.25 to an effective 1.5. */ + zoom: 1.2; + margin-top: 0; + gap: 0; + grid-template-columns: 1fr; + border-top: 1px dashed var(--vp-c-divider); + border-bottom: 1px dashed var(--vp-c-divider); +} + +.cs-featured .case-study-item { + padding: 32px 24px; +} + +/* Stacked (narrow): horizontal dashed dividers between cells. */ +.cs-featured .case-study-item:not(:first-child) { + border-top: 1px dashed var(--vp-c-divider); +} + +.cs-featured .case-study-item > a:first-child { + height: 80px; +} + +.cs-featured .case-study-item img { + max-height: 80px; +} + +@media (min-width: 961px) { + /* Three across: swap to vertical dashed dividers. */ + .case-studies.cs-featured { + grid-template-columns: repeat(3, 1fr); + } + .cs-featured .case-study-item:not(:first-child) { + border-top: 0; + border-left: 1px dashed var(--vp-c-divider); + } +} + +/* Once the page frame is visible (≥1241px, matching .vp-home-extras), + the band's own border stops ~24px short of each frame line. Replace + it with frame-spanning pseudo-elements so the top/bottom dashed lines + reach the vertical frame lines. The pseudo-elements sit inside the + band's compounded zoom (cs-page 1.25 × cs-featured 1.2 = 1.5), so the + real-px frame width is divided by that factor to render at the true + frame span, centered on the (centered) band. */ +@media (min-width: 1241px) { + .case-studies.cs-featured { + border-top: 0; + border-bottom: 0; + /* Break the band out to the full page-frame width so the outer cells + meet the frame lines — otherwise they stop ~56px short (the content + column's 32px padding + the 24px content-to-frame gutter), leaving + whitespace beside the first/last cells. `/1.5` undoes the compounded + zoom (cs-page 1.25 × cs-featured 1.2); left:50% + translateX(-50%) + re-centers the wider band on the frame regardless of the narrower + content container it lives in. */ + width: calc(var(--ldk-frame-width) / 1.5); + max-width: none; + left: 50%; + transform: translateX(-50%); + } + .case-studies.cs-featured::before, + .case-studies.cs-featured::after { + content: ''; + position: absolute; + left: 50%; + width: calc(var(--ldk-frame-width) / 1.5); + transform: translateX(-50%); + border-top: 1px dashed var(--vp-c-divider); + pointer-events: none; + } + .case-studies.cs-featured::before { + top: 0; + } + .case-studies.cs-featured::after { + bottom: 0; + } +} + +.case-study-item > a:first-child { + display: inline-flex; + align-items: center; + justify-content: center; + height: 64px; + margin-bottom: 12px; +} + +.case-study-item img { + max-height: 64px; + max-width: 140px; + object-fit: contain; +} + +.case-study-item h3 { + margin: 0 0 8px; + font-size: 18px; + font-weight: 600; + border: 0; + padding: 0; +} + +.case-study-item h3 a { + color: var(--vp-c-text-1); + text-decoration: none; +} + +.case-study-item h3 a:hover { + color: var(--vp-c-brand-1); +} + +.case-study-item p { + margin: 0 0 12px; + color: var(--vp-c-text-2); + font-size: 14px; + line-height: 1.5; + flex-grow: 1; +} + +.case-study-item .nav-link { + display: inline-block; + margin-top: auto; + color: var(--vp-c-brand-1); + font-size: 14px; + font-weight: 500; + text-decoration: none; +} + +.case-study-item .nav-link:hover { + color: var(--vp-c-brand-2); +} + +.more-cases-heading { + margin-top: 32px; + font-size: 28px; + font-weight: 600; +} + +/* Brand-color the nav items (Docs / Case Studies / Blog / Discord / GitHub) + to match the v1 spiralbtc navbar. */ +.VPNavBarMenuLink, +.VPNavBarMenuGroup .text { + color: var(--vp-c-brand-1) !important; +} + +.VPNavBarMenuLink:hover, +.VPNavBarMenuGroup:hover .text { + color: var(--vp-c-brand-2) !important; +} + +/* Larger nav item text on desktop. */ +@media (min-width: 768px) { + .VPNavBarMenuLink, + .VPNavBarMenuGroup .text { + font-size: 18px; + } +} + +/* VitePress renders a divider line between the menu group and the + appearance toggle. With socialLinks removed it's a stray vertical + line next to the toggle — hide it. The same goes for the `::before` + pseudo-element on `.appearance` (and adjacent combinations) that + draws another 1px vertical bar. */ +.VPNavBar .divider { + display: none; +} +.VPNavBar .appearance::before, +.VPNavBar .menu + .social-links::before, +.VPNavBar .translations + .appearance::before, +.VPNavBar .appearance + .social-links::before { + display: none !important; + content: none !important; +} + +/* Visually reorder the navbar items so search sits AFTER the menu + (GitHub) and before the appearance toggle. The DOM order is + Search → Menu → Appearance; flex `order` rearranges them as + Menu → Search → Appearance without touching markup. */ +.VPNavBar .content-body .VPNavBarMenu { + order: 1; +} +.VPNavBar .content-body .VPNavBarSearch { + order: 2; + /* Default `flex-grow: 1` absorbs leftover space and pushes the + menu items left. Disable so everything hugs the right edge. */ + flex-grow: 0; +} +.VPNavBar .content-body .VPNavBarAppearance { + order: 3; + /* Mobile base: surface the dark/light toggle in the navbar itself, + sitting between search (order 2) and the hamburger (order 4). + VitePress hides it here by default (it lives in the hamburger + screen), so we opt it back in. */ + display: flex; +} +/* Push the hamburger past search and appearance (it has no `order`, + so defaults to 0) — order reads Search → Appearance → Hamburger. + The 48px button centers its 16px icon, leaving 16px of internal + padding before the container's 24px edge — so the icon group would + sit ~16px further in than the logo on the left. Cancel that padding + with a negative margin so the icon aligns to the same 24px line as + the LDK symbol (the right-packed group shifts out as a unit). */ +.VPNavBar .content-body .VPNavBarHamburger { + order: 4; + margin-right: -16px; +} + +/* Mobile: space the three visible controls (search, appearance, + hamburger) evenly with a single gap rather than per-item margins, + which previously left an uneven 16px / 0px split. */ +.VPNavBar .content-body { + gap: 8px; +} + +@media (min-width: 768px) { + /* Desktop manages spacing per item, so drop the mobile gap and + restore the search/appearance insets. The "⋯" extra menu carries + the appearance toggle in this range, so hide the standalone one. */ + .VPNavBar .content-body { + gap: 0; + } + .VPNavBar .content-body .VPNavBarSearch { + padding-left: 16px; + } + .VPNavBar .content-body .VPNavBarAppearance { + display: none; + margin-left: 16px; + } + .VPNavBar .content-body .VPNavBarHamburger { + margin-right: 0; + } +} + +/* ≥1280px: VitePress surfaces the standalone toggle again (its + default), so restore it. */ +@media (min-width: 1280px) { + .VPNavBar .content-body .VPNavBarAppearance { + display: flex; + } +} diff --git a/docs/blockchain_data/block_source.md b/docs/blockchain_data/block_source.md deleted file mode 100644 index 32523d9ad..000000000 --- a/docs/blockchain_data/block_source.md +++ /dev/null @@ -1,35 +0,0 @@ -# Block Source - -Implementing the `BlockSource` interface requires defining methods for fetching -headers, blocks, and the best block hash. - - - - - - - - -For instance, you may implement this interface by querying Bitcoin Core's JSON -RPC interface, which happens to be a sample implementation provided by -`lightning-block-sync`. - -Let's walk through the use case where LDK receives full blocks. diff --git a/docs/blockchain_data/chain_activity.md b/docs/blockchain_data/chain_activity.md deleted file mode 100644 index e72e2ff02..000000000 --- a/docs/blockchain_data/chain_activity.md +++ /dev/null @@ -1,27 +0,0 @@ -# Chain Activity - -Initially, our node doesn't have any channels and hence has no data to monitor -for on-chain. When a channel is opened with a peer, the `ChannelManager` creates -a `ChannelMonitor` and passes it to the `ChainMonitor` to watch. - -At this point, you need to feed LDK any chain data of interest so that it can -respond accordingly. It supports receiving either full blocks or pre-filtered -blocks using the `chain::Listen` interface. While block data can be sourced from -anywhere, it is your responsibility to call the `block_connected` and -`block_disconnected` methods on `ChannelManager` and `ChainMonitor`. This allows -them to update channel state and respond to on-chain events, respectively. - -LDK comes with a `lightning-block-sync` utility that handles polling a block -source for the best chain tip, detecting chain forks, and notifying listeners -when blocks are connected and disconnected. It can be configured to: - -* Poll a custom `BlockSource` -* Notify `ChannelManager` and `ChainMonitor` of block events - -It is your choice as to whether you use this utility or your own to feed the -required chain data to LDK. If you choose to use it, you will need to implement -the `BlockSource` interface or use one of the samples that it provides. - -::: tip Note -Currently, `lightning-block-sync` is only available in Rust. -::: diff --git a/docs/blockchain_data/confirmed_transactions.md b/docs/blockchain_data/confirmed_transactions.md deleted file mode 100644 index c62e3d124..000000000 --- a/docs/blockchain_data/confirmed_transactions.md +++ /dev/null @@ -1,41 +0,0 @@ -# Confirmed Transactions - -Up until this point, we've explored how to notify LDK of chain activity using -blocks. But what if you're sourcing chain activity from a place that doesn't -provide a block-centric interface, like Electrum? - -LDK's `ChannelManager` and `ChainMonitor` implement a -[`chain::Confirm`](https://docs.rs/lightning/*/lightning/chain/trait.Confirm.html) -interface to support this use case, analogous to the block-oriented -[`chain::Listen`](https://docs.rs/lightning/*/lightning/chain/trait.Listen.html) -interface which we've been using up until now. With this alternative approach, -you still need to give LDK information about chain activity, -but only for transactions of interest. To this end, you must call -`Confirm::transactions_confirmed` when any transactions identified by -[`chain::Filter`](https://docs.rs/lightning/*/lightning/chain/trait.Filter.html)'s -`register_tx`/`register_output` methods are confirmed. - -You also need to notify LDK of any transactions with insufficient confirmations -that have been reorganized out of the chain. Transactions that need to be monitored for such -reorganization are returned by `Confirm::get_relevant_txids`. If any of these transactions become -unconfirmed, you must call `Confirm::transaction_unconfirmed`. - -Lastly, you must notify LDK whenever a new chain tip is available using -the `Confirm::best_block_updated` method. See the documentation for a full -picture of how this interface is intended to be used. - -::: tip Note -Note that the described methods of `Confirm` must be called in accordance with the ordering requirements -described in the [`Confirm` documentation](https://docs.rs/lightning/*/lightning/chain/trait.Confirm.html#order) -::: - -::: tip Note -Note that the described methods of `Confirm` must be called both on the -`ChannelManager` *and* the `ChainMonitor`. -::: - -::: tip Note -Be advised that `chain::Confirm` is a less mature interface than -`chain::Listen`. As such, there is not yet a utility like -`lightning-block-sync` to use for interacting with clients like Electrum. -::: diff --git a/docs/blockchain_data/full_blocks.md b/docs/blockchain_data/full_blocks.md deleted file mode 100644 index 529bdc194..000000000 --- a/docs/blockchain_data/full_blocks.md +++ /dev/null @@ -1,14 +0,0 @@ -# Full Blocks - -If your Lightning node is backed by a Bitcoin full node, the operation is -straight forward: call the appropriate methods on `ChannelManager` and -`ChainMonitor` as blocks are connected and disconnected. LDK will handle the -rest! - -So what happens? The `ChannelManager` examines the block's transactions and -updates the internal channel state as needed. The `ChainMonitor` will detect -any spends of the channel funding transaction or any pertinent transaction -outputs, tracking them as necessary. - -If necessary, LDK will broadcast a transaction on your behalf. More on that -later. For now, let's look at the more interesting case of pre-filtered blocks. diff --git a/docs/blockchain_data/index.md b/docs/blockchain_data/index.md new file mode 100644 index 000000000..3c3dff224 --- /dev/null +++ b/docs/blockchain_data/index.md @@ -0,0 +1,205 @@ +# Blockchain Data + +In this guide, we'll explore how to provide chain data to LDK upon startup and +as new blocks are mined. This allows LDK to maintain channel state and monitor +for on-chain channel activity. + +LDK maintains channels with your node's peers during the course of node +operation. When a new channel is opened, the `ChannelManager` will keep track of +the channel's state and tell the `ChainMonitor` that a new channel should be +watched. The `ChainMonitor` does so by maintaining a `ChannelMonitor` for each +channel. + +When a new block is mined, it is connected to the chain while other blocks may +be disconnected if reorganized out. Transactions are confirmed or unconfirmed +during this process. You are required to feed this activity to LDK which will +process it by: + +* Updating channel state +* Signaling back transactions to filter +* Broadcasting transactions if necessary + +## Chain Activity + +Initially, our node doesn't have any channels and hence has no data to monitor +for on-chain. When a channel is opened with a peer, the `ChannelManager` creates +a `ChannelMonitor` and passes it to the `ChainMonitor` to watch. + +At this point, you need to feed LDK any chain data of interest so that it can +respond accordingly. It supports receiving either full blocks or pre-filtered +blocks using the `chain::Listen` interface. While block data can be sourced from +anywhere, it is your responsibility to call the `block_connected` and +`block_disconnected` methods on `ChannelManager` and `ChainMonitor`. This allows +them to update channel state and respond to on-chain events, respectively. + +LDK comes with a `lightning-block-sync` utility that handles polling a block +source for the best chain tip, detecting chain forks, and notifying listeners +when blocks are connected and disconnected. It can be configured to: + +* Poll a custom `BlockSource` +* Notify `ChannelManager` and `ChainMonitor` of block events + +It is your choice as to whether you use this utility or your own to feed the +required chain data to LDK. If you choose to use it, you will need to implement +the `BlockSource` interface or use one of the samples that it provides. + +::: tip Note +Currently, `lightning-block-sync` is only available in Rust. +::: + +## Block Source + +Implementing the `BlockSource` interface requires defining methods for fetching +headers, blocks, and the best block hash. (`lightning-block-sync` is Rust-only.) + +```rust +impl BlockSource for Blockchain { + fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, _height: Option) -> AsyncBlockSourceResult<'a, BlockHeaderData> { + // + } + + // Note: `get_block` returns `BlockData` (it can yield either a full block + // or just the header, supporting pre-filtered block sources). + fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, BlockData> { + // + } + + fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<'a, (BlockHash, Option)> { + // + } +} +``` + +For instance, you may implement this interface by querying Bitcoin Core's JSON +RPC interface, which happens to be a sample implementation provided by +`lightning-block-sync`. + +Let's walk through the use case where LDK receives full blocks. + +## Full Blocks + +If your Lightning node is backed by a Bitcoin full node, the operation is +straight forward: call the appropriate methods on `ChannelManager` and +`ChainMonitor` as blocks are connected and disconnected. LDK will handle the +rest! + +So what happens? The `ChannelManager` examines the block's transactions and +updates the internal channel state as needed. The `ChainMonitor` will detect +any spends of the channel funding transaction or any pertinent transaction +outputs, tracking them as necessary. + +If necessary, LDK will broadcast a transaction on your behalf. More on that +later. For now, let's look at the more interesting case of pre-filtered blocks. + +## Pre-filtered Blocks + +For environments that are resource constrained, receiving and processing all +transaction data may not be feasible. LDK handles this case by signaling back +which transactions and outputs it is interested in. This information can then be +used to filter blocks prior to sending them to your node. + +For example, if your block source is an Electrum client, you can pass along this +information to it. Or, if you are making use of a BIP 157 client, you can check +if a block contains relevant transactions before fetching it. + +So how does this work in practice? `ChainMonitor` is parameterized by an +optional type that implements `chain::Filter`: + +::: code-group + +```rust [Rust] +impl chain::Filter for Blockchain { + fn register_tx(&self, txid: &Txid, script_pubkey: &Script) { + // + } + + fn register_output(&self, output: WatchedOutput) { + // + } +} +``` + +```kotlin [Kotlin] +val txFilter = Filter.new_impl(object : Filter.FilterInterface { + override fun register_tx(txid: ByteArray, scriptPubkey: ByteArray) { + // + } + + override fun register_output(output: WatchedOutput) { + // + } +}) +``` + +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; + +const txFilter = ldk.Filter.new_impl({ + register_tx(txid: Uint8Array, scriptPubkey: Uint8Array): void { + // + }, + register_output(output: ldk.WatchedOutput): void { + // + }, +} as ldk.FilterInterface); +``` + +::: + +When this is provided, `ChainMonitor` will call back to the filter as channels +are opened and blocks connected. This gives the opportunity for the source to +pre-filter blocks as desired. + +Regardless, when a block is connected, its header must be processed by LDK. + +## Confirmed Transactions + +Up until this point, we've explored how to notify LDK of chain activity using +blocks. But what if you're sourcing chain activity from a place that doesn't +provide a block-centric interface, like Electrum or Esplora? + +LDK's `ChannelManager` and `ChainMonitor` implement a +[`chain::Confirm`](https://docs.rs/lightning/0.2.2/lightning/chain/trait.Confirm.html) +interface to support this use case, analogous to the block-oriented +[`chain::Listen`](https://docs.rs/lightning/0.2.2/lightning/chain/trait.Listen.html) +interface which we've been using up until now. With this alternative approach, +you still need to give LDK information about chain activity, +but only for transactions of interest. To this end, you must call +`Confirm::transactions_confirmed` when any transactions identified by +[`chain::Filter`](https://docs.rs/lightning/0.2.2/lightning/chain/trait.Filter.html)'s +`register_tx`/`register_output` methods are confirmed. + +You also need to notify LDK of any transactions with insufficient confirmations +that have been reorganized out of the chain. Transactions that need to be monitored for such +reorganization are returned by `Confirm::get_relevant_txids`. If any of these transactions become +unconfirmed, you must call `Confirm::transaction_unconfirmed`. + +Lastly, you must notify LDK whenever a new chain tip is available using +the `Confirm::best_block_updated` method. See the documentation for a full +picture of how this interface is intended to be used. + +::: tip Note +The described methods of `Confirm` must be called both on the `ChannelManager` +*and* the `ChainMonitor`, and in accordance with the ordering requirements +described in the [`Confirm` documentation](https://docs.rs/lightning/0.2.2/lightning/chain/trait.Confirm.html#order). +::: + +::: tip Note +For Electrum and Esplora backends, LDK provides the +[`lightning-transaction-sync`](https://docs.rs/lightning-transaction-sync/0.2.0/lightning_transaction_sync/) +crate, which drives the `Confirm` interface for you via its `EsploraSyncClient` +and `ElectrumSyncClient`. You register interest through the `Filter` it exposes, +then call `sync` with the `ChannelManager` and `ChainMonitor`. +::: + +## Transaction Broadcasting + +Inevitably, LDK will need to broadcast transactions on your behalf. As you +notify it of blocks, it will determine if it should broadcast a transaction and +do so using an implementation of `BroadcasterInterface` that you have provided. + +And as those transactions or those from your peers are confirmed on-chain, they +will be likewise processed when notified of a connected block. Thus, continuing +the cycle. diff --git a/docs/blockchain_data/introduction.md b/docs/blockchain_data/introduction.md deleted file mode 100644 index 8c2ef2f5d..000000000 --- a/docs/blockchain_data/introduction.md +++ /dev/null @@ -1,24 +0,0 @@ -## Introduction - -In this guide, we'll explore how to provide chain data to LDK upon startup and -as new blocks are mined. This allows LDK to maintain channel state and monitor -for on-chain channel activity. - -LDK maintains channels with your node's peers during the course of node -operation. When a new channel is opened, the `ChannelManager` will keep track of -the channel's state and tell the `ChainMonitor` that a new channel should be -watched. The `ChainMonitor` does so by maintaining a `ChannelMonitor` for each -channel. - -When a new block is mined, it is connected to the chain while other blocks may -be disconnected if reorganized out. Transactions are confirmed or unconfirmed -during this process. You are required to feed this activity to LDK which will -process it by: - -* Updating channel state -* Signaling back transactions to filter -* Broadcasting transactions if necessary - -We will walk through this process as depicted here: - -![LDK block processing](../assets/ldk-block-processing.svg) \ No newline at end of file diff --git a/docs/blockchain_data/pre_filtered_blocks.md b/docs/blockchain_data/pre_filtered_blocks.md deleted file mode 100644 index c1d59342f..000000000 --- a/docs/blockchain_data/pre_filtered_blocks.md +++ /dev/null @@ -1,56 +0,0 @@ -# Pre-filtered Blocks - -For environments that are resource constrained, receiving and processing all -transaction data may not be feasible. LDK handles this case by signaling back -which transactions and outputs it is interested in. This information can then be -used to filter blocks prior to sending them to your node. - -For example, if your block source is an Electrum client, you can pass along this -information to it. Or, if you are making use of a BIP 157 client, you can check -if a block contains relevant transactions before fetching it. - -So how does this work in practice? `ChainMonitor` is parameterized by an -optional type that implements `chain::Filter`: - - - - - - -When this is provided, `ChainMonitor` will call back to the filter as channels -are opened and blocks connected. This gives the opportunity for the source to -pre-filter blocks as desired. - -Regardless, when a block is connected, its header must be processed by LDK. diff --git a/docs/blockchain_data/transaction_broadcasting.md b/docs/blockchain_data/transaction_broadcasting.md deleted file mode 100644 index f0e3e870b..000000000 --- a/docs/blockchain_data/transaction_broadcasting.md +++ /dev/null @@ -1,9 +0,0 @@ -# Transaction Broadcasting - -Inevitably, LDK will need to broadcast transactions on your behalf. As you -notify it of blocks, it will determine if it should broadcast a transaction and -do so using an implementation of `BroadcasterInterface` that you have provided. - -And as those transactions or those from your peers are confirmed on-chain, they -will be likewise processed when notified of a connected block. Thus, continuing -the cycle. \ No newline at end of file diff --git a/docs/blog/_taxonomy.ts b/docs/blog/_taxonomy.ts new file mode 100644 index 000000000..f30f7c1c7 --- /dev/null +++ b/docs/blog/_taxonomy.ts @@ -0,0 +1,91 @@ +/** + * Slugify "Self-custody" → "self-custody", "Elias Rohrer" → "elias-rohrer". + * + * Kept in a separate module from `posts.data.mts` because VitePress's + * static-data plugin transforms `.data.{js,ts,mjs,mts}` files so they + * expose only a `data` named export — any other exports (like this + * function) get dropped, and consumers get + * `"slugify" is not exported by "posts.data.mts"` at build time. + */ +export function slugify(value: string): string { + return value + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/-+/g, '-') + .replace(/^-|-$/g, '') +} + +export interface Post { + url: string + title: string + description: string + date: string + authors: string[] + tags: string[] +} + +/** + * Read blog frontmatter directly from disk. Used by `[param].paths.mts` + * files which are loaded by VitePress via `loadConfigFromFile` and + * bypass the static-data plugin pipeline — so they can't use the + * `data` export from `posts.data.mts` (would be undefined). The + * paths files run at build time on Node, hence the `fs` import. + * + * Runtime pages (markdown bodies with ` + +# Posts by {{ $params.name }} + +

No posts found.

+ + + +[← Back to all authors](/blog/author/) diff --git a/docs/blog/author/[author].paths.mts b/docs/blog/author/[author].paths.mts new file mode 100644 index 000000000..414b8a8e2 --- /dev/null +++ b/docs/blog/author/[author].paths.mts @@ -0,0 +1,18 @@ +import { fileURLToPath } from 'node:url' +import { dirname, resolve } from 'node:path' +import { readBlogPosts, slugify } from '../_taxonomy.ts' + +const blogDir = resolve(dirname(fileURLToPath(import.meta.url)), '..') + +export default { + async paths() { + const posts = await readBlogPosts(blogDir) + const authors = new Set() + for (const post of posts) { + for (const author of post.authors) authors.add(author) + } + return [...authors].map((author) => ({ + params: { author: slugify(author), name: author }, + })) + }, +} diff --git a/docs/blog/author/index.md b/docs/blog/author/index.md new file mode 100644 index 000000000..bc3d6aba3 --- /dev/null +++ b/docs/blog/author/index.md @@ -0,0 +1,75 @@ +--- +title: Authors +description: Browse blog posts by author +--- + + + +# Authors + + + + diff --git a/docs/_blog/bitkit-uses-ldk-to-build-the-ultimate-alternative-to-custodial wallets.md b/docs/blog/bitkit-uses-ldk-to-build-the-ultimate-alternative-to-custodial wallets.md similarity index 100% rename from docs/_blog/bitkit-uses-ldk-to-build-the-ultimate-alternative-to-custodial wallets.md rename to docs/blog/bitkit-uses-ldk-to-build-the-ultimate-alternative-to-custodial wallets.md diff --git a/docs/_blog/bolt12-has-arrived.md b/docs/blog/bolt12-has-arrived.md similarity index 100% rename from docs/_blog/bolt12-has-arrived.md rename to docs/blog/bolt12-has-arrived.md diff --git a/docs/_blog/cashapp-enables-lightning-withdrawals-and-deposits-using-ldk.md b/docs/blog/cashapp-enables-lightning-withdrawals-and-deposits-using-ldk.md similarity index 100% rename from docs/_blog/cashapp-enables-lightning-withdrawals-and-deposits-using-ldk.md rename to docs/blog/cashapp-enables-lightning-withdrawals-and-deposits-using-ldk.md diff --git a/docs/_blog/fedimint-lightning-gateway-uses-ldk-node-to-simplify-deployment-and-liquidity-management.md b/docs/blog/fedimint-lightning-gateway-uses-ldk-node-to-simplify-deployment-and-liquidity-management.md similarity index 100% rename from docs/_blog/fedimint-lightning-gateway-uses-ldk-node-to-simplify-deployment-and-liquidity-management.md rename to docs/blog/fedimint-lightning-gateway-uses-ldk-node-to-simplify-deployment-and-liquidity-management.md diff --git a/docs/_blog/how-we-built-our-sparknodes-using-ldk.md b/docs/blog/how-we-built-our-sparknodes-using-ldk.md similarity index 100% rename from docs/_blog/how-we-built-our-sparknodes-using-ldk.md rename to docs/blog/how-we-built-our-sparknodes-using-ldk.md diff --git a/docs/blog/index.md b/docs/blog/index.md new file mode 100644 index 000000000..4ed99673a --- /dev/null +++ b/docs/blog/index.md @@ -0,0 +1,12 @@ +--- +title: Blog +description: Updates, deep-dives, and case studies from the LDK team and community +--- + + + +# Articles + + diff --git a/docs/_blog/introducing-phantom-node-payments.md b/docs/blog/introducing-phantom-node-payments.md similarity index 100% rename from docs/_blog/introducing-phantom-node-payments.md rename to docs/blog/introducing-phantom-node-payments.md diff --git a/docs/_blog/ldk-an-sdk-for-the-lightning-network.md b/docs/blog/ldk-an-sdk-for-the-lightning-network.md similarity index 100% rename from docs/_blog/ldk-an-sdk-for-the-lightning-network.md rename to docs/blog/ldk-an-sdk-for-the-lightning-network.md diff --git a/docs/_blog/ldk-pathfinding.md b/docs/blog/ldk-pathfinding.md similarity index 100% rename from docs/_blog/ldk-pathfinding.md rename to docs/blog/ldk-pathfinding.md diff --git a/docs/_blog/ldk-roadmap.md b/docs/blog/ldk-roadmap.md similarity index 100% rename from docs/_blog/ldk-roadmap.md rename to docs/blog/ldk-roadmap.md diff --git a/docs/_blog/lqwd-liquidity-provider-get-liquidity-when-you-need-it.md b/docs/blog/lqwd-liquidity-provider-get-liquidity-when-you-need-it.md similarity index 100% rename from docs/_blog/lqwd-liquidity-provider-get-liquidity-when-you-need-it.md rename to docs/blog/lqwd-liquidity-provider-get-liquidity-when-you-need-it.md diff --git a/docs/_blog/mutiny-uses-ldk-the-first-lightning-wallet-for-the-web.md b/docs/blog/mutiny-uses-ldk-the-first-lightning-wallet-for-the-web.md similarity index 100% rename from docs/_blog/mutiny-uses-ldk-the-first-lightning-wallet-for-the-web.md rename to docs/blog/mutiny-uses-ldk-the-first-lightning-wallet-for-the-web.md diff --git a/docs/_blog/onion-messages-demystified.md b/docs/blog/onion-messages-demystified.md similarity index 100% rename from docs/_blog/onion-messages-demystified.md rename to docs/blog/onion-messages-demystified.md diff --git a/docs/blog/posts.data.mts b/docs/blog/posts.data.mts new file mode 100644 index 000000000..72461a8ea --- /dev/null +++ b/docs/blog/posts.data.mts @@ -0,0 +1,28 @@ +import { createContentLoader } from 'vitepress' +import type { Post } from './_taxonomy.ts' + +declare const data: Post[] +export { data } + +export default createContentLoader('blog/*.md', { + excerpt: false, + transform(raw): Post[] { + return raw + .filter(({ url }) => { + // Skip meta pages — only individual articles get aggregated. + if (url === '/blog/' || url === '/blog/index') return false + if (url.startsWith('/blog/tags/')) return false + if (url.startsWith('/blog/author/')) return false + return true + }) + .map(({ url, frontmatter }) => ({ + url, + title: frontmatter.title ?? '', + description: frontmatter.description ?? '', + date: frontmatter.date ?? '', + authors: Array.isArray(frontmatter.authors) ? frontmatter.authors : [], + tags: Array.isArray(frontmatter.tags) ? frontmatter.tags : [], + })) + .sort((a, b) => +new Date(b.date) - +new Date(a.date)) + }, +}) diff --git a/docs/_blog/sensei-uses-ldk-to-build-a-multi-node-lightning-server-application.md b/docs/blog/sensei-uses-ldk-to-build-a-multi-node-lightning-server-application.md similarity index 100% rename from docs/_blog/sensei-uses-ldk-to-build-a-multi-node-lightning-server-application.md rename to docs/blog/sensei-uses-ldk-to-build-a-multi-node-lightning-server-application.md diff --git a/docs/blog/tags/[tag].md b/docs/blog/tags/[tag].md new file mode 100644 index 000000000..24a47ac1e --- /dev/null +++ b/docs/blog/tags/[tag].md @@ -0,0 +1,23 @@ +--- +title: Tag +--- + + + +# Posts tagged "{{ $params.name }}" + +

No posts found.

+ + + +[← Back to all tags](/blog/tags/) diff --git a/docs/blog/tags/[tag].paths.mts b/docs/blog/tags/[tag].paths.mts new file mode 100644 index 000000000..84ba44534 --- /dev/null +++ b/docs/blog/tags/[tag].paths.mts @@ -0,0 +1,18 @@ +import { fileURLToPath } from 'node:url' +import { dirname, resolve } from 'node:path' +import { readBlogPosts, slugify } from '../_taxonomy.ts' + +const blogDir = resolve(dirname(fileURLToPath(import.meta.url)), '..') + +export default { + async paths() { + const posts = await readBlogPosts(blogDir) + const tags = new Set() + for (const post of posts) { + for (const tag of post.tags) tags.add(tag) + } + return [...tags].map((tag) => ({ + params: { tag: slugify(tag), name: tag }, + })) + }, +} diff --git a/docs/blog/tags/index.md b/docs/blog/tags/index.md new file mode 100644 index 000000000..50dd39cbe --- /dev/null +++ b/docs/blog/tags/index.md @@ -0,0 +1,75 @@ +--- +title: Tags +description: Browse blog posts by tag +--- + + + +# Tags + + + + diff --git a/docs/_blog/teos-uses-ldk-to-build-open-source-watchtower.md b/docs/blog/teos-uses-ldk-to-build-open-source-watchtower.md similarity index 100% rename from docs/_blog/teos-uses-ldk-to-build-open-source-watchtower.md rename to docs/blog/teos-uses-ldk-to-build-open-source-watchtower.md diff --git a/docs/_blog/the-challenges-of-developing-non-custodial-lightning-on-mobile.md b/docs/blog/the-challenges-of-developing-non-custodial-lightning-on-mobile.md similarity index 100% rename from docs/_blog/the-challenges-of-developing-non-custodial-lightning-on-mobile.md rename to docs/blog/the-challenges-of-developing-non-custodial-lightning-on-mobile.md diff --git a/docs/_blog/unleashing-liquidity-on-the-lightning-network-with-lightning-liquidity.md b/docs/blog/unleashing-liquidity-on-the-lightning-network-with-lightning-liquidity.md similarity index 100% rename from docs/_blog/unleashing-liquidity-on-the-lightning-network-with-lightning-liquidity.md rename to docs/blog/unleashing-liquidity-on-the-lightning-network-with-lightning-liquidity.md diff --git a/docs/_blog/zero-confirmation-channels.md b/docs/blog/zero-confirmation-channels.md similarity index 100% rename from docs/_blog/zero-confirmation-channels.md rename to docs/blog/zero-confirmation-channels.md diff --git a/docs/building-a-node-with-ldk/closing-a-channel.md b/docs/building-a-node-with-ldk/closing-a-channel.md index b72284685..7b98394e0 100644 --- a/docs/building-a-node-with-ldk/closing-a-channel.md +++ b/docs/building-a-node-with-ldk/closing-a-channel.md @@ -2,28 +2,32 @@ Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs will be accepted on the given channel, and after additional timeout/the closing of all pending HTLCs, the channel will be closed on chain. - - - - - +::: To claim Funds directly into a custom wallet like BDK wallet using a custom `KeysManager` see the [Key Management](/key_management.md) guide for more info. # SpendableOutputs Event Handling - - - - - - +::: -**References:** [Rust `SpendableOutputs` docs](https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.SpendableOutputs), [Java/Kotlin `SpendableOutputs` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L802) \ No newline at end of file +**References:** [Rust `SpendableOutputs` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.Event.html#variant.SpendableOutputs), [Rust `OutputSpender` docs](https://docs.rs/lightning/0.2.2/lightning/sign/trait.OutputSpender.html), [Java/Kotlin `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Event.java), [TypeScript `OutputSpender` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/OutputSpender.mts) \ No newline at end of file diff --git a/docs/building-a-node-with-ldk/connect-to-peers.md b/docs/building-a-node-with-ldk/connect-to-peers.md index 2a000b94a..96e45145b 100644 --- a/docs/building-a-node-with-ldk/connect-to-peers.md +++ b/docs/building-a-node-with-ldk/connect-to-peers.md @@ -4,24 +4,26 @@ In this section you'll learn how to join the lightning network. Firstly we need to have the ability to do high performance I/O operations. LDK provides default implementations for initializing all of your networking needs. If you are using Rust, you can use our simple socket handling library `lightning_net_tokio`. In Kotlin/Java you can use the `NioPeerHandler` which uses Java's NIO I/O interface. +In TypeScript there is no networking module for non-Node.js (browser) environments: WASM cannot open raw TCP sockets. Instead you implement a `SocketDescriptor` that bridges LDK to a transport you do have — typically a `WebSocket` talking to a WebSocket-to-TCP proxy you run server-side — and feed bytes to the `PeerManager` yourself. (Node.js users can use the separate [`lightningdevkit-node-net`](https://www.npmjs.com/package/lightningdevkit-node-net) package instead.) + **What it's used for**: making peer connections, facilitating peer data to and from LDK - - - - - - - - +::: Connections to other peers are established with `PeerManager`. You'll need to know the pubkey and address of another node that you want as a peer. Once the connection is established and the handshake is complete, `PeerManager` will show the peer's pubkey in its list of peers. - - - - - - - - +::: **Dependencies:** `PeerManager` -**References:** [Rust `lightning-net-tokio` docs](https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/), [Rust `PeerManager` docs](https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html), [Java/Kotlin `NioPeerHandler` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/batteries/NioPeerHandler.java), -[Java/Kotlin `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java), +**References:** [Rust `lightning-net-tokio` docs](https://docs.rs/lightning-net-tokio/0.2.0/lightning_net_tokio/), [Rust `PeerManager` docs](https://docs.rs/lightning/0.2.2/lightning/ln/peer_handler/struct.PeerManager.html), [Java/Kotlin `NioPeerHandler` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/batteries/NioPeerHandler.java), [Java/Kotlin `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/PeerManager.java), [TypeScript `SocketDescriptor` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/SocketDescriptor.mts) diff --git a/docs/building-a-node-with-ldk/handling-events.md b/docs/building-a-node-with-ldk/handling-events.md index 00b3c3b79..044afcc9f 100644 --- a/docs/building-a-node-with-ldk/handling-events.md +++ b/docs/building-a-node-with-ldk/handling-events.md @@ -4,69 +4,69 @@ LDK requires that you handle many different events throughout your app's life cy To start handling events in your application, run: - - - - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; + +// There is no BackgroundProcessor in the TypeScript bindings — pull events +// yourself by passing an EventHandler to `process_pending_events`. +const handler = ldk.EventHandler.new_impl({ + handle_event(event: ldk.Event): ldk.Result_NoneReplayEventZ { + if (event instanceof ldk.Event_PaymentSent) { + // Handle successful payment + } else if (event instanceof ldk.Event_PaymentFailed) { + // Handle failed payment + } else if (event instanceof ldk.Event_FundingGenerationReady) { + // Create a funding tx to be broadcast + } + return ldk.Result_NoneReplayEventZ.constructor_ok(); + }, +} as ldk.EventHandlerInterface); + +// Call this whenever the channel manager / chain monitor signals work is pending. +channelManager.as_EventsProvider().process_pending_events(handler); +chainMonitor.as_EventsProvider().process_pending_events(handler); +``` - +::: -References: [Rust `Event` docs](https://docs.rs/lightning/*/lightning/events/enum.Event.html), [Java/Kotlin `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java) +References: [Rust `Event` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.Event.html), [Java/Kotlin `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Event.java), [TypeScript `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/Event.mts) diff --git a/docs/building-a-node-with-ldk/installation.md b/docs/building-a-node-with-ldk/installation.md index c8ada95cc..29994988c 100644 --- a/docs/building-a-node-with-ldk/installation.md +++ b/docs/building-a-node-with-ldk/installation.md @@ -8,27 +8,23 @@ If you have any questions about anything related to LDK, feel free to ask our co Add LDK to a project by configuring the respective config files: - - - - +```bash [TypeScript] +# Install the LDK WASM bindings from npm, replacing {VERSION} with the version +# you want. Pin an explicit version: the npm `latest` tag lags the releases +# (e.g. use 0.2.0-0). The bindings are pure ESM and require a one-time async +# WASM init before use (see below). - +npm install lightningdevkit@{VERSION} +``` + +::: Example usage after installation is complete: - - - - - - - -::: tip Installing LDK Swift -Add ldk-swift package using the Swift Package Manager. +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; -To import the package, use: `import LightningDevKit` +// Load the WASM once, before using any API: +await ldk.initializeWasmWebFetch("/liblightningjs.wasm"); +``` ::: diff --git a/docs/building-a-node-with-ldk/introduction.md b/docs/building-a-node-with-ldk/introduction.md index a169a58fc..92c965086 100644 --- a/docs/building-a-node-with-ldk/introduction.md +++ b/docs/building-a-node-with-ldk/introduction.md @@ -18,19 +18,19 @@ The following tutorials will show you how to build the simplest lightning node u Let's start by looking at the core components we'll need to make this node work for the tasks we outlined above. -1. A [`ChannelManager`](https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManager.html), to open and close channels. -2. A networking stack (https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/index.html), for establishing TCP/IP connections to other nodes on the lightning network. +1. A [`ChannelManager`](https://docs.rs/lightning/0.2.2/lightning/ln/channelmanager/struct.ChannelManager.html), to open and close channels. +2. A networking stack (https://docs.rs/lightning-net-tokio/0.2.0/lightning_net_tokio/index.html), for establishing TCP/IP connections to other nodes on the lightning network. 3. Payments & routing, ability to create and pay invoices. To make the above work we also need to setup a series of supporting modules, including: -1. A [`FeeEstimator`](https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html) -2. A [`Logger`](https://docs.rs/lightning/*/lightning/util/logger/index.html) -3. A Transaction [`Broadcaster`](https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html) -4. A [`NetworkGraph`](https://docs.rs/lightning/*/lightning/routing/gossip/struct.NetworkGraph.html) -5. A [`Persister`](https://docs.rs/lightning/*/lightning/util/persist/trait.Persister.html) -6. An [`EventHandler`](https://docs.rs/lightning/*/lightning/events/trait.EventHandler.html) -7. A Transaction [`Filter`](https://docs.rs/lightning/*/lightning/chain/trait.Filter.html) -8. A [`ChainMonitor`](https://docs.rs/lightning/*/lightning/chain/chainmonitor/index.html) -9. A [`KeysManager`](https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html) -10. A [`Scorer`](https://docs.rs/lightning/*/lightning/routing/scoring/index.html) +1. A [`FeeEstimator`](https://docs.rs/lightning/0.2.2/lightning/chain/chaininterface/trait.FeeEstimator.html) +2. A [`Logger`](https://docs.rs/lightning/0.2.2/lightning/util/logger/index.html) +3. A Transaction [`Broadcaster`](https://docs.rs/lightning/0.2.2/lightning/chain/chaininterface/trait.BroadcasterInterface.html) +4. A [`NetworkGraph`](https://docs.rs/lightning/0.2.2/lightning/routing/gossip/struct.NetworkGraph.html) +5. A [`Persister`](https://docs.rs/lightning/0.2.2/lightning/util/persist/trait.Persister.html) +6. An [`EventHandler`](https://docs.rs/lightning/0.2.2/lightning/events/trait.EventHandler.html) +7. A Transaction [`Filter`](https://docs.rs/lightning/0.2.2/lightning/chain/trait.Filter.html) +8. A [`ChainMonitor`](https://docs.rs/lightning/0.2.2/lightning/chain/chainmonitor/index.html) +9. A [`KeysManager`](https://docs.rs/lightning/0.2.2/lightning/sign/struct.KeysManager.html) +10. A [`Scorer`](https://docs.rs/lightning/0.2.2/lightning/routing/scoring/index.html) diff --git a/docs/building-a-node-with-ldk/opening-a-channel.md b/docs/building-a-node-with-ldk/opening-a-channel.md index eca962cb7..bab6a2c52 100644 --- a/docs/building-a-node-with-ldk/opening-a-channel.md +++ b/docs/building-a-node-with-ldk/opening-a-channel.md @@ -11,73 +11,66 @@ Now that you have a peer, you can open a channel with them using `ChannelManager Channels can be announced to the network or can remain private, which is controlled via `UserConfig::announced_channel`. - - - - - - - - +::: # FundingGenerationReady Event Handling @@ -89,42 +82,41 @@ Remember that the funding transaction must only spend [SegWit](https://bitcoinop ::: - - - - - - - - +::: -**References:** [Rust `FundingGenerationReady` docs](https://docs.rs/lightning/*/lightning/util/events/enum.Event.html#variant.FundingGenerationReady), [Java `FundingGenerationReady` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L95) +**References:** [Rust `FundingGenerationReady` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.Event.html#variant.FundingGenerationReady), [Java/Kotlin `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Event.java), [TypeScript `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/Event.mts) # Broadcasting the Funding Transaction After crafting the funding transaction you'll need to send it to the Bitcoin network where it will hopefully be mined and added to the blockchain. You'll need to watch this transaction and wait for a minimum of 6 confirmations before the channel is ready to use. - - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; - - - +::: -**References:** [Rust `BroadcasterInterface` docs](https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html), [Java/Kotlin `BroadcasterInterface` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/BroadcasterInterface.java) +**References:** [Rust `BroadcasterInterface` docs](https://docs.rs/lightning/0.2.2/lightning/chain/chaininterface/trait.BroadcasterInterface.html), [Java/Kotlin `BroadcasterInterface` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/BroadcasterInterface.java), [TypeScript `BroadcasterInterface` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/BroadcasterInterface.mts) ::: tip Keep LDK in sync diff --git a/docs/building-a-node-with-ldk/receiving-payments.md b/docs/building-a-node-with-ldk/receiving-payments.md index 1cf525ddd..1b9e6824d 100644 --- a/docs/building-a-node-with-ldk/receiving-payments.md +++ b/docs/building-a-node-with-ldk/receiving-payments.md @@ -5,20 +5,21 @@ amount and description. `ChannelManager` contains the remaining information needed for the invoice. Use the provided utility to generate an invoice and register a pending payment in `ChannelManager`. - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; - - +::: While it is possible to create an invoice without using the utility, `ChannelManager` will reject any incoming HTLCs for unregistered payments to protect your privacy. In this case, use either `create_inbound_payment` or `create_inbound_payment_for_hash` to register a payment with `ChannelManager` before creating the invoice with the returned payment hash and/or secret. -You might also opt to for `inbound_payment`, useful for generating invoices for [phantom node payments](https://docs.rs/lightning/*/lightning/sign/struct.PhantomKeysManager.html) without a ChannelManager. +You might also opt to for `inbound_payment`, useful for generating invoices for [phantom node payments](https://docs.rs/lightning/0.2.2/lightning/sign/struct.PhantomKeysManager.html) without a ChannelManager. # PaymentClaimable Event Handling @@ -98,61 +85,52 @@ As with sending a payment, LDK will generate an event once a payment is received. It is your responsibility to handle the `PaymentClaimable` event by using `ChannelManager` to release the preimage and claim the funds. - - - - - - +::: -**References:** [Rust `PaymentClaimable` docs](https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentClaimable), [Java/Kotlin `PaymentClaimable` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L261) +**References:** [Rust `PaymentClaimable` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.Event.html#variant.PaymentClaimable), [Rust `PaymentPurpose` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.PaymentPurpose.html), [Java/Kotlin `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Event.java), [TypeScript `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/Event.mts) diff --git a/docs/building-a-node-with-ldk/sending-payments.md b/docs/building-a-node-with-ldk/sending-payments.md index 74e16cbd2..e4adff0b5 100644 --- a/docs/building-a-node-with-ldk/sending-payments.md +++ b/docs/building-a-node-with-ldk/sending-payments.md @@ -5,93 +5,88 @@ string in accordance with BOLT 11. After parsing the invoice, you'll need to find a route from your node to the recipient and then make the payment using `ChannelManager`. - - - - - - - +::: # PaymentSent & PaymentFailed Event Handling @@ -100,51 +95,46 @@ in a `PaymentSent` event with the preimage of the payment hash. Be sure to look out for a `PaymentFailed` event, if the payment fails for some reason, and act accordingly. - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; - - - +::: -**References:** [Rust `PaymentSent` docs](https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentSent),[Rust `PaymentFailed` docs](https://docs.rs/lightning/*/lightning/events/enum.Event.html#variant.PaymentFailed), [Java/Kotlin `PaymentSent` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L464), [Java/Kotlin `PaymentFailed` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L512) \ No newline at end of file +**References:** [Rust `PaymentSent` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.Event.html#variant.PaymentSent), [Rust `PaymentFailed` docs](https://docs.rs/lightning/0.2.2/lightning/events/enum.Event.html#variant.PaymentFailed), [Java/Kotlin `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Event.java), [TypeScript `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/Event.mts) \ No newline at end of file diff --git a/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md b/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md index 47b917f47..11c6e0cef 100644 --- a/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md +++ b/docs/building-a-node-with-ldk/setting-up-a-channel-manager.md @@ -6,33 +6,31 @@ The `ChannelManager` is responsible for several tasks related to managing channe Adding a `ChannelManager` to your application should look something like this: - - - - - - +// The TypeScript bindings have no ChannelManagerConstructor helper — call the +// raw constructor. (The sections below build each dependency.) +const params = ldk.ChainParameters.constructor_new( + ldk.Network.LDKNetwork_Regtest, + ldk.BestBlock.constructor_from_network(ldk.Network.LDKNetwork_Regtest) +); +const messageRouter = ldk.DefaultMessageRouter.constructor_new( + networkGraph, + keysManager.as_EntropySource() +); - +const channelManager = ldk.ChannelManager.constructor_new( + feeEstimator, + chainMonitor.as_Watch(), + txBroadcaster, + router.as_Router(), + messageRouter.as_MessageRouter(), + logger, + keysManager.as_EntropySource(), + keysManager.as_NodeSigner(), + keysManager.as_SignerProvider(), + userConfig, + params, + Math.floor(Date.now() / 1000) // current_timestamp (seconds) +); +``` + +::: There are a few dependencies needed to get this working. Let's walk through setting up each one so we can plug them into our `ChannelManager`. @@ -92,88 +89,71 @@ There are a few dependencies needed to get this working. Let's walk through sett **What it's used for:** estimating fees for on-chain transactions that LDK wants broadcasted. - - - - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; + +const feeEstimator = ldk.FeeEstimator.new_impl({ + get_est_sat_per_1000_weight(target: ldk.ConfirmationTarget): number { + // Return your own feerates per ConfirmationTarget (floor is 253). + switch (target) { + case ldk.ConfirmationTarget.LDKConfirmationTarget_UrgentOnChainSweep: + return 5000; + case ldk.ConfirmationTarget.LDKConfirmationTarget_ChannelCloseMinimum: + return 253; + default: + return 2000; + } + }, +} as ldk.FeeEstimatorInterface); +``` - +::: **Implementation notes:** 1. Fees must be returned in: satoshis per 1000 weight units @@ -183,67 +163,68 @@ retrieving fresh ones every time **Dependencies:** *none* -**References:** [Rust `FeeEstimator` docs](https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.FeeEstimator.html), [Java/Kotlin `FeeEstimator` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/FeeEstimator.java) +**References:** [Rust `FeeEstimator` docs](https://docs.rs/lightning/0.2.2/lightning/chain/chaininterface/trait.FeeEstimator.html), [Java/Kotlin `FeeEstimator` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/FeeEstimator.java) ### Initialize the `Router` **What it's used for:** Finds a Route for a payment between the given payer and a payee. - - +::: code-group - +```kotlin [Kotlin] +// If you use the ChannelManagerConstructor it builds the router for you. The +// NetworkGraph it needs is created like so: +val networkGraph = NetworkGraph.of(Network.LDKNetwork_Regtest, logger) +``` - +const router = ldk.DefaultRouter.constructor_new( + networkGraph, + logger, + keysManager.as_EntropySource(), + multiThreadedScorer.as_LockableScore(), + ldk.ProbabilisticScoringFeeParameters.constructor_default() +); +``` - +::: **Dependencies:** `P2PGossipSync`, `Logger`, `KeysManager`, `Scorer` -**References:** [Rust `Router` docs](https://docs.rs/lightning/*/lightning/routing/router/trait.Router.html), [Java/Kotlin `Router` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Router.java) +**References:** [Rust `Router` docs](https://docs.rs/lightning/0.2.2/lightning/routing/router/trait.Router.html), [Java/Kotlin `Router` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Router.java) ### Initialize the `Logger` **What it's used for:** LDK logging - - - - - - +const logger = ldk.Logger.new_impl({ + log(record: ldk.Record): void { + console.log(`${record.get_level()} [${record.get_module_path()}] ${record.get_args()}`); + }, +} as ldk.LoggerInterface); +``` - +::: **Implementation notes:** you'll likely want to write the logs to a file for debugging purposes. **Dependencies:** *none* -**References:** [Rust `Logger` docs](https://docs.rs/lightning/*/lightning/util/logger/trait.Logger.html), [Java/Kotlin `Logger` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Logger.java) +**References:** [Rust `Logger` docs](https://docs.rs/lightning/0.2.2/lightning/util/logger/trait.Logger.html), [Java/Kotlin `Logger` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Logger.java) ### Initialize the `BroadcasterInterface` **What it's used for:** broadcasting various transactions to the bitcoin network - - - - - - +const txBroadcaster = ldk.BroadcasterInterface.new_impl({ + broadcast_transactions(txs: Uint8Array[]): void { + // + }, +} as ldk.BroadcasterInterfaceInterface); +``` - +::: **Dependencies:** _none_ -**References:** [Rust `BroadcasterInterface` docs](https://docs.rs/lightning/*/lightning/chain/chaininterface/trait.BroadcasterInterface.html), [Java/Kotlin `BroadcasterInterface` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/BroadcasterInterface.java) +**References:** [Rust `BroadcasterInterface` docs](https://docs.rs/lightning/0.2.2/lightning/chain/chaininterface/trait.BroadcasterInterface.html), [Java/Kotlin `BroadcasterInterface` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/BroadcasterInterface.java) ### Initialize `Persist` **What it's used for:** persisting `ChannelMonitor`s, which contain crucial channel data, in a timely manner - - - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; + +const persister = ldk.Persist.new_impl({ + persist_new_channel(id: ldk.OutPoint, data: ldk.ChannelMonitor): ldk.ChannelMonitorUpdateStatus { + // + return ldk.ChannelMonitorUpdateStatus.LDKChannelMonitorUpdateStatus_Completed; + }, + update_persisted_channel(id: ldk.OutPoint, update: ldk.ChannelMonitorUpdate, data: ldk.ChannelMonitor): ldk.ChannelMonitorUpdateStatus { + return ldk.ChannelMonitorUpdateStatus.LDKChannelMonitorUpdateStatus_Completed; + }, + get_and_clear_completed_updates(): ldk.TwoTuple_ChannelIdu64Z[] { + return []; + }, +} as ldk.PersistInterface); +``` - +::: - - - +::: **Implementation notes:** @@ -452,46 +409,89 @@ let persister = FilesystemPersister::new(ldk_data_dir_path); **Dependencies:** _none_ -**References:** [Rust `Persister` docs](https://docs.rs/lightning/*/lightning/chain/chainmonitor/trait.Persist.html), [Java/Kotlin `Persister` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Persist.java) +**References:** [Rust `Persister` docs](https://docs.rs/lightning/0.2.2/lightning/chain/chainmonitor/trait.Persist.html), [Java/Kotlin `Persister` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Persist.java) ### Start Background Processing **What it's used for:** running tasks periodically in the background to keep LDK operational. - - - +::: -**Dependencies:** `ChannelManager`, `ChainMonitor`, `PeerManager`, `Logger` +**Dependencies:** `ChannelManager`, `ChainMonitor`, `PeerManager`, `Logger`, `Persister`/`KVStore` (plus, in Rust, the `OnionMessenger`, `GossipSync`, and optionally `Scorer`/`OutputSweeper`) -**References:** [Rust `BackgroundProcessor::Start` docs](https://docs.rs/lightning-background-processor/*/lightning_background_processor/struct.BackgroundProcessor.html#method.start) +**References:** [Rust `process_events_async` docs](https://docs.rs/lightning-background-processor/0.2.0/lightning_background_processor/fn.process_events_async.html), [Java/Kotlin `ChannelManagerConstructor` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/batteries/ChannelManagerConstructor.java) ### Regularly Broadcast Node Announcement **What it's used for:** if you have 1 or more public channels, you may need to announce your node and its channels occasionally. LDK will automatically announce channels when they are created, but there are no guarantees you have connected peers at that time or that your peers will propagate such announcements. The broader node-announcement message is not automatically broadcast. - - - +::: **Dependencies:** `Peer Manager` -**References:** [`PeerManager::broadcast_node_announcement` docs](https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html#method.broadcast_node_announcement) +**References:** [`PeerManager::broadcast_node_announcement` docs](https://docs.rs/lightning/0.2.2/lightning/ln/peer_handler/struct.PeerManager.html#method.broadcast_node_announcement) ### Optional: Initialize the Transaction `Filter` @@ -514,10 +513,9 @@ i.e. if you're using BIP 157/158 or Electrum as your chain backend **What it's used for:** if you are not providing full blocks, LDK uses this object to tell you what transactions and outputs to watch for on-chain. - - - - - - - - +::: -**Implementation notes:** see the [Blockchain Data](/blockchain_data/introduction.md) guide for more info +**Implementation notes:** see the [Blockchain Data](/blockchain_data/) guide for more info **Dependencies:** _none_ -**References:** [Rust `Filter` docs](https://docs.rs/lightning/*/lightning/chain/trait.Filter.html), [Java/Kotlin `Filter` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Filter.java) +**References:** [Rust `Filter` docs](https://docs.rs/lightning/0.2.2/lightning/chain/trait.Filter.html), [Java/Kotlin `Filter` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/Filter.java) ### Initialize the `ChainMonitor` **What it's used for:** tracking one or more `ChannelMonitor`s and using them to monitor the chain for lighting transactions that are relevant to our node, and broadcasting transactions if need be. - - - - - - - - +::: **Implementation notes:** `Filter` must be non-`None` if you're using Electrum or BIP 157/158 as your chain backend @@ -631,16 +627,15 @@ let chainMonitor = ChainMonitor( **Optional dependency:** `Filter` -**References:** [Rust `ChainMonitor` docs](https://docs.rs/lightning/*/lightning/chain/chainmonitor/struct.ChainMonitor.html), [Java/Kotlin `ChainMonitor` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChainMonitor.java) +**References:** [Rust `ChainMonitor` docs](https://docs.rs/lightning/0.2.2/lightning/chain/chainmonitor/struct.ChainMonitor.html), [Java/Kotlin `ChainMonitor` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/ChainMonitor.java) ### Initialize the `KeysManager` **What it's used for:** providing keys for signing Lightning transactions - - - - - - - - +::: **Implementation notes:** @@ -718,32 +712,30 @@ let keysManager = KeysManager(seed: seed, startingTimeSecs: timestampSeconds, st **Dependencies:** random bytes -**References:** [Rust `KeysManager` docs](https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html), [Java/Kotlin `KeysManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/KeysManager.java) +**References:** [Rust `KeysManager` docs](https://docs.rs/lightning/0.2.2/lightning/sign/struct.KeysManager.html), [Java/Kotlin `KeysManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/KeysManager.java) ### Read `ChannelMonitor` state from disk **What it's used for:** if LDK is restarting and has at least 1 channel, its `ChannelMonitor`s will need to be (1) fed to the `ChannelManager` and (2) synced to chain. - - - - - - - +::: **Dependencies:** `KeysManager` -**References:** [Rust `load_outputs_to_watch` docs](https://docs.rs/lightning/*/lightning/chain/channelmonitor/struct.ChannelMonitor.html#method.load_outputs_to_watch) +**References:** [Rust `load_outputs_to_watch` docs](https://docs.rs/lightning/0.2.2/lightning/chain/channelmonitor/struct.ChannelMonitor.html#method.load_outputs_to_watch) ### Initialize the `ChannelManager` **What it's used for:** managing channel state - - - - - - - - +::: **Implementation notes:** No methods should be called on `ChannelManager` until _after_ the `ChannelMonitor`s and `ChannelManager` are synced to the chain tip (next step). **Dependencies:** `KeysManager`, `FeeEstimator`, `ChainMonitor`, `BroadcasterInterface`, `Logger` -**References:** [Rust `ChannelManager` docs](https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManager.html), [Java/Kotlin `ChannelManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ChannelManager.java) +**References:** [Rust `ChannelManager` docs](https://docs.rs/lightning/0.2.2/lightning/ln/channelmanager/struct.ChannelManager.html), [Java/Kotlin `ChannelManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/ChannelManager.java) ### Sync `ChannelMonitor`s and `ChannelManager` to chain tip @@ -937,10 +914,9 @@ _after_ the `ChannelMonitor`s and `ChannelManager` are synced to the chain tip ( **Example:** - - - - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; + +// The TypeScript bindings have no block-sync helper — drive the `Confirm` +// interface yourself. Both the ChannelManager and ChainMonitor implement it +// (via `as_Confirm()`); as you learn of confirmed/unconfirmed transactions and +// new tips from your chain source, forward them to both: +// +// const confirm = channelManager.as_Confirm(); +// confirm.transactions_confirmed(header, txdata, height); +// confirm.transaction_unconfirmed(txid); +// confirm.best_block_updated(header, height); +// +// Use `confirm.get_relevant_txids()` to learn which transactions to monitor for +// reorgs. Repeat for `chainMonitor.as_Confirm()`. +``` - +::: **Implementation notes:** @@ -1130,7 +1062,7 @@ If you are connecting full blocks or using BIP 157/158, then it is recommended t LDK's `lightning_block_sync` crate as in the example above: the high-level steps that must be done for both `ChannelManager` and each `ChannelMonitor` are as follows: 1. Get the last blockhash that each object saw. - - Receive the latest block hash when through [deserializtion](https://docs.rs/lightning/*/lightning/ln/channelmanager/struct.ChannelManagerReadArgs.html) of the `ChannelManager` via `read()` + - Receive the latest block hash when through [deserializtion](https://docs.rs/lightning/0.2.2/lightning/ln/channelmanager/struct.ChannelManagerReadArgs.html) of the `ChannelManager` via `read()` - Each `ChannelMonitor`'s is in `channel_manager.channel_monitors`, as the 2nd element in each tuple 2. For each object, if its latest known blockhash has been reorged out of the chain, then disconnect blocks using `channel_manager.as_Listen().block_disconnected(..)` or `channel_monitor.block_disconnected(..)` until you reach the last common ancestor with the main chain. 3. For each object, reconnect blocks starting from the common ancestor until it gets to your best known chain tip using `channel_manager.as_Listen().block_connected(..)` and/or `channel_monitor.block_connected(..)`. @@ -1146,98 +1078,62 @@ Alternatively, you can use LDK's `lightning-transaction-sync` crate. This provid **What it's used for:** generating routes to send payments over - - - - - - - - - +::: **Implementation notes:** this struct is not required if you are providing your own routes. It will be used internally in `ChannelManager` to build a `NetworkGraph`. Network options include: `Mainnet`,`Regtest`,`Testnet`,`Signet` **Dependencies:** `Logger` -**Optional dependency:** `Access`, a source of chain information. Recommended to be able to verify channels before adding them to the internal network graph. +**Optional dependency:** `UtxoLookup` (formerly `Access`), a source of chain information. Recommended to be able to verify channels before adding them to the internal network graph. -**References:** [Rust `P2PGossipSync` docs](https://docs.rs/lightning/*/lightning/routing/gossip/struct.P2PGossipSync.html), [`Access` docs](https://docs.rs/lightning/*/lightning/chain/trait.Access.html), [Java/Kotlin `P2PGossipSync` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/P2PGossipSync.java), [Rust `RapidGossipSync` docs](https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/), [Java/Kotlin `RapidGossipSync` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/RapidGossipSync.java) +**References:** [Rust `P2PGossipSync` docs](https://docs.rs/lightning/0.2.2/lightning/routing/gossip/struct.P2PGossipSync.html), [`UtxoLookup` docs](https://docs.rs/lightning/0.2.2/lightning/routing/utxo/trait.UtxoLookup.html), [Java/Kotlin `P2PGossipSync` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/P2PGossipSync.java), [Rust `RapidGossipSync` docs](https://docs.rs/lightning-rapid-gossip-sync/0.2.0/lightning_rapid_gossip_sync/), [Java/Kotlin `RapidGossipSync` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/RapidGossipSync.java) ### Optional: Initialize `Probabilistic Scorer` **What it's used for**: to find a suitable payment path to reach the destination. - - - - - - - - - +::: **Dependencies:** `NetworkGraph` -**References:** [Rust `ProbabilisticScorer` docs](https://docs.rs/lightning/*/lightning/routing/scoring/struct.ProbabilisticScorer.html), [Java/Kotlin `ProbabilisticScorer` docs](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/ProbabilisticScorer.java) \ No newline at end of file +**References:** [Rust `ProbabilisticScorer` docs](https://docs.rs/lightning/0.2.2/lightning/routing/scoring/struct.ProbabilisticScorer.html), [Java/Kotlin `ProbabilisticScorer` docs](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/ProbabilisticScorer.java) \ No newline at end of file diff --git a/docs/building-a-node-with-ldk/setting-up-a-peer-manager.md b/docs/building-a-node-with-ldk/setting-up-a-peer-manager.md index 0c4619b61..061c4ef80 100644 --- a/docs/building-a-node-with-ldk/setting-up-a-peer-manager.md +++ b/docs/building-a-node-with-ldk/setting-up-a-peer-manager.md @@ -6,60 +6,65 @@ The `PeerManager` is responsible for managing a set of peer connections and data To add a `PeerManager` to your application, run: - - +```java [Kotlin] +import org.ldk.structs.PeerManager - - - +```typescript [TypeScript] +import * as ldk from "lightningdevkit"; + +// In TypeScript there is no MessageHandler wrapper — pass each handler to +// PeerManager.constructor_new directly. Use IgnoringMessageHandler for any +// role you don't need (here: routing, onion and custom messages). +const ignorer = ldk.IgnoringMessageHandler.constructor_new(); + +const peerManager = ldk.PeerManager.constructor_new( + channelManager.as_ChannelMessageHandler(), + ignorer.as_RoutingMessageHandler(), // or gossipSync.as_RoutingMessageHandler() + ignorer.as_OnionMessageHandler(), // or onionMessenger.as_OnionMessageHandler() + ignorer.as_CustomMessageHandler(), + chainMonitor.as_SendOnlyMessageHandler(), + Math.floor(Date.now() / 1000), // current time / nonce + keysManager.as_EntropySource().get_secure_random_bytes(), // 32 ephemeral bytes + logger, + keysManager.as_NodeSigner() +); +``` - +::: -**Implementation notes:** if you did not initialize `P2PGossipSync` in the previous step, you can initialize your own struct (which can be a dummy struct) that implements `RoutingMessageHandler` +**Implementation notes:** if you did not initialize `P2PGossipSync` in the previous step, you can pass an `IgnoringMessageHandler` (as shown in the TypeScript example) or your own struct implementing `RoutingMessageHandler` in its place. -**Dependencies:** `ChannelManager`, `RoutingMessageHandler`, `KeysManager`, random bytes, `Logger` +**Dependencies:** `ChannelManager`, `RoutingMessageHandler`, `ChainMonitor`, `KeysManager`, random bytes, `Logger` -**References:** [Rust `PeerManager` docs](https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html), [Rust `RoutingMessageHandler` docs](https://docs.rs/lightning/*/lightning/ln/msgs/trait.RoutingMessageHandler.html), [Java/Kotlin `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java), [Java/Kotlin `RoutingMessageHandler` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/RoutingMessageHandler.java) +**References:** [Rust `PeerManager` docs](https://docs.rs/lightning/0.2.2/lightning/ln/peer_handler/struct.PeerManager.html), [Rust `MessageHandler` docs](https://docs.rs/lightning/0.2.2/lightning/ln/peer_handler/struct.MessageHandler.html), [Java/Kotlin `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/src/main/java/org/ldk/structs/PeerManager.java), [TypeScript `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/v0.2.0.0/ts/structs/PeerManager.mts) diff --git a/docs/case-studies.md b/docs/case-studies.md index 8460707cb..76965c3a4 100644 --- a/docs/case-studies.md +++ b/docs/case-studies.md @@ -1,435 +1,10 @@ --- -cases: true +title: Case Studies +description: Bitcoin applications and services building with LDK sidebar: false -tagline: "Bitcoin applications building with LDK" -description: "A list of bitcoin applications and services building with LDK" -actionText: "Add your project" -actionLink: "https://github.com/orgs/lightningdevkit/discussions/1554" -features: - - title: "Alby Hub" - details: "Equipped with its own lightning node, ready to connect you to numerous applications" - image: "/img/alby-hub-featured.svg" - imageAlt: "alby hub logo" - caseStudyLink: "/blog/alby-hub-uses-ldk-to-offer-a-self-custodial-lightning-wallet-for-everyone/" - - title: "Cash App" - details: "Send and spend, bank, and buy stocks or bitcoin " - image: "/img/cashapp-badge.svg" - imageAlt: "cash app logo" - caseStudyLink: "/blog/cashapp-enables-lightning-withdrawals-and-deposits-using-ldk/" - - title: "Bitkit" - details: "Hands you the keys to your money, profile, contacts, and web accounts" - image: "/img/bitkit.svg" - imageAlt: "" - caseStudyLink: "/blog/bitkit-uses-ldk-to-build-the-ultimate-alternative-to-custodial-wallets/" +aside: false editLink: false lastUpdated: false --- -

- Meet the projects building with LDK -

- - - - - - - - - - - - - - - - - + diff --git a/docs/examples.md b/docs/examples.md index c332fab6a..5f5386563 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -7,14 +7,6 @@ Click the links below and learn from community-built example projects This sample serves as a complete reference for constructing a lightning node with LDK. This is a good starting point if you want a self-guided tour. -### [Kotlin/Android Sample App](https://github.com/conorokus/umlando-wallet) - -This sample uses the Kotlin bindings provided by [ldk-garbagecollected](https://github.com/lightningdevkit/ldk-garbagecollected) to create a self-custodial mobile lightning wallet on Android. - -### [Swift/iOS Sample App](https://github.com/Roy0Anonymous/Vajra-Wallet) - -This sample uses the Swift bindings provided by [ldk-swift](https://github.com/lightningdevkit/ldk-swift) to create a self-custodial mobile lightning wallet on iOS. - ### [Rust node with sample Lightning Signer integration](https://gitlab.com/lightning-signer/lnrod/) A Rust lightning node implementation based on LDK and the Lightning Signer projects. Aims to be production ready at some point. @@ -22,31 +14,3 @@ A Rust lightning node implementation based on LDK and the Lightning Signer proje ### [Rust node with sample Tor integration](https://github.com/TonyGiorgio/ldk-sample-tor) A Rust lightning node sample implementation based on LDK with an embedded Tor daemon. - -### [LDK Node](https://github.com/lightningdevkit/ldk-node) - -A ready-to-go Lightning node library built using LDK and [BDK](https://bitcoindevkit.org/). - -### [LDK Node Rust Sample](https://github.com/optout21/ldk-node-sample) - -A sample lightning node command-line app built on top of LDK Node (similar to ldk-sample). - -### [LDK Node Swift Sample App](https://github.com/reez/Monday/tree/main/LDKNodeMonday) - -This sample uses [ldk-node-swift](https://github.com/lightningdevkit/ldk-node/blob/main/Package.swift) bindings to quickly build a self custodial lightning mobile wallet on iOS. Watch the video tutorial [here](https://www.youtube.com/watch?v=rcU3LU6iZCs). - -### [LDK Node Swift Sample app using Bitcoin Design Guide](https://github.com/bdgwallet/dailywallet) - -This sample is a good starting point for building a sample iOS wallet with a strong focus on user experience. - -### [LDK Node Flutter Sample App](https://github.com/LtbLightning/ldk-node-flutter-demo) - -This sample is a starting point for an LDK Node Flutter app. - -### [LDK Node React Native Sample App](https://github.com/LtbLightning/ldk-node-rn-demo) - -This sample is a starting point for an LDK Node React Native app. - -### [LDK Node Sample Desktop App](https://github.com/jbesraa/ldk-node-desktop) - -This sample is a desktop node manager for LDK Node. diff --git a/docs/fee_estimation.md b/docs/fee_estimation.md index eef33ee56..00b76d7cf 100644 --- a/docs/fee_estimation.md +++ b/docs/fee_estimation.md @@ -106,16 +106,16 @@ Once you've created the directory, open the ```Cargo.toml``` file, which Cargo u [package] name = "ldk-fee-estimator" version = "0.1.0" -edition = "2024" +edition = "2021" [dependencies] -lightning = { version = "0.0.124", features = ["max_level_trace"] } -lightning-block-sync = { version = "0.0.124", features = [ "rpc-client" ] } -lightning-invoice = { version = "0.31.0" } -lightning-net-tokio = { version = "0.0.124" } -lightning-persister = { version = "0.0.124" } -lightning-background-processor = { version = "0.0.124" } -lightning-rapid-gossip-sync = { version = "0.0.124" } +lightning = { version = "0.2.2", features = ["max_level_trace"] } +lightning-block-sync = { version = "0.2.0", features = [ "rpc-client" ] } +lightning-invoice = { version = "0.34.0" } +lightning-net-tokio = { version = "0.2.0" } +lightning-persister = { version = "0.2.0" } +lightning-background-processor = { version = "0.2.0" } +lightning-rapid-gossip-sync = { version = "0.2.0" } reqwest = { version = "0.11", features = ["json", "blocking"] } serde = { version = "1.0", features = ["derive"] } tokio = { version = "1", features = ["full"] } # Async runtime, required for reqwest diff --git a/docs/index.md b/docs/index.md index d456dccd6..586001662 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,49 +1,11 @@ --- -home: true -heroText: Build Lightning applications your way with LDK -tagline: A complete Lightning implementation packaged as an SDK -actionText: Get started -actionLink: /introduction/ -features: - - title: "Flexible and customizable " - details: "Persistence. Networking. Chain sourcing. Routing. Key management. You name it. LDK easily configures to your application’s needs." - image: "customizable" - - title: "High performance" - details: "As lightweight and compact as you need it to be, LDK performs on small-footprint devices and scales in the cloud." - image: "focus" - - title: "Any language, any platform" - details: "LDK provides a multi-language native API. Run a Lightning node on mobile, web, HSMs, LSPs, or your existing infrastructure." - image: "mobile" -promo: true -promoImage: "ldk-node" -promoTitle: "LDK Node" -promoDescription: "Build a mobile Lightning wallet fast with our ready-to-go solution" -promoActionText: "Get Started" -promoActionLink: "https://docs.rs/ldk-node/*/ldk_node/" ---- - -
-
-
- - - - -
-
-

Trusted by the best

-

Innovative projects are building with LDK

- All case studies -> -
-
-
+layout: home - +hero: + text: Build Lightning applications your way with LDK + tagline: A complete Lightning implementation packaged as an SDK + actions: + - theme: brand + text: Get started + link: /introduction/ +--- diff --git a/docs/introduction/architecture.md b/docs/introduction/architecture.md index ff56cfb3b..7ca614a24 100644 --- a/docs/introduction/architecture.md +++ b/docs/introduction/architecture.md @@ -9,4 +9,4 @@ LDK also uses an event-driven architecture which allows for asynchronous result ::: tip Language Bindings -Although the core SDK is written in Rust, LDK supports many other programming languages. These include Java/Kotlin, Swift, JavaScript/TypeScript (Beta), C++ (Alpha). Check out [examples](../examples.md) to see some of the implementations out in the wild! +Although the core SDK is written in Rust, LDK supports many other programming languages. These include Java/Kotlin, JavaScript/TypeScript, C++ (Alpha). Check out [examples](../examples.md) to see some of the implementations out in the wild! diff --git a/docs/introduction/blockchain_data.md b/docs/introduction/blockchain_data.md index 79930cd44..4676b3587 100644 --- a/docs/introduction/blockchain_data.md +++ b/docs/introduction/blockchain_data.md @@ -2,6 +2,6 @@ LDK provides a simple `block_connected`/`block_disconnected` API which you pass block headers and transaction information to. LDK also provides an API for getting information about transactions it wishes to be informed of, which is compatible with Electrum server requests/neutrino filtering/etc. -[Blockchain Data Guide](https://lightningdevkit.org/blockchain_data/introduction/) +[Blockchain Data Guide](/blockchain_data/) [Sample module in Rust](https://github.com/rust-bitcoin/rust-lightning/tree/main/lightning-block-sync) diff --git a/docs/introduction/index.md b/docs/introduction/index.md index ec73f5fc5..effa1e0bb 100644 --- a/docs/introduction/index.md +++ b/docs/introduction/index.md @@ -16,11 +16,6 @@ These provide the most searchable and comprehensive documentation on LDK. If you're using Java and want more information on any method/struct/etc., searching the Rust docs for the Rust version of that struct/method is your best bet. -### [Swift LDK Documentation](https://github.com/arik-so/SwiftLightning/tree/master/Documentation) - -These docs are mainly geared towards how Swift could call LDK C bindings directly, but still may -provide a useful overview of Rust Lightning in the context of language bindings. - ### [Rust Sample Node](https://github.com/lightningdevkit/ldk-sample) The sample serves as a complete reference for constructing a Lightning node with diff --git a/docs/introduction/transactions.md b/docs/introduction/transactions.md index 8988745f5..298d59829 100644 --- a/docs/introduction/transactions.md +++ b/docs/introduction/transactions.md @@ -6,7 +6,7 @@ Clients running a light client may wish to filter for transactions on a separate [LDK's `Filter` API reference](https://docs.rs/lightning/*/lightning/chain/trait.Filter.html) -More information is available in the [Blockchain Data guide](/blockchain_data/introduction). +More information is available in the [Blockchain Data guide](/blockchain_data/). ## Fee Estimation diff --git a/docs/key_management.md b/docs/key_management.md index 8f012932b..83442a38d 100644 --- a/docs/key_management.md +++ b/docs/key_management.md @@ -1,53 +1,46 @@ # Key Management -LDK provides a simple default `KeysManager` implementation that takes a 32-byte seed for use as a BIP 32 extended key and derives keys from that. Check out the [Rust docs](https://docs.rs/lightning/*/lightning/sign/struct.KeysManager.html). +LDK provides a simple default `KeysManager` implementation that takes a 32-byte seed for use as a BIP 32 extended key and derives keys from that. Check out the [Rust docs](https://docs.rs/lightning/0.2.2/lightning/sign/struct.KeysManager.html). However, LDK also allows to customize the way key material and entropy are sourced through custom implementations of the `NodeSigner`, `SignerProvider`, and `EntropySource` traits located in `sign`. These traits include basic methods to provide public and private key material, as well as pseudorandom numbers. A `KeysManager` can be constructed simply with only a 32-byte seed and some random integers which ensure uniqueness across restarts (defined as `starting_time_secs` and `starting_time_nanos`): - - - - - - - - +::: # Creating a Unified Wallet @@ -60,10 +53,9 @@ Using a [BDK](https://bitcoindevkit.org/)-based wallet the steps would be as fol 3. Derive the private key at `m/535h` (or some other custom path). That's 32 bytes and is your starting entropy for your LDK wallet. 4. Optional: use a custom `SignerProvider` implementation to have the BDK wallet provide the destination and shutdown scripts (see [Spending On-Chain Funds](#spending-on-chain-funds)). - - - - - - - +::: ::: tip Protection for on-chain wallet @@ -139,7 +117,7 @@ An advantage to this approach is that the LDK entropy is contained within your i # Spending On-Chain Funds -When a channel has been closed and some outputs on chain are spendable only by us, LDK provides a `util::events::Event::SpendableOutputs` event in return from `ChannelMonitor::get_and_clear_pending_events()`. It contains a list of `sign::SpendableOutputDescriptor` objects which describe the output and provide all necessary information to spend it. +When a channel has been closed and some outputs on chain are spendable only by us, LDK provides a `events::Event::SpendableOutputs` event in return from `ChannelMonitor::get_and_clear_pending_events()`. It contains a list of `sign::SpendableOutputDescriptor` objects which describe the output and provide all necessary information to spend it. If you're using `KeysManager` directly, a utility method is provided which can generate a signed transaction given a list of ` SpendableOutputDescriptor` objects. `KeysManager::spend_spendable_outputs` can be called any time after receiving the `SpendableOutputDescriptor` objects to build a spending transaction, including delaying until sending funds to an external destination or opening a new channel. Note that if you open new channels directly with `SpendableOutputDescriptor` objects, you must ensure all closing/destination scripts provided to LDK are SegWit (either native or P2SH-wrapped). @@ -150,10 +128,18 @@ In order to make the outputs from channel closing spendable by a third-party wal For example, a wrapper based on BDK's [`Wallet`](https://docs.rs/bdk/*/bdk/wallet/struct.Wallet.html) could look like this: - - - - - - - +::: diff --git a/docs/probing.md b/docs/probing.md index 8baa414c0..920fb67a9 100644 --- a/docs/probing.md +++ b/docs/probing.md @@ -235,12 +235,15 @@ To instantiate the background processor, you need to pass in the required compon // by sending a signal that can be checked at appropriate intervals. let (bp_exit, bp_exit_check) = tokio::sync::watch::channel(()); let mut background_processor = tokio::spawn(process_events_async( - Arc::clone(&persister), // Persister for writing/reading from file system. + Arc::clone(&persister), // KVStore for writing/reading from the file system. event_handler, // Handler for processing various LDK events. chain_monitor.clone(), // Monitors blocks for relevant activity. channel_manager.clone(), // Responsible for managing tasks related to channel state. + Some(onion_messenger.clone()), // Onion messenger (or None). GossipSync::p2p(gossip_sync.clone()), // Handles P2P network gossip. peer_manager.clone(), // Manages peer connections and associated data. + None, // Liquidity manager (NO_LIQUIDITY_MANAGER). + Some(output_sweeper.clone()), // Output sweeper (or None). logger.clone(), // Logger for recording events and errors. Some(scorer.clone()), // Scorer for updating and persisting scoring updates. move |t| { @@ -287,7 +290,7 @@ fn update_scorer<'a, S: 'static + Deref + Send + Sync, SC: 'a + Wri let mut score = scorer.write_lock(); score.probe_successful(path, duration_since_epoch); }, - Event::ailed { path, short_channel_id: Some(scid), .. } => { + Event::ProbeFailed { path, short_channel_id: Some(scid), .. } => { let mut score = scorer.write_lock(); score.probe_failed(path, *scid, duration_since_epoch); }, diff --git a/docs/.vuepress/public/browserconfig.xml b/docs/public/browserconfig.xml similarity index 100% rename from docs/.vuepress/public/browserconfig.xml rename to docs/public/browserconfig.xml diff --git a/docs/.vuepress/public/card.png b/docs/public/card.png similarity index 100% rename from docs/.vuepress/public/card.png rename to docs/public/card.png diff --git a/docs/.vuepress/public/css/variables.css b/docs/public/css/variables.css similarity index 100% rename from docs/.vuepress/public/css/variables.css rename to docs/public/css/variables.css diff --git a/docs/.vuepress/public/favicon.ico b/docs/public/favicon.ico similarity index 100% rename from docs/.vuepress/public/favicon.ico rename to docs/public/favicon.ico diff --git a/docs/.vuepress/public/fonts/ibm-plex-mono-400.woff2 b/docs/public/fonts/ibm-plex-mono-400.woff2 similarity index 100% rename from docs/.vuepress/public/fonts/ibm-plex-mono-400.woff2 rename to docs/public/fonts/ibm-plex-mono-400.woff2 diff --git a/docs/public/img/10101.png b/docs/public/img/10101.png new file mode 100644 index 000000000..3daa50096 Binary files /dev/null and b/docs/public/img/10101.png differ diff --git a/docs/public/img/OM-dm-image-1.png b/docs/public/img/OM-dm-image-1.png new file mode 100644 index 000000000..c8f7ca9d1 Binary files /dev/null and b/docs/public/img/OM-dm-image-1.png differ diff --git a/docs/public/img/OM-dm-image-2.png b/docs/public/img/OM-dm-image-2.png new file mode 100644 index 000000000..2fe817099 Binary files /dev/null and b/docs/public/img/OM-dm-image-2.png differ diff --git a/docs/public/img/OM-dm-image-3.png b/docs/public/img/OM-dm-image-3.png new file mode 100644 index 000000000..66ffb916f Binary files /dev/null and b/docs/public/img/OM-dm-image-3.png differ diff --git a/docs/public/img/OM-dm-image-4.png b/docs/public/img/OM-dm-image-4.png new file mode 100644 index 000000000..ab01cb95d Binary files /dev/null and b/docs/public/img/OM-dm-image-4.png differ diff --git a/docs/public/img/OM-image-1.png b/docs/public/img/OM-image-1.png new file mode 100644 index 000000000..d3a79c48f Binary files /dev/null and b/docs/public/img/OM-image-1.png differ diff --git a/docs/public/img/OM-image-2.png b/docs/public/img/OM-image-2.png new file mode 100644 index 000000000..0bb41a34f Binary files /dev/null and b/docs/public/img/OM-image-2.png differ diff --git a/docs/public/img/OM-image-3.png b/docs/public/img/OM-image-3.png new file mode 100644 index 000000000..9197f1754 Binary files /dev/null and b/docs/public/img/OM-image-3.png differ diff --git a/docs/public/img/OM-image-4.png b/docs/public/img/OM-image-4.png new file mode 100644 index 000000000..431c454e1 Binary files /dev/null and b/docs/public/img/OM-image-4.png differ diff --git a/docs/public/img/abcd_ln_path.png b/docs/public/img/abcd_ln_path.png new file mode 100644 index 000000000..be266a005 Binary files /dev/null and b/docs/public/img/abcd_ln_path.png differ diff --git a/docs/public/img/aciedo.svg b/docs/public/img/aciedo.svg new file mode 100644 index 000000000..2fd57142a --- /dev/null +++ b/docs/public/img/aciedo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/public/img/alby-architecture.png b/docs/public/img/alby-architecture.png new file mode 100644 index 000000000..090353f64 Binary files /dev/null and b/docs/public/img/alby-architecture.png differ diff --git a/docs/.vuepress/public/img/alby-hub-featured.svg b/docs/public/img/alby-hub-featured.svg similarity index 100% rename from docs/.vuepress/public/img/alby-hub-featured.svg rename to docs/public/img/alby-hub-featured.svg diff --git a/docs/public/img/alby-logo.webp b/docs/public/img/alby-logo.webp new file mode 100644 index 000000000..6f290dc3d Binary files /dev/null and b/docs/public/img/alby-logo.webp differ diff --git a/docs/public/img/alby.svg b/docs/public/img/alby.svg new file mode 100644 index 000000000..27c457374 --- /dev/null +++ b/docs/public/img/alby.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/docs/public/img/atomic.png b/docs/public/img/atomic.png new file mode 100644 index 000000000..621c22e9f Binary files /dev/null and b/docs/public/img/atomic.png differ diff --git a/docs/public/img/atomicdex.svg b/docs/public/img/atomicdex.svg new file mode 100644 index 000000000..3235dbe9b --- /dev/null +++ b/docs/public/img/atomicdex.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/img/bdk-logo.svg b/docs/public/img/bdk-logo.svg new file mode 100644 index 000000000..93916d4aa --- /dev/null +++ b/docs/public/img/bdk-logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/public/img/bitkit-architecture.png b/docs/public/img/bitkit-architecture.png new file mode 100644 index 000000000..317e2a5ca Binary files /dev/null and b/docs/public/img/bitkit-architecture.png differ diff --git a/docs/public/img/bitkit.png b/docs/public/img/bitkit.png new file mode 100644 index 000000000..1a25ce0af Binary files /dev/null and b/docs/public/img/bitkit.png differ diff --git a/docs/.vuepress/public/img/bitkit.svg b/docs/public/img/bitkit.svg similarity index 100% rename from docs/.vuepress/public/img/bitkit.svg rename to docs/public/img/bitkit.svg diff --git a/docs/public/img/blinded-path.svg b/docs/public/img/blinded-path.svg new file mode 100644 index 000000000..7939fcca5 --- /dev/null +++ b/docs/public/img/blinded-path.svg @@ -0,0 +1 @@ + diff --git a/docs/.vuepress/public/img/border.svg b/docs/public/img/border.svg similarity index 100% rename from docs/.vuepress/public/img/border.svg rename to docs/public/img/border.svg diff --git a/docs/public/img/c=.png b/docs/public/img/c=.png new file mode 100644 index 000000000..1c75d7db6 Binary files /dev/null and b/docs/public/img/c=.png differ diff --git a/docs/public/img/cash-app-architecture.svg b/docs/public/img/cash-app-architecture.svg new file mode 100644 index 000000000..66ee48454 --- /dev/null +++ b/docs/public/img/cash-app-architecture.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/img/cash-app-logo.png b/docs/public/img/cash-app-logo.png new file mode 100644 index 000000000..1a410b5a9 Binary files /dev/null and b/docs/public/img/cash-app-logo.png differ diff --git a/docs/.vuepress/public/img/cashapp-badge.svg b/docs/public/img/cashapp-badge.svg similarity index 100% rename from docs/.vuepress/public/img/cashapp-badge.svg rename to docs/public/img/cashapp-badge.svg diff --git a/docs/public/img/cashapp.svg b/docs/public/img/cashapp.svg new file mode 100644 index 000000000..3e2ee39e8 --- /dev/null +++ b/docs/public/img/cashapp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/img/etta.png b/docs/public/img/etta.png new file mode 100644 index 000000000..d5714a130 Binary files /dev/null and b/docs/public/img/etta.png differ diff --git a/docs/.vuepress/public/img/favicon/android-chrome-192x192.png b/docs/public/img/favicon/android-chrome-192x192.png similarity index 100% rename from docs/.vuepress/public/img/favicon/android-chrome-192x192.png rename to docs/public/img/favicon/android-chrome-192x192.png diff --git a/docs/.vuepress/public/img/favicon/android-chrome-512x512.png b/docs/public/img/favicon/android-chrome-512x512.png similarity index 100% rename from docs/.vuepress/public/img/favicon/android-chrome-512x512.png rename to docs/public/img/favicon/android-chrome-512x512.png diff --git a/docs/.vuepress/public/img/favicon/apple-touch-icon.png b/docs/public/img/favicon/apple-touch-icon.png similarity index 100% rename from docs/.vuepress/public/img/favicon/apple-touch-icon.png rename to docs/public/img/favicon/apple-touch-icon.png diff --git a/docs/.vuepress/public/img/favicon/mstile-144x144.png b/docs/public/img/favicon/mstile-144x144.png similarity index 100% rename from docs/.vuepress/public/img/favicon/mstile-144x144.png rename to docs/public/img/favicon/mstile-144x144.png diff --git a/docs/.vuepress/public/img/favicon/mstile-150x150.png b/docs/public/img/favicon/mstile-150x150.png similarity index 100% rename from docs/.vuepress/public/img/favicon/mstile-150x150.png rename to docs/public/img/favicon/mstile-150x150.png diff --git a/docs/.vuepress/public/img/favicon/mstile-310x150.png b/docs/public/img/favicon/mstile-310x150.png similarity index 100% rename from docs/.vuepress/public/img/favicon/mstile-310x150.png rename to docs/public/img/favicon/mstile-310x150.png diff --git a/docs/.vuepress/public/img/favicon/mstile-310x310.png b/docs/public/img/favicon/mstile-310x310.png similarity index 100% rename from docs/.vuepress/public/img/favicon/mstile-310x310.png rename to docs/public/img/favicon/mstile-310x310.png diff --git a/docs/.vuepress/public/img/favicon/mstile-70x70.png b/docs/public/img/favicon/mstile-70x70.png similarity index 100% rename from docs/.vuepress/public/img/favicon/mstile-70x70.png rename to docs/public/img/favicon/mstile-70x70.png diff --git a/docs/.vuepress/public/img/fedimint.png b/docs/public/img/fedimint.png similarity index 100% rename from docs/.vuepress/public/img/fedimint.png rename to docs/public/img/fedimint.png diff --git a/docs/public/img/gatewayd-arch-ldk2.png b/docs/public/img/gatewayd-arch-ldk2.png new file mode 100644 index 000000000..83a5e292e Binary files /dev/null and b/docs/public/img/gatewayd-arch-ldk2.png differ diff --git a/docs/public/img/gatewayd-arch.png b/docs/public/img/gatewayd-arch.png new file mode 100644 index 000000000..0e26454a9 Binary files /dev/null and b/docs/public/img/gatewayd-arch.png differ diff --git a/docs/public/img/github-white.png b/docs/public/img/github-white.png new file mode 100644 index 000000000..9e7c3cf66 Binary files /dev/null and b/docs/public/img/github-white.png differ diff --git a/docs/public/img/github.png b/docs/public/img/github.png new file mode 100644 index 000000000..342ca9c1c Binary files /dev/null and b/docs/public/img/github.png differ diff --git a/docs/public/img/hydranet.png b/docs/public/img/hydranet.png new file mode 100644 index 000000000..d38d848b3 Binary files /dev/null and b/docs/public/img/hydranet.png differ diff --git a/docs/.vuepress/public/img/illustrations.svg b/docs/public/img/illustrations.svg similarity index 98% rename from docs/.vuepress/public/img/illustrations.svg rename to docs/public/img/illustrations.svg index f7ad9610e..9a377e27a 100644 --- a/docs/.vuepress/public/img/illustrations.svg +++ b/docs/public/img/illustrations.svg @@ -11,7 +11,7 @@ - + diff --git a/docs/public/img/kumuly.png b/docs/public/img/kumuly.png new file mode 100644 index 000000000..9a56a7f25 Binary files /dev/null and b/docs/public/img/kumuly.png differ diff --git a/docs/public/img/kuutamo.png b/docs/public/img/kuutamo.png new file mode 100644 index 000000000..d99e6ec88 Binary files /dev/null and b/docs/public/img/kuutamo.png differ diff --git a/docs/public/img/ldk-architecture.svg b/docs/public/img/ldk-architecture.svg new file mode 100644 index 000000000..9f9b83111 --- /dev/null +++ b/docs/public/img/ldk-architecture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/img/ldk-block-processing.svg b/docs/public/img/ldk-block-processing.svg new file mode 100644 index 000000000..657f91127 --- /dev/null +++ b/docs/public/img/ldk-block-processing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/public/img/ldk-peer-management.svg b/docs/public/img/ldk-peer-management.svg new file mode 100644 index 000000000..b3dd28e28 --- /dev/null +++ b/docs/public/img/ldk-peer-management.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/img/ldk-roadmap.png b/docs/public/img/ldk-roadmap.png new file mode 100644 index 000000000..0e3347223 Binary files /dev/null and b/docs/public/img/ldk-roadmap.png differ diff --git a/docs/public/img/lexe-logo.jpg b/docs/public/img/lexe-logo.jpg new file mode 100644 index 000000000..86c62c1bc Binary files /dev/null and b/docs/public/img/lexe-logo.jpg differ diff --git a/docs/public/img/lexe.png b/docs/public/img/lexe.png new file mode 100644 index 000000000..706f26896 Binary files /dev/null and b/docs/public/img/lexe.png differ diff --git a/docs/public/img/lightspark-logo.svg b/docs/public/img/lightspark-logo.svg new file mode 100644 index 000000000..d287b2e4e --- /dev/null +++ b/docs/public/img/lightspark-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/public/img/lightspark.png b/docs/public/img/lightspark.png new file mode 100644 index 000000000..d871be6fa Binary files /dev/null and b/docs/public/img/lightspark.png differ diff --git a/docs/public/img/lightspark.svg b/docs/public/img/lightspark.svg new file mode 100644 index 000000000..8fb8325d1 --- /dev/null +++ b/docs/public/img/lightspark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/public/img/lipa.png b/docs/public/img/lipa.png new file mode 100644 index 000000000..9f3392608 Binary files /dev/null and b/docs/public/img/lipa.png differ diff --git a/docs/public/img/lndk.png b/docs/public/img/lndk.png new file mode 100644 index 000000000..2889039e6 Binary files /dev/null and b/docs/public/img/lndk.png differ diff --git a/docs/.vuepress/public/img/logo.svg b/docs/public/img/logo.svg similarity index 98% rename from docs/.vuepress/public/img/logo.svg rename to docs/public/img/logo.svg index 998b74fb0..9f2e2bfb7 100644 --- a/docs/.vuepress/public/img/logo.svg +++ b/docs/public/img/logo.svg @@ -1,12 +1,12 @@ - + - + diff --git a/docs/public/img/lqwd.png b/docs/public/img/lqwd.png new file mode 100644 index 000000000..a86785aa3 Binary files /dev/null and b/docs/public/img/lqwd.png differ diff --git a/docs/public/img/lqwd_lsp_node.png b/docs/public/img/lqwd_lsp_node.png new file mode 100644 index 000000000..86561cbbb Binary files /dev/null and b/docs/public/img/lqwd_lsp_node.png differ diff --git a/docs/public/img/mercury.png b/docs/public/img/mercury.png new file mode 100644 index 000000000..2dff472f4 Binary files /dev/null and b/docs/public/img/mercury.png differ diff --git a/docs/.vuepress/public/img/mutiny-featured.png b/docs/public/img/mutiny-featured.png similarity index 100% rename from docs/.vuepress/public/img/mutiny-featured.png rename to docs/public/img/mutiny-featured.png diff --git a/docs/public/img/mutiny.png b/docs/public/img/mutiny.png new file mode 100644 index 000000000..33bf684b6 Binary files /dev/null and b/docs/public/img/mutiny.png differ diff --git a/docs/public/img/mutiny.svg b/docs/public/img/mutiny.svg new file mode 100644 index 000000000..c3a51afc3 --- /dev/null +++ b/docs/public/img/mutiny.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/public/img/offer-metadata.svg b/docs/public/img/offer-metadata.svg new file mode 100644 index 000000000..f28c04b54 --- /dev/null +++ b/docs/public/img/offer-metadata.svg @@ -0,0 +1 @@ + diff --git a/docs/public/img/offers-flow.svg b/docs/public/img/offers-flow.svg new file mode 100644 index 000000000..cd21e16fe --- /dev/null +++ b/docs/public/img/offers-flow.svg @@ -0,0 +1 @@ + diff --git a/docs/public/img/phantom-hints.png b/docs/public/img/phantom-hints.png new file mode 100644 index 000000000..86a50ed0e Binary files /dev/null and b/docs/public/img/phantom-hints.png differ diff --git a/docs/public/img/phantom-pmt.png b/docs/public/img/phantom-pmt.png new file mode 100644 index 000000000..503c62b47 Binary files /dev/null and b/docs/public/img/phantom-pmt.png differ diff --git a/docs/public/img/qr-codes.png b/docs/public/img/qr-codes.png new file mode 100644 index 000000000..0ee808ec6 Binary files /dev/null and b/docs/public/img/qr-codes.png differ diff --git a/docs/public/img/scoring_initial_histogram.png b/docs/public/img/scoring_initial_histogram.png new file mode 100644 index 000000000..d3daf4228 Binary files /dev/null and b/docs/public/img/scoring_initial_histogram.png differ diff --git a/docs/public/img/scoring_initial_rene_cdf.png b/docs/public/img/scoring_initial_rene_cdf.png new file mode 100644 index 000000000..8ab4bcc66 Binary files /dev/null and b/docs/public/img/scoring_initial_rene_cdf.png differ diff --git a/docs/public/img/scoring_modern_nonlinear_cdf.png b/docs/public/img/scoring_modern_nonlinear_cdf.png new file mode 100644 index 000000000..0b72b824e Binary files /dev/null and b/docs/public/img/scoring_modern_nonlinear_cdf.png differ diff --git a/docs/public/img/scoring_og_nonlinear_cdf.png b/docs/public/img/scoring_og_nonlinear_cdf.png new file mode 100644 index 000000000..bd8c17512 Binary files /dev/null and b/docs/public/img/scoring_og_nonlinear_cdf.png differ diff --git a/docs/public/img/scoring_real_histogram.png b/docs/public/img/scoring_real_histogram.png new file mode 100644 index 000000000..dae28b47a Binary files /dev/null and b/docs/public/img/scoring_real_histogram.png differ diff --git a/docs/public/img/scoring_results.png b/docs/public/img/scoring_results.png new file mode 100644 index 000000000..c10671ba7 Binary files /dev/null and b/docs/public/img/scoring_results.png differ diff --git a/docs/public/img/scoring_second_histogram.png b/docs/public/img/scoring_second_histogram.png new file mode 100644 index 000000000..cff94689c Binary files /dev/null and b/docs/public/img/scoring_second_histogram.png differ diff --git a/docs/public/img/scoring_truncated_og_cdf.png b/docs/public/img/scoring_truncated_og_cdf.png new file mode 100644 index 000000000..5667c5c0d Binary files /dev/null and b/docs/public/img/scoring_truncated_og_cdf.png differ diff --git a/docs/public/img/sensei-architecture.svg b/docs/public/img/sensei-architecture.svg new file mode 100644 index 000000000..355821928 --- /dev/null +++ b/docs/public/img/sensei-architecture.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/.vuepress/public/img/sensei-main.png b/docs/public/img/sensei-main.png similarity index 100% rename from docs/.vuepress/public/img/sensei-main.png rename to docs/public/img/sensei-main.png diff --git a/docs/public/img/sensei.png b/docs/public/img/sensei.png new file mode 100644 index 000000000..2c730f41a Binary files /dev/null and b/docs/public/img/sensei.png differ diff --git a/docs/public/img/teos-architecture-diagram.png b/docs/public/img/teos-architecture-diagram.png new file mode 100644 index 000000000..0c83143cc Binary files /dev/null and b/docs/public/img/teos-architecture-diagram.png differ diff --git a/docs/.vuepress/public/img/teos-main.png b/docs/public/img/teos-main.png similarity index 100% rename from docs/.vuepress/public/img/teos-main.png rename to docs/public/img/teos-main.png diff --git a/docs/public/img/teos.png b/docs/public/img/teos.png new file mode 100644 index 000000000..473931834 Binary files /dev/null and b/docs/public/img/teos.png differ diff --git a/docs/public/img/teos.svg b/docs/public/img/teos.svg new file mode 100644 index 000000000..650b4f1a5 --- /dev/null +++ b/docs/public/img/teos.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/img/valera.png b/docs/public/img/valera.png new file mode 100644 index 000000000..d6b1d47fc Binary files /dev/null and b/docs/public/img/valera.png differ diff --git a/docs/public/img/velas.png b/docs/public/img/velas.png new file mode 100644 index 000000000..930542ec7 Binary files /dev/null and b/docs/public/img/velas.png differ diff --git a/docs/public/img/vls.png b/docs/public/img/vls.png new file mode 100644 index 000000000..7146754f3 Binary files /dev/null and b/docs/public/img/vls.png differ diff --git a/docs/public/img/voltage.png b/docs/public/img/voltage.png new file mode 100644 index 000000000..ed10bca6d Binary files /dev/null and b/docs/public/img/voltage.png differ diff --git a/docs/public/img/vss-data-flow-simplified.svg b/docs/public/img/vss-data-flow-simplified.svg new file mode 100644 index 000000000..5e8f0085d --- /dev/null +++ b/docs/public/img/vss-data-flow-simplified.svg @@ -0,0 +1 @@ +VSS High Level Data FlowVSS High Level Data FlowMobileDeviceVSSStorageMobileDeviceMobileDeviceVSSVSSStorageStorageAuthentication Requestsome(authToken)loop[for every payment sent/received]Update LN Channel StateAtomic Update LN Channel StateSuccess \ No newline at end of file diff --git a/docs/.vuepress/public/llms.txt b/docs/public/llms.txt similarity index 100% rename from docs/.vuepress/public/llms.txt rename to docs/public/llms.txt diff --git a/docs/.vuepress/public/site.webmanifest b/docs/public/site.webmanifest similarity index 100% rename from docs/.vuepress/public/site.webmanifest rename to docs/public/site.webmanifest diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 000000000..5c331a40c --- /dev/null +++ b/netlify.toml @@ -0,0 +1,9 @@ +# Build the VitePress site for Netlify deploy previews (and production). +# Overrides any build command/publish dir configured in the Netlify UI, +# which still pointed at the old VuePress pipeline. +[build] + command = "npm run build:vitepress" + publish = "docs/.vitepress/dist" + +[build.environment] + NODE_VERSION = "22" diff --git a/package-lock.json b/package-lock.json index 08077378e..a23a9e1b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,321 @@ "broken-link-checker": "0.7.8", "serve": "14.2.6", "start-server-and-test": "3.0.5", + "vitepress": "^1.5.0", "vue": "2.7.16", "vue-server-renderer": "2.7.16", "vuepress": "1.9.10" } }, + "node_modules/@algolia/abtesting": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.18.1.tgz", + "integrity": "sha512-aehCadlWOGvrT91KUIZpC0MbB8KBW9yUuvTJFd2xesR7le/IsT4nJUnjCCZ4ZqZCeTcPHPV5mo//fZ5oxcSVYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "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-core/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/autocomplete-core/node_modules/algoliasearch": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.1.tgz", + "integrity": "sha512-fHA8+kXTbjagw3jkLiaS7KKrH8qe2DyOsiUhGlN4cdT77PEsfqXZl7ewDk1hsg+pJnPlnE50XtLxjR91iJOpmg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/abtesting": "1.18.1", + "@algolia/client-abtesting": "5.52.1", + "@algolia/client-analytics": "5.52.1", + "@algolia/client-common": "5.52.1", + "@algolia/client-insights": "5.52.1", + "@algolia/client-personalization": "5.52.1", + "@algolia/client-query-suggestions": "5.52.1", + "@algolia/client-search": "5.52.1", + "@algolia/ingestion": "1.52.1", + "@algolia/monitoring": "1.52.1", + "@algolia/recommend": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "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-plugin-algolia-insights/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/autocomplete-plugin-algolia-insights/node_modules/algoliasearch": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.1.tgz", + "integrity": "sha512-fHA8+kXTbjagw3jkLiaS7KKrH8qe2DyOsiUhGlN4cdT77PEsfqXZl7ewDk1hsg+pJnPlnE50XtLxjR91iJOpmg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/abtesting": "1.18.1", + "@algolia/client-abtesting": "5.52.1", + "@algolia/client-analytics": "5.52.1", + "@algolia/client-common": "5.52.1", + "@algolia/client-insights": "5.52.1", + "@algolia/client-personalization": "5.52.1", + "@algolia/client-query-suggestions": "5.52.1", + "@algolia/client-search": "5.52.1", + "@algolia/ingestion": "1.52.1", + "@algolia/monitoring": "1.52.1", + "@algolia/recommend": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.52.1.tgz", + "integrity": "sha512-HmXOGBOAOJPounpBzBpuY0zDYeiCpxgHnQmuA7JO6ScukcBdGp3/XM9zJk5pJx/xNGD68mbPGXWpDxGtl6BwDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.52.1.tgz", + "integrity": "sha512-5oo4+I8iixie9vXhCyNFCzeIr8pqA3FQ//VsLHTDvZAV4ttYOPGvYHGQq5NSalrLx5Jc3dRro/5uDOlnUMcBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.52.1.tgz", + "integrity": "sha512-qCDoZfx5MpX7XQzvQ3bC4tSEMkQWQMaF/ABtLuoze03Y/flR563CCSws02qIJ23oX7lxl92LsilZjINVyTdtLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.52.1.tgz", + "integrity": "sha512-hnGs0/lsFJ2PWDxNBz7pxreXo/Xz7gxYRcfePBUjsH26ad0kU/sgnVZd9LwWBpsQv65z2jlb5dkyaB9WE9M9FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.52.1.tgz", + "integrity": "sha512-2VxxNc/uBysyKvGeBdSM5n9eIDKH8kWD7wd9/yqbJAiVwU4Yv6tU1LSJusHKrXV/aCu1KW7t9Gug9QyeEmtn/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.52.1.tgz", + "integrity": "sha512-O6mPtsw3xEfNOe6gWFpYLeAZAIljNa4Hgna3bq15PwyN7nbjTY0wXJFRbzs/0YVf75Br+SbOQUmjKxXYjDiSiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.52.1.tgz", + "integrity": "sha512-gA8oJOV1LnQQkDf91iebNnFInHuW0gRPEgLSOQ7EfipCEjYTHm5swm1DlH9H5RaRw4RrHuzHBegnlzc0MAstcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.52.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.52.1.tgz", + "integrity": "sha512-U9zZfc5xIu9wRxZkt+HceJUAD4VKHKbAyLSloJdEyMRmphXeibfrY9cxqIXBcmPeZzGhn3Imb35Dq8l19PkJhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.52.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.52.1.tgz", + "integrity": "sha512-a3SGNceHmkQfq77iG8Ka+w1pvwfZa/0lzEIgse30fL0kD+yKnd/dg0dQvSfFPAEt2f21DMcGkDSSeJlO3KdQjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.52.1.tgz", + "integrity": "sha512-z98QEguCFDpxb4S/PyrUK1igqF8tPsdbqOUUO6ON91vJ58w+Gwa6ncrI0oNXSFcrkxA5EqPKPQ2A1PBCn08TYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.52.1.tgz", + "integrity": "sha512-CI7+/0I11QeZM59Uc8whd2or0kqzFVjpaPn9Qpwll/krHcBAxk24WkAQ6WX+IwDVMfpont4YGbKwAmCre3vE8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.52.1.tgz", + "integrity": "sha512-S6bDuw9byfOvm3T71cgdoZgrgnZq6hpdMLkx52Louh57nUAmvGQESz2aojOynQHjbTiV55smvAFbgn0qT4tJrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.52.1.tgz", + "integrity": "sha512-tqZXM+54rWo4mk5jL5Z/flE11nPmNEdXwFBM5py9DkOmbjeCNemfVd45FyM97XdzfZ0dl9uOJC6PYn1FpkeyQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -1848,139 +2158,1099 @@ "deprecated": "Potential XSS vulnerability patched in v6.0.0.", "dev": true }, - "node_modules/@hapi/address": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", - "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/formula": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", - "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/hoek": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/pinpoint": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", - "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", + "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": "BSD-3-Clause" + "license": "MIT" }, - "node_modules/@hapi/tlds": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", - "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", + "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": "BSD-3-Clause", - "engines": { - "node": ">=14.0.0" + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" } }, - "node_modules/@hapi/topo": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", + "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": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@hapi/hoek": "^11.0.2" + "@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/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@docsearch/react/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": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@docsearch/react/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", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@docsearch/react/node_modules/algoliasearch": { + "version": "5.52.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.1.tgz", + "integrity": "sha512-fHA8+kXTbjagw3jkLiaS7KKrH8qe2DyOsiUhGlN4cdT77PEsfqXZl7ewDk1hsg+pJnPlnE50XtLxjR91iJOpmg==", "dev": true, "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.18.1", + "@algolia/client-abtesting": "5.52.1", + "@algolia/client-analytics": "5.52.1", + "@algolia/client-common": "5.52.1", + "@algolia/client-insights": "5.52.1", + "@algolia/client-personalization": "5.52.1", + "@algolia/client-query-suggestions": "5.52.1", + "@algolia/client-search": "5.52.1", + "@algolia/ingestion": "1.52.1", + "@algolia/monitoring": "1.52.1", + "@algolia/recommend": "5.52.1", + "@algolia/requester-browser-xhr": "5.52.1", + "@algolia/requester-fetch": "5.52.1", + "@algolia/requester-node-http": "5.52.1" + }, "engines": { - "node": ">=6.0.0" + "node": ">= 14.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "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" + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "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", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "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" + "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/@hapi/address": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", + "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^11.0.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@hapi/formula": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", + "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/hoek": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", + "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/pinpoint": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", + "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/tlds": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", + "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@hapi/topo": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", + "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^11.0.2" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.82", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.82.tgz", + "integrity": "sha512-4p978qHx8eD/QBOhgBzp/p7uS3OO2KCnVpFPJTUvuhuDXv1Hr4RcxcZ5MWc6ptkf/3Dlb1xb23068OtPyx10mA==", + "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/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "dependencies": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "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": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - }, - "engines": { - "node": ">=4" + "@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/@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "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, - "engines": { - "node": ">= 6" + "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/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -2063,6 +3333,13 @@ "@types/node": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/express": { "version": "4.17.17", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", @@ -2097,6 +3374,16 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/highlight.js": { "version": "9.12.4", "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", @@ -2126,10 +3413,11 @@ "license": "MIT" }, "node_modules/@types/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==", - "dev": true + "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": "10.0.3", @@ -2143,11 +3431,22 @@ "highlight.js": "^9.7.0" } }, + "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": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true + "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/mime": { "version": "1.3.2", @@ -2228,6 +3527,20 @@ "source-map": "^0.6.1" } }, + "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/@types/webpack": { "version": "4.41.33", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz", @@ -2275,6 +3588,13 @@ "node": ">= 8" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@vssue/api-github-v3": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@vssue/api-github-v3/-/api-github-v3-1.4.7.tgz", @@ -2697,6 +4017,76 @@ "url": "https://opencollective.com/postcss/" } }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "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.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.34.tgz", + "integrity": "sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.34" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.34.tgz", + "integrity": "sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.34", + "@vue/shared": "3.5.34" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.34.tgz", + "integrity": "sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.34", + "@vue/runtime-core": "3.5.34", + "@vue/shared": "3.5.34", + "csstype": "^3.2.3" + } + }, "node_modules/@vue/shared": { "version": "3.5.34", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.34.tgz", @@ -3130,6 +4520,153 @@ "webpack-chain": "^6.0.0" } }, + "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/core/node_modules/@vue/compiler-sfc": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz", + "integrity": "sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.34", + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.14", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vueuse/core/node_modules/@vue/server-renderer": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.34.tgz", + "integrity": "sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34" + }, + "peerDependencies": { + "vue": "3.5.34" + } + }, + "node_modules/@vueuse/core/node_modules/vue": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz", + "integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-sfc": "3.5.34", + "@vue/runtime-dom": "3.5.34", + "@vue/server-renderer": "3.5.34", + "@vue/shared": "3.5.34" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "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/@vueuse/shared/node_modules/@vue/compiler-sfc": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz", + "integrity": "sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.34", + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.14", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vueuse/shared/node_modules/@vue/server-renderer": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.34.tgz", + "integrity": "sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34" + }, + "peerDependencies": { + "vue": "3.5.34" + } + }, + "node_modules/@vueuse/shared/node_modules/vue": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz", + "integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-sfc": "3.5.34", + "@vue/runtime-dom": "3.5.34", + "@vue/server-renderer": "3.5.34", + "@vue/shared": "3.5.34" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -4328,6 +5865,16 @@ "file-uri-to-path": "1.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/bluebird": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", @@ -5251,6 +6798,17 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "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/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -5356,6 +6914,28 @@ "integrity": "sha512-acv43vqJ0+N0rD+Uw3pDHSxP30FHrywu2NO6/wBaHChJIizpDeBUd6NjqhNhy9LGaEAhZAXn46QzmlAvIWd16g==", "dev": true }, + "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/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -6082,6 +7662,17 @@ "stream-length": "^1.0.1" } }, + "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/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -6296,6 +7887,22 @@ "dev": true, "license": "MIT" }, + "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/copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -7096,10 +8703,11 @@ "license": "CC0-1.0" }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "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/cyclist": { "version": "1.0.2", @@ -8295,6 +9903,16 @@ "node": ">= 0.8" } }, + "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/des.js": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", @@ -8330,6 +9948,20 @@ "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==", "dev": true }, + "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/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -8630,6 +10262,13 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "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/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", @@ -9984,6 +11623,16 @@ "readable-stream": "^2.3.6" } }, + "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/follow-redirects": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", @@ -10812,6 +12461,44 @@ "node": ">= 0.4" } }, + "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/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -10864,6 +12551,13 @@ "hulk": "bin/hulk" } }, + "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/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -10937,6 +12631,17 @@ "node": ">=4" } }, + "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/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", @@ -12248,6 +13953,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -12832,6 +14550,13 @@ "node": ">=0.10.0" } }, + "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/markdown-it": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", @@ -12982,6 +14707,28 @@ "safe-buffer": "^5.1.2" } }, + "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/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -13097,6 +14844,100 @@ "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==", "dev": true }, + "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/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -13261,6 +15102,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -13304,6 +15152,13 @@ "node": ">=0.4" } }, + "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/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -14082,6 +15937,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/opencollective-postinstall": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", @@ -14573,6 +16440,13 @@ ], "license": "MIT" }, + "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/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -16262,6 +18136,17 @@ "dev": true, "license": "MIT" }, + "node_modules/preact": { + "version": "10.29.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz", + "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -16341,6 +18226,17 @@ "dev": true, "license": "ISC" }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -16872,6 +18768,16 @@ "node": ">=4" } }, + "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-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -16910,6 +18816,23 @@ "node": ">=0.10.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/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -17329,6 +19252,13 @@ "node": ">= 4" } }, + "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/rgb-regex": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", @@ -17445,6 +19375,66 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", "dev": true }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/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/run-queue": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", @@ -17572,6 +19562,14 @@ "url": "https://opencollective.com/webpack" } }, + "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/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -18018,6 +20016,23 @@ "node": ">=8" } }, + "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/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -18414,6 +20429,17 @@ "deprecated": "See https://github.com/lydell/source-map-url#deprecated", "dev": true }, + "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/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -18511,6 +20537,16 @@ "dev": true, "license": "MIT" }, + "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/speech-rule-engine": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz", @@ -18954,6 +20990,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -19148,6 +21199,19 @@ "node": ">= 8" } }, + "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/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -19220,6 +21284,13 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "dev": true, + "license": "MIT" + }, "node_modules/tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -19775,6 +21846,17 @@ "tree-kill": "cli.js" } }, + "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/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -20058,26 +22140,99 @@ "unique-slug": "^2.0.0" } }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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": "ISC", + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4" + "@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/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "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": { - "crypto-random-string": "^2.0.0" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/universalify": { @@ -20693,6 +22848,408 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, + "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/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/vitepress/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/vitepress/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/vitepress/node_modules/@vue/compiler-sfc": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz", + "integrity": "sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.34", + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.14", + "source-map-js": "^1.2.1" + } + }, + "node_modules/vitepress/node_modules/@vue/server-renderer": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.34.tgz", + "integrity": "sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34" + }, + "peerDependencies": { + "vue": "3.5.34" + } + }, + "node_modules/vitepress/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/vitepress/node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/vitepress/node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/vitepress/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/vitepress/node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vitepress/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/vitepress/node_modules/terser": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vitepress/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/node_modules/vue": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz", + "integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-sfc": "3.5.34", + "@vue/runtime-dom": "3.5.34", + "@vue/server-renderer": "3.5.34", + "@vue/shared": "3.5.34" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -22907,6 +25464,17 @@ "resolved": "https://registry.npmjs.org/zepto/-/zepto-1.2.0.tgz", "integrity": "sha512-C1x6lfvBICFTQIMgbt3JqMOno3VOtkWat/xEakLTOurskYIHPmzJrzd1e8BnmtdDVJlGuk5D+FxyCA8MPmkIyA==", "dev": 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/package.json b/package.json index eb1756161..598e93ac3 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "prestart": "rm -rf $npm_package_config_dist", "start": "NODE_ENV=development vuepress dev docs -p $npm_package_config_port", "build": "NODE_ENV=production vuepress build docs", + "start:vitepress": "vitepress dev docs", + "build:vitepress": "vitepress build docs", "linkcheck": "start-server-and-test linkcheck:serve $npm_package_config_port linkcheck:local", "linkcheck:serve": "serve -p $npm_package_config_port $npm_package_config_dist", "linkcheck:local": "$npm_package_config_linkcheck http://localhost:$npm_package_config_port" @@ -34,6 +36,7 @@ "broken-link-checker": "0.7.8", "serve": "14.2.6", "start-server-and-test": "3.0.5", + "vitepress": "^1.5.0", "vue": "2.7.16", "vue-server-renderer": "2.7.16", "vuepress": "1.9.10" diff --git a/scripts/migrate-codeswitcher.mjs b/scripts/migrate-codeswitcher.mjs new file mode 100644 index 000000000..6c3f40fd4 --- /dev/null +++ b/scripts/migrate-codeswitcher.mjs @@ -0,0 +1,93 @@ +#!/usr/bin/env node +// One-shot migration script: (VuePress 1 spiralbtc theme) +// -> ::: code-group (VitePress built-in). +// +// Usage: +// node scripts/migrate-codeswitcher.mjs +// +// Idempotent: skips files with no CodeSwitcher blocks. Safe to run twice. +// +// This script is one-shot and can be deleted after the migration lands. + +import fs from 'node:fs' + +const files = process.argv.slice(2) +if (files.length === 0) { + console.error('Usage: node scripts/migrate-codeswitcher.mjs ') + process.exit(1) +} + +const codeSwitcherRe = + /([\s\S]*?)<\/CodeSwitcher>/g +const templateRe = + /([\s\S]*?)<\/template>/g + +function parseLanguagesMap(raw) { + // raw looks like `{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}`. + const inner = raw.replace(/^\{|\}$/g, '') + const labels = {} + for (const pair of inner.split(',')) { + const m = pair.match(/^\s*['"]?([\w-]+)['"]?\s*:\s*['"]([^'"]+)['"]\s*$/) + if (m) labels[m[1]] = m[2] + } + return labels +} + +function dedent(text) { + const lines = text.split('\n') + // Strip pure leading/trailing blank lines for measurement. + const nonBlank = lines.filter((l) => l.trim().length > 0) + if (nonBlank.length === 0) return '' + const indents = nonBlank.map((l) => l.match(/^[ \t]*/)[0].length) + const minIndent = Math.min(...indents) + if (minIndent === 0) return lines.join('\n') + return lines + .map((l) => (l.length >= minIndent ? l.slice(minIndent) : l)) + .join('\n') +} + +function transformTemplate(slotName, slotContent, labels) { + const label = labels[slotName] || slotName + const dedented = dedent(slotContent).trim() + + // Inject `[Label]` after the first opening code-fence language tag. + // Don't change the language token itself — the original may legitimately + // use a different fence (e.g. kotlin slot rendering as ```java). + const withLabel = dedented.replace( + /^(```[\w-]*)\s*$/m, + (_, fence) => `${fence} [${label}]`, + ) + return withLabel +} + +let totalBlocks = 0 +let filesChanged = 0 + +for (const file of files) { + const original = fs.readFileSync(file, 'utf8') + let blocksInFile = 0 + + const transformed = original.replace(codeSwitcherRe, (_match, langMap, body) => { + blocksInFile++ + const labels = parseLanguagesMap(langMap) + const blocks = [] + let templateMatch + templateRe.lastIndex = 0 + while ((templateMatch = templateRe.exec(body)) !== null) { + const [, slot, content] = templateMatch + blocks.push(transformTemplate(slot, content, labels)) + } + return `::: code-group\n\n${blocks.join('\n\n')}\n\n:::` + }) + + if (blocksInFile > 0) { + fs.writeFileSync(file, transformed) + console.log(`✓ ${file}: ${blocksInFile} block(s)`) + filesChanged++ + totalBlocks += blocksInFile + } +} + +console.log( + `\n${totalBlocks} CodeSwitcher block(s) converted across ${filesChanged} file(s).`, +)