diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index bc54724..e32c75c 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -5,6 +5,9 @@ on:
branches: [main]
paths:
- "docs/**"
+ - "server/openapi.yml"
+ - "frontend/ds/openapi.yml"
+ - "frontend/s2/openapi.yml"
- ".github/workflows/docs.yml"
workflow_dispatch:
diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index 93bdb73..29c8ad8 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -1,4 +1,6 @@
import { defineConfig } from 'vitepress';
+import { useSidebar } from 'vitepress-openapi';
+import { adminSpec, dsSpec, s2Spec } from './specs';
function sideItem(label: string, link: string, path: string) {
return {
@@ -7,6 +9,102 @@ function sideItem(label: string, link: string, path: string) {
};
}
+function operationItems(spec: object, prefix: string) {
+ return useSidebar({ spec, linkPrefix: prefix })
+ .generateSidebarGroups({ linkPrefix: prefix })
+ .flatMap((group) => group.items ?? []);
+}
+
+const docsSidebar = [
+ sideItem(
+ 'Introduction',
+ '/introduction',
+ '',
+ ),
+ sideItem(
+ 'Quickstart',
+ '/quickstart',
+ '',
+ ),
+ sideItem(
+ 'Benchmark',
+ '/benchmark',
+ '',
+ ),
+ {
+ ...sideItem(
+ 'Protocol',
+ '/protocol',
+ '',
+ ),
+ collapsed: false,
+ items: [
+ {
+ ...sideItem(
+ 'Durable Streams',
+ '/protocol/durable-streams',
+ '',
+ ),
+ collapsed: true,
+ items: operationItems(dsSpec, '/protocol/durable-streams/'),
+ },
+ {
+ ...sideItem(
+ 'S2',
+ '/protocol/s2',
+ '',
+ ),
+ collapsed: true,
+ items: operationItems(s2Spec, '/protocol/s2/'),
+ },
+ ],
+ },
+ {
+ ...sideItem(
+ 'Deployment',
+ '/deployment',
+ '',
+ ),
+ collapsed: false,
+ items: [
+ sideItem(
+ 'AWS',
+ '/deployment/aws',
+ '',
+ ),
+ sideItem(
+ 'Fly.io',
+ '/deployment/fly',
+ '',
+ ),
+ ],
+ },
+ {
+ ...sideItem(
+ 'Operations',
+ '/operations',
+ '',
+ ),
+ collapsed: false,
+ items: [
+ sideItem(
+ 'Durability',
+ '/operations/durability',
+ '',
+ ),
+ {
+ ...sideItem(
+ 'Admin',
+ '/operations/api',
+ '',
+ ),
+ collapsed: true,
+ items: operationItems(adminSpec, '/operations/api/'),
+ },
+ ],
+ },
+];
+
export default defineConfig({
title: 'Stream Stack',
description: 'A durable stream engine on object storage.',
@@ -16,6 +114,11 @@ export default defineConfig({
srcDir: 'pages',
vite: {
publicDir: 'assets',
+ server: {
+ fs: {
+ allow: ['..'],
+ },
+ },
},
markdown: {
theme: 'github-dark',
@@ -35,43 +138,7 @@ export default defineConfig({
{ text: 'Home', link: '/' },
{ text: 'Docs', link: '/introduction' },
],
- sidebar: [
- sideItem(
- 'Introduction',
- '/introduction',
- '',
- ),
- sideItem(
- 'Quickstart',
- '/quickstart',
- '',
- ),
- sideItem(
- 'Benchmark',
- '/benchmark',
- '',
- ),
- {
- ...sideItem(
- 'Deployment',
- '/deployment',
- '',
- ),
- collapsed: false,
- items: [
- sideItem(
- 'AWS',
- '/deployment/aws',
- '',
- ),
- sideItem(
- 'Fly.io',
- '/deployment/fly',
- '',
- ),
- ],
- },
- ],
+ sidebar: docsSidebar,
search: {
provider: 'local',
},
@@ -86,4 +153,9 @@ export default defineConfig({
copyright: '© 2026 Modak Labs. Apache 2.0.',
},
},
+ transformPageData(pageData) {
+ if (pageData.params?.pageTitle) {
+ pageData.title = pageData.params.pageTitle;
+ }
+ },
});
diff --git a/docs/.vitepress/specs.ts b/docs/.vitepress/specs.ts
new file mode 100644
index 0000000..fe1ca53
--- /dev/null
+++ b/docs/.vitepress/specs.ts
@@ -0,0 +1,14 @@
+import { readFileSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import { resolve } from 'node:path';
+import { parseSpec } from 'vitepress-openapi';
+
+const streamstack = resolve(fileURLToPath(new URL('../..', import.meta.url)));
+
+function loadSpec(rel: string) {
+ return parseSpec(readFileSync(resolve(streamstack, rel), 'utf8'));
+}
+
+export const dsSpec = loadSpec('frontend/ds/openapi.yml');
+export const s2Spec = loadSpec('frontend/s2/openapi.yml');
+export const adminSpec = loadSpec('server/openapi.yml');
diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css
index 5ccbef4..d9c8ea4 100644
--- a/docs/.vitepress/theme/custom.css
+++ b/docs/.vitepress/theme/custom.css
@@ -234,14 +234,12 @@
}
.VPDoc h1 {
- font-size: clamp(2.25rem, 5vw, 3.5rem);
- line-height: 1.05;
+ font-size: clamp(1.7rem, 3vw, 2.05rem);
+ line-height: 1.15;
}
-.vp-doc h2:first-of-type {
- margin-top: 1.25rem;
- padding-top: 0;
- border-top: none;
+.vp-doc h2 {
+ margin-top: 2rem;
}
.vp-doc div[class*="language-"] {
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
index 2300b26..4382c2e 100644
--- a/docs/.vitepress/theme/index.ts
+++ b/docs/.vitepress/theme/index.ts
@@ -1,11 +1,13 @@
import DefaultTheme from 'vitepress/theme';
import { h } from 'vue';
import type { Theme } from 'vitepress';
+import { theme as openapiTheme } from 'vitepress-openapi/client';
import ColorSwitch from './ColorSwitch.vue';
import HeroDither from './HeroDither.vue';
import HomeChips from './HomeChips.vue';
import HomeBento from './HomeBento.vue';
import SiteLogo from './SiteLogo.vue';
+import 'vitepress-openapi/dist/style.css';
import './custom.css';
export default {
@@ -21,4 +23,7 @@ export default {
h('p', { class: 'ss-doc-copyright' }, '© 2026 Modak Labs. Apache 2.0.'),
});
},
+ enhanceApp({ app }) {
+ openapiTheme.enhanceApp({ app });
+ },
} satisfies Theme;
diff --git a/docs/package-lock.json b/docs/package-lock.json
index ba85e1c..771a306 100644
--- a/docs/package-lock.json
+++ b/docs/package-lock.json
@@ -6,7 +6,8 @@
"": {
"name": "streamstack-docs",
"dependencies": {
- "@paper-design/shaders": "0.0.80"
+ "@paper-design/shaders": "0.0.80",
+ "vitepress-openapi": "^0.2.4"
},
"devDependencies": {
"vitepress": "^1.6.4"
@@ -16,7 +17,6 @@
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.22.0.tgz",
"integrity": "sha512-BFR6zNowNKcY7Ou7TaJc9QWexES4YKPbmf/OTFofpdsdhz4x6q0lbxp3duO0EHnyrN7rE4ba/TSXuY+BDGu4+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -32,7 +32,6 @@
"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",
@@ -43,7 +42,6 @@
"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"
@@ -56,7 +54,6 @@
"version": "1.17.7",
"resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz",
"integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/autocomplete-shared": "1.17.7"
@@ -70,7 +67,6 @@
"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",
@@ -81,7 +77,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.56.0.tgz",
"integrity": "sha512-7r4Z3NC7yU1oAQVWJNA2HX7tX481F3pJvCGyLIXiTdBcthz4Q/o21jwcMYDFkuI92UWTNBQQmHYgwHo1zS5dzg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -97,7 +92,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.56.0.tgz",
"integrity": "sha512-avmjXQSq+jadFO8Xl2em05/uQdQnEmHsJyOAdVbZkmVgpMfxL12aJwVVfGNwYr9nulcpuJN1X0lTaQ5wxuNGcA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -113,7 +107,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.56.0.tgz",
"integrity": "sha512-v2TPStUhY//ripPjIVclZ8AWc7DEGooXULZGFlFu37zNatgHjw34oZZ+OSbbc/YHO+xZwPl62I1k8xH1m4S2eg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.0.0"
@@ -123,7 +116,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.56.0.tgz",
"integrity": "sha512-P0ehROpM4Sem3Sqo5x2cKPgj67D3G3jy0rh1Amwkcvsfr6tkvIcdCmerieanqTF7NxUMPNFLkpIFeMO8Rpa50w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -139,7 +131,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.56.0.tgz",
"integrity": "sha512-SXK3Vn3WVxyzbm31oePZBJkp1wpOyuWdd4B/Pv7n0aXDxmeSWhC1R1FC1517mMrFAIaPH4Rt0x6RUe7ZNjz8FA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -155,7 +146,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.56.0.tgz",
"integrity": "sha512-5+ZdX8garFnmycnZgKhtXHePEaLj5zqDxI/0lkhhluzCcvTn0/PvvTirTg8hHYetQHvn7GDyeAiqTAieMvMW4A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -171,7 +161,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.56.0.tgz",
"integrity": "sha512-+mKUdYvqOi0BcvpAEyCEw49vSBptufIcfibtHz2bdr1pI789M46Yt0uQEk/sxtK3teh71OQvVFHaTDzShUWewQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -187,7 +176,6 @@
"version": "1.56.0",
"resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.56.0.tgz",
"integrity": "sha512-9g/zj+AZx5moFcdFIrYQoVrueXivjUcc3MQHtCYT8WhIuk1lUh1AyEhvJCS0XBZld09cLvd1AZ3BvDBpVpX2UA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -203,7 +191,6 @@
"version": "1.56.0",
"resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.56.0.tgz",
"integrity": "sha512-Qf3Sr6f9A9uxCZUf3MXS0d2b877uYzEB5yxqpVGXAhcJnBCQjrRRon0KvefpGkxy+BshrIJs96OUoMtGqXTFDA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -219,7 +206,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.56.0.tgz",
"integrity": "sha512-GXWG1rWc5wu8hY4N33Y3b6ernY6sAdAvmKWN/zHAiACOx40WnpG0TVX5YazCAr/9gOYGInSiM2A0y2jy2xbiDA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0",
@@ -235,7 +221,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.56.0.tgz",
"integrity": "sha512-7t24cBxaInS3mZb7ddEaZT/tp6q+/aR4YttsQVyP1/i+LmwPR34atO35KjaLFCcRVrlP7sYOAqkCfg6lIRB+ew==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0"
@@ -248,7 +233,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.56.0.tgz",
"integrity": "sha512-R7ePHgVYmDFjZpvrsVAfbDz/d4RxKAYZ5/vgLfIsCVRZRryjWl/3INOxpOICzitehQ5FjNtNjcLQTrmHPTcHBQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0"
@@ -261,7 +245,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.56.0.tgz",
"integrity": "sha512-PIOUXlSnrqM0S+WOgDRb4RzotydJH7ZoT6tOyL7tAO7qJOfvX5wsEW8Pe+PMKMwvuI4/gIyK9cg2H7lJXqnc4Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/client-common": "5.56.0"
@@ -274,7 +257,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -284,7 +266,6 @@
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -294,7 +275,6 @@
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
"integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.8"
@@ -310,7 +290,6 @@
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
"integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.29.7",
@@ -324,14 +303,12 @@
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz",
"integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/@docsearch/js": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz",
"integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@docsearch/react": "3.8.2",
@@ -342,7 +319,6 @@
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz",
"integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/autocomplete-core": "1.17.7",
@@ -378,7 +354,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -395,7 +370,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -412,7 +386,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -429,7 +402,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -446,7 +418,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -463,7 +434,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -480,7 +450,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -497,7 +466,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -514,7 +482,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -531,7 +498,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -548,7 +514,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -565,7 +530,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -582,7 +546,6 @@
"cpu": [
"mips64el"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -599,7 +562,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -616,7 +578,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -633,7 +594,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -650,7 +610,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -667,7 +626,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -684,7 +642,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -701,7 +658,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -718,7 +674,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -735,7 +690,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -752,7 +706,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -762,11 +715,72 @@
"node": ">=12"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
+ "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
+ "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.8.0",
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
+ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
+ "license": "MIT"
+ },
+ "node_modules/@floating-ui/vue": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.1.11.tgz",
+ "integrity": "sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.7.6",
+ "@floating-ui/utils": "^0.2.11",
+ "vue-demi": ">=0.13.0"
+ }
+ },
+ "node_modules/@floating-ui/vue/node_modules/vue-demi": {
+ "version": "0.14.10",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@iconify-json/simple-icons": {
"version": "1.2.93",
"resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.93.tgz",
"integrity": "sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw==",
- "dev": true,
"license": "CC0-1.0",
"dependencies": {
"@iconify/types": "*"
@@ -776,14 +790,30 @@
"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/@internationalized/date": {
+ "version": "3.12.3",
+ "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.3.tgz",
+ "integrity": "sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/helpers": "^0.5.0"
+ }
+ },
+ "node_modules/@internationalized/number": {
+ "version": "3.6.7",
+ "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz",
+ "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/helpers": "^0.5.0"
+ }
+ },
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true,
"license": "MIT"
},
"node_modules/@napi-rs/lzma-linux-x64-gnu": {
@@ -793,7 +823,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -816,7 +845,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -830,7 +858,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -844,7 +871,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -858,7 +884,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -872,7 +897,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -886,7 +910,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -900,7 +923,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -914,7 +936,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -928,7 +949,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -942,7 +962,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -956,7 +975,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -970,7 +988,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -984,7 +1001,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -998,7 +1014,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1012,7 +1027,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1026,7 +1040,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1040,7 +1053,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1054,7 +1066,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1068,7 +1079,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1082,7 +1092,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1096,7 +1105,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1110,7 +1118,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1124,7 +1131,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1138,7 +1144,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1152,7 +1157,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1163,7 +1167,6 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz",
"integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/engine-javascript": "2.5.0",
@@ -1178,7 +1181,6 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz",
"integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@shikijs/types": "2.5.0",
@@ -1190,7 +1192,6 @@
"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",
@@ -1201,7 +1202,6 @@
"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"
@@ -1211,7 +1211,6 @@
"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"
@@ -1221,7 +1220,6 @@
"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",
@@ -1232,7 +1230,6 @@
"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",
@@ -1243,21 +1240,53 @@
"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/@swc/helpers": {
+ "version": "0.5.23",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
+ "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@tanstack/virtual-core": {
+ "version": "3.17.7",
+ "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.7.tgz",
+ "integrity": "sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/vue-virtual": {
+ "version": "3.13.35",
+ "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.35.tgz",
+ "integrity": "sha512-lOfSPvgPdlaH6Qy+CyIc3XpycitaSQ9GECndGpTuDiu+uDA1am+90yWXwzDSd/20ZM196ggWJLS+Qb6WjVd/OA==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/virtual-core": "3.17.7"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "vue": "^2.7.0 || ^3.0.0"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/hast": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz",
"integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "*"
@@ -1267,14 +1296,12 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/markdown-it": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/linkify-it": "^5",
@@ -1285,7 +1312,6 @@
"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": "*"
@@ -1295,35 +1321,30 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/unist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
- "dev": true,
"license": "MIT"
},
"node_modules/@ungap/structured-clone": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz",
"integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==",
- "dev": true,
"license": "ISC"
},
"node_modules/@vitejs/plugin-vue": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
"integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": "^18.0.0 || >=20.0.0"
@@ -1337,7 +1358,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz",
"integrity": "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.8",
@@ -1351,7 +1371,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz",
"integrity": "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/compiler-core": "3.5.41",
@@ -1362,7 +1381,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz",
"integrity": "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.8",
@@ -1380,7 +1398,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz",
"integrity": "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.41",
@@ -1391,7 +1408,6 @@
"version": "7.7.10",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz",
"integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^7.7.10"
@@ -1401,7 +1417,6 @@
"version": "7.7.10",
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz",
"integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^7.7.10",
@@ -1417,7 +1432,6 @@
"version": "7.7.10",
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz",
"integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"rfdc": "^1.4.1"
@@ -1427,7 +1441,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz",
"integrity": "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/shared": "3.5.41"
@@ -1437,7 +1450,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.41.tgz",
"integrity": "sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.41",
@@ -1448,7 +1460,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.41.tgz",
"integrity": "sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.41",
@@ -1461,7 +1472,6 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.41.tgz",
"integrity": "sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/compiler-ssr": "3.5.41",
@@ -1473,14 +1483,12 @@
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz",
"integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==",
- "dev": true,
"license": "MIT"
},
"node_modules/@vueuse/core": {
"version": "12.8.2",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz",
"integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
@@ -1496,7 +1504,6 @@
"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",
@@ -1563,7 +1570,6 @@
"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"
@@ -1573,7 +1579,6 @@
"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"
@@ -1586,7 +1591,6 @@
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.56.0.tgz",
"integrity": "sha512-PrqppUmhT4ENdas2pH9caE7efUcxy6EcSFhWzosiVuQBzu2tQ5yLTI6jwomT/1cuBnivzGfxiJCqDNN9FRRh+Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@algolia/abtesting": "1.22.0",
@@ -1608,11 +1612,22 @@
"node": ">= 14.0.0"
}
},
+ "node_modules/aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"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"
@@ -1622,7 +1637,6 @@
"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",
@@ -1633,7 +1647,6 @@
"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",
@@ -1644,18 +1657,37 @@
"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/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"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",
@@ -1666,7 +1698,6 @@
"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"
@@ -1682,14 +1713,18 @@
"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/defu": {
+ "version": "6.1.7",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
+ "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
"license": "MIT"
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -1699,7 +1734,6 @@
"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"
@@ -1713,14 +1747,12 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz",
"integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==",
- "dev": true,
"license": "MIT"
},
"node_modules/entities": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
- "dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
@@ -1733,7 +1765,6 @@
"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": {
@@ -1772,14 +1803,12 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
- "dev": true,
"license": "MIT"
},
"node_modules/focus-trap": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz",
"integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"tabbable": "^6.4.0"
@@ -1789,7 +1818,6 @@
"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,
@@ -1804,7 +1832,6 @@
"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",
@@ -1828,7 +1855,6 @@
"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"
@@ -1842,14 +1868,12 @@
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/html-void-elements": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
"integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
- "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -1860,7 +1884,6 @@
"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"
@@ -1869,11 +1892,20 @@
"url": "https://github.com/sponsors/mesqueeb"
}
},
+ "node_modules/lucide-vue-next": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-1.0.0.tgz",
+ "integrity": "sha512-V6SPvx1IHTj/UY+FrIYWV5faISsPSb8BnWSFDxAtezWKvWc9ZZ40PDrdu1/Qb5vg4lHWr1hs1BAMGVGm6V1Xdg==",
+ "deprecated": "Package deprecated. Please use @lucide/vue instead.",
+ "license": "ISC",
+ "peerDependencies": {
+ "vue": ">=3.0.1"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
@@ -1883,14 +1915,18 @@
"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-link-attributes": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it-link-attributes/-/markdown-it-link-attributes-4.0.1.tgz",
+ "integrity": "sha512-pg5OK0jPLg62H4k7M9mRJLT61gUp9nvG0XveKYHMOOluASo9OEF13WlXrpAp2aj35LbedAy3QOCgQCw0tkLKAQ==",
"license": "MIT"
},
"node_modules/mdast-util-to-hast": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
"integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
@@ -1912,7 +1948,6 @@
"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",
@@ -1933,7 +1968,6 @@
"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",
@@ -1950,7 +1984,6 @@
"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",
@@ -1972,7 +2005,6 @@
"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",
@@ -1989,7 +2021,6 @@
"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",
@@ -2006,21 +2037,18 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz",
"integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==",
- "dev": true,
"license": "MIT"
},
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.18",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -2035,11 +2063,16 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/ohash": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz",
+ "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==",
+ "license": "MIT"
+ },
"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",
@@ -2051,21 +2084,18 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
- "dev": true,
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.5.26",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
"integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2094,7 +2124,6 @@
"version": "10.29.8",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz",
"integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==",
- "dev": true,
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -2113,7 +2142,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz",
"integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==",
- "dev": true,
"license": "MIT",
"funding": {
"type": "github",
@@ -2124,7 +2152,6 @@
"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"
@@ -2134,7 +2161,6 @@
"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"
@@ -2144,21 +2170,81 @@
"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/reka-ui": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.10.3.tgz",
+ "integrity": "sha512-nJGZbwcha8AcP2wbnjodfzsciTKBqp1mIzepC9Pi2xDI/YK3++ej3vpJOSPyxqrkq1Oorj4K+BdJkbVCV6x6ag==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.6.13",
+ "@floating-ui/vue": "^1.1.6",
+ "@internationalized/date": "^3.5.0",
+ "@internationalized/number": "^3.5.0",
+ "@tanstack/vue-virtual": "^3.12.0",
+ "@vueuse/core": "^14.1.0",
+ "@vueuse/shared": "^14.1.0",
+ "aria-hidden": "^1.2.4",
+ "defu": "^6.1.5",
+ "ohash": "^2.0.11"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/zernonia"
+ },
+ "peerDependencies": {
+ "vue": ">= 3.4.0"
+ }
+ },
+ "node_modules/reka-ui/node_modules/@vueuse/core": {
+ "version": "14.4.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.4.0.tgz",
+ "integrity": "sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.21",
+ "@vueuse/metadata": "14.4.0",
+ "@vueuse/shared": "14.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
+ "node_modules/reka-ui/node_modules/@vueuse/metadata": {
+ "version": "14.4.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.4.0.tgz",
+ "integrity": "sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/reka-ui/node_modules/@vueuse/shared": {
+ "version": "14.4.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.4.0.tgz",
+ "integrity": "sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
- "dev": true,
"license": "MIT"
},
"node_modules/rollup": {
"version": "4.62.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz",
"integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.9"
@@ -2204,7 +2290,6 @@
"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
},
@@ -2212,7 +2297,6 @@
"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",
@@ -2229,7 +2313,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -2239,7 +2322,6 @@
"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",
@@ -2250,7 +2332,6 @@
"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"
@@ -2260,7 +2341,6 @@
"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",
@@ -2275,7 +2355,6 @@
"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"
@@ -2288,25 +2367,28 @@
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz",
"integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==",
- "dev": true,
"license": "MIT"
},
"node_modules/trim-lines": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
"integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
- "dev": true,
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"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"
@@ -2320,7 +2402,6 @@
"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"
@@ -2334,7 +2415,6 @@
"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"
@@ -2348,7 +2428,6 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
"integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -2364,7 +2443,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz",
"integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -2379,7 +2457,6 @@
"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",
@@ -2394,7 +2471,6 @@
"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",
@@ -2409,7 +2485,6 @@
"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",
@@ -2469,7 +2544,6 @@
"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",
@@ -2507,11 +2581,69 @@
}
}
},
+ "node_modules/vitepress-openapi": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/vitepress-openapi/-/vitepress-openapi-0.2.4.tgz",
+ "integrity": "sha512-wzZ4n++Ais5nUG9X7h5V0wF+uvfu17xEb2RpK8Mdp0blGHU56E7WbSzBY8yr3/K2k0164XxVn/r+zYZIvqBKYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vueuse/core": "^14.2.1",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-vue-next": "^1.0.0",
+ "markdown-it-link-attributes": "^4.0.1",
+ "reka-ui": "^2.9.5"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "vitepress": ">=1.0.0",
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/vitepress-openapi/node_modules/@vueuse/core": {
+ "version": "14.4.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.4.0.tgz",
+ "integrity": "sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.21",
+ "@vueuse/metadata": "14.4.0",
+ "@vueuse/shared": "14.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
+ "node_modules/vitepress-openapi/node_modules/@vueuse/metadata": {
+ "version": "14.4.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.4.0.tgz",
+ "integrity": "sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/vitepress-openapi/node_modules/@vueuse/shared": {
+ "version": "14.4.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.4.0.tgz",
+ "integrity": "sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
"node_modules/vue": {
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.41.tgz",
"integrity": "sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.41",
@@ -2533,7 +2665,6 @@
"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",
diff --git a/docs/package.json b/docs/package.json
index da61b3c..2c60a03 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -11,6 +11,7 @@
"vitepress": "^1.6.4"
},
"dependencies": {
- "@paper-design/shaders": "0.0.80"
+ "@paper-design/shaders": "0.0.80",
+ "vitepress-openapi": "^0.2.4"
}
}
diff --git a/docs/pages/deployment.md b/docs/pages/deployment.md
index 6d80035..4be10dd 100644
--- a/docs/pages/deployment.md
+++ b/docs/pages/deployment.md
@@ -1,6 +1,6 @@
# Deployment
-Docker image: `harness/docker`. Deploy `StreamStack` on `local`, [aws](/deployment/aws), or [fly](/deployment/fly). Each node: raft, metadata, and the storage engine in one JVM. [Durable Streams](https://github.com/durable-streams/durable-streams) and [S2](https://github.com/s2-streamstore/s2) are protocol facades over the same engine. Pick one per deployment.
+Docker image: `harness/docker`. Deploy `StreamStack` on `local`, [aws](/deployment/aws), or [fly](/deployment/fly). Each node: raft, metadata, and the storage engine in one JVM. [Durable Streams](/protocol/durable-streams) and [S2](/protocol/s2) are protocol facades over the same engine. Pick one per deployment.
Storage configuration from the topo file (`TOPO`). `DATA_BUCKET` / `WAL_BUCKET` / `BUCKET_NAME` override the topo S3 URIs.
@@ -37,48 +37,4 @@ URI forms: `0@s3://bucket?region=us-east-1`, `-2@file:///path`, `0@mem://bucket`
`--topo` requires `--node-id`. CLI flags override topo values and export credentials in the environment that starts the process.
-## Admin and health
-
-Every node serves an admin plane on a separate port, independent of the protocol facade. Default port is `9090`; set it per node with `adminPort` in the topo, `--admin-port` on the CLI, or `ADMIN_PORT` in the Docker image. Set `0` to disable.
-
-| Endpoint | Description |
-|----------|-------------|
-| `GET /health` | Liveness. `200 ok` as soon as the process is up, before raft and storage are ready |
-| `GET /ready` | Readiness. `200` once raft has a leader, the node is registered, and storage started; `503` otherwise |
-| `GET /admin/cluster` | Cluster and raft status: leader, applied index, stream and object counts |
-| `GET /admin/nodes` | Registered nodes with advertised addresses and epochs |
-| `GET /admin/streams/{name}` | Owner and metadata for a stream |
-| `POST /admin/peers` | Add a raft peer: `{"peer": "host:port"}` (leader only) |
-| `DELETE /admin/peers/{peer}` | Remove a raft peer (leader only) |
-| `POST /admin/transfer-leader` | Transfer raft leadership: `{"peer": "host:port"}` (leader only) |
-| `POST /admin/snapshot` | Trigger a metadata raft snapshot immediately |
-| `GET /admin/snapshots` | Archived metadata snapshots in object storage, with archive health |
-
-The admin port also serves a read-only dashboard at `/` with cluster, node, and raft status.
-
-Point load balancer target-group health checks at `/ready`. On shutdown the node flips `/ready` to `503` first and waits `shutdownDrainSec` (topo config, default `0`) before closing, so the load balancer drains in-flight traffic.
-
-At startup the node verifies the storage and WAL buckets are reachable, retrying with backoff for up to ten attempts before failing; `/health` responds while it retries.
-
-## Metadata durability
-
-Stream data lives in object storage, but metadata (streams, object registry, KV) lives in each node's raft `dataDir`: a periodic local snapshot plus a bounded log. Raft replication covers single-node loss; the snapshot archive covers losing the data directories of a quorum.
-
-The raft leader archives every metadata snapshot to the storage bucket under `_streamstack/metadata/{clusterId}/snapshots/`, keeping the last five. Archival is asynchronous and never blocks the snapshot itself; failures are logged and reported on `GET /admin/snapshots` and the dashboard. Disable with `metadataArchive: false` in the topo config, `--metadata-archive false` on the CLI, or `METADATA_ARCHIVE=false` in the Docker image. Keep the `_streamstack/` key prefix reserved for StreamStack internals.
-
-Run production nodes on durable disks (EBS, not instance storage) for `dataDir`, with a stable DNS name per node.
-
-### Replacing a node
-
-- Disk survived: attach the volume to a replacement machine with the same `nodeId` and DNS name and start it. The node replays its local snapshot and log and rejoins.
-- Disk lost: start a replacement with the same `nodeId` and DNS name and an empty `dataDir`. The raft leader streams its latest snapshot to the new peer and replays the log tail. If the address changed, fix membership with `POST /admin/peers` and `DELETE /admin/peers/{peer}`.
-
-### Restoring from the archive
-
-If a quorum of data directories is lost, bootstrap from the archive:
-
-1. Start node 1 with an empty `dataDir`, a single-peer topo, and `--restore-from-storage true` (or `RESTORE_FROM_STORAGE=true`). The node loads the latest archived snapshot before forming raft and persists it into a local raft snapshot right after election.
-2. Verify with `GET /admin/cluster` and `GET /admin/streams/{name}`.
-3. Add nodes 2 and 3 with empty data dirs via `POST /admin/peers`; they receive the snapshot from the leader.
-
-Restore only runs on a fresh `dataDir`; if local raft state exists it is skipped, and a log without a snapshot fails with instructions to wipe first. Data appended after the last archived snapshot keeps its bytes in the bucket but has no metadata entries; the snapshot interval (30s) bounds that window.
\ No newline at end of file
+Admin plane, health checks, and metadata restore: [Operations](/operations).
\ No newline at end of file
diff --git a/docs/pages/operations.md b/docs/pages/operations.md
new file mode 100644
index 0000000..be35049
--- /dev/null
+++ b/docs/pages/operations.md
@@ -0,0 +1,11 @@
+# Operations
+
+Every node optionally serves an admin-plane on a separate port, independent of the protocol facade. Default port is `9090`. Set it per node with `adminPort` in the topo, `--admin-port` on the CLI, or `ADMIN_PORT` in the Docker image. Set `0` to disable.
+
+The admin APIs also power the dashboard with cluster, node, and raft status.
+
+## Health
+
+Point load-balancer target-group health checks at `/ready`. On shutdown the node flips `/ready` to `503` first and waits `shutdownDrainSec` (topo config, default `0`) before closing, so the load balancer drains in-flight traffic.
+
+At startup the node verifies the storage and WAL buckets are reachable, retrying with backoff for up to ten attempts before failing. `/health` responds while it retries.
diff --git a/docs/pages/operations/api.md b/docs/pages/operations/api.md
new file mode 100644
index 0000000..5a502a6
--- /dev/null
+++ b/docs/pages/operations/api.md
@@ -0,0 +1,8 @@
+---
+aside: false
+outline: false
+---
+
+# Admin API
+
+Admin plane on a separate port from the protocol facade. Default port is `9090`.
diff --git a/docs/pages/operations/api/[operationId].md b/docs/pages/operations/api/[operationId].md
new file mode 100644
index 0000000..2f75be3
--- /dev/null
+++ b/docs/pages/operations/api/[operationId].md
@@ -0,0 +1,13 @@
+---
+aside: false
+outline: false
+---
+
+
+
+
diff --git a/docs/pages/operations/api/[operationId].paths.ts b/docs/pages/operations/api/[operationId].paths.ts
new file mode 100644
index 0000000..6d3ede3
--- /dev/null
+++ b/docs/pages/operations/api/[operationId].paths.ts
@@ -0,0 +1,15 @@
+import { usePaths } from 'vitepress-openapi';
+import { adminSpec } from '../../../.vitepress/specs';
+
+export default {
+ paths() {
+ return usePaths({ spec: adminSpec })
+ .getPathsByVerbs()
+ .map(({ operationId, summary }) => ({
+ params: {
+ operationId,
+ pageTitle: summary,
+ },
+ }));
+ },
+};
diff --git a/docs/pages/operations/durability.md b/docs/pages/operations/durability.md
new file mode 100644
index 0000000..e3528aa
--- /dev/null
+++ b/docs/pages/operations/durability.md
@@ -0,0 +1,30 @@
+# Durability
+
+Stream data lives in object-storage, but metadata (streams, object registry, KV) lives in each node's raft `dataDir`: a periodic local snapshot and a bounded log. Raft replication covers single-node loss. The snapshot archive covers losing the data directories of a quorum.
+
+The raft leader archives every metadata snapshot to the storage bucket under `_streamstack/metadata/{clusterId}/snapshots/`, keeping the last five. Archival is asynchronous and never blocks the snapshot itself.
+
+::: info
+Run production nodes on durable disks (EBS, not instance storage) for `dataDir`, with a stable DNS name per node.
+:::
+
+Failures are logged and reported on `GET /admin/snapshots` and visible on the dashboard. Disable with `metadataArchive: false` in the topo config, `--metadata-archive false` on the CLI, or `METADATA_ARCHIVE=false` in the Docker image.
+
+## Replacing a node
+
+- Disk survived: attach the volume to a replacement machine with the same `nodeId`, DNS name and start it. The node replays its local snapshot, log and rejoins.
+- Disk lost: start the replacement machine with the same `nodeId`, DNS name and an empty `dataDir`. The raft leader streams its latest snapshot to the new peer and replays the log tail. If the address changed, fix membership with `POST /admin/peers` and `DELETE /admin/peers/{peer}`.
+
+## Restoring from archive
+
+If a quorum of data directories is lost, bootstrap from the archive:
+
+- Start node 1 with an empty `dataDir`, a single-peer topo, and `--restore-from-storage true` (or `RESTORE_FROM_STORAGE=true`). The node loads the latest archived snapshot before forming raft and persists it into a local raft snapshot right after election.
+- Verify with `GET /admin/cluster` and `GET /admin/streams/{name}`.
+- Add nodes 2 and 3 with empty data dirs via `POST /admin/peers`. They receive the snapshot from the leader.
+
+Restore only runs on a fresh `dataDir`. If local raft state exists it is skipped, and a log without a snapshot fails with instructions to wipe first.
+
+On graceful shutdown the node flushes the `WAL` tail, commits it to metadata, and archives a final snapshot before raft stops, so acknowledged writes always survive a planned stop followed by disk loss.
+
+For a hard crash where the data directories are also lost, commits since the last archived snapshot (bounded by the `30s` snapshot interval) keep their bytes in the bucket but lose their metadata entries. A crash alone, with disks intact, loses nothing because the local raft log and WAL replay cover the tail.
diff --git a/docs/pages/protocol.md b/docs/pages/protocol.md
new file mode 100644
index 0000000..10676c7
--- /dev/null
+++ b/docs/pages/protocol.md
@@ -0,0 +1,10 @@
+# Protocol
+
+Storage, metadata, and protocol are three decoupled layers. The engine writes to object-storage and replicates metadata with `JRaft`. A protocol facade sits on top and speaks one client protocol.
+
+[Durable Streams](https://github.com/durable-streams/durable-streams) and [S2](https://github.com/s2-streamstore/s2) are the supported facades today. Pick one per deployment. Both talk to the same streams, WAL, and raft group. The HTTP port is `4437` by default.
+
+Specs:
+
+- [Durable Streams](/protocol/durable-streams)
+- [S2](/protocol/s2)
diff --git a/docs/pages/protocol/durable-streams.md b/docs/pages/protocol/durable-streams.md
new file mode 100644
index 0000000..a0c187d
--- /dev/null
+++ b/docs/pages/protocol/durable-streams.md
@@ -0,0 +1,8 @@
+---
+aside: false
+outline: false
+---
+
+# Durable Streams
+
+The [Durable Streams](https://github.com/durable-streams/durable-streams) protocol facade. Default HTTP port is `4437`. Endpoints are in the sidebar.
diff --git a/docs/pages/protocol/durable-streams/[operationId].md b/docs/pages/protocol/durable-streams/[operationId].md
new file mode 100644
index 0000000..1a00b92
--- /dev/null
+++ b/docs/pages/protocol/durable-streams/[operationId].md
@@ -0,0 +1,13 @@
+---
+aside: false
+outline: false
+---
+
+
+
+
diff --git a/docs/pages/protocol/durable-streams/[operationId].paths.ts b/docs/pages/protocol/durable-streams/[operationId].paths.ts
new file mode 100644
index 0000000..6cb3990
--- /dev/null
+++ b/docs/pages/protocol/durable-streams/[operationId].paths.ts
@@ -0,0 +1,15 @@
+import { usePaths } from 'vitepress-openapi';
+import { dsSpec } from '../../../.vitepress/specs';
+
+export default {
+ paths() {
+ return usePaths({ spec: dsSpec })
+ .getPathsByVerbs()
+ .map(({ operationId, summary }) => ({
+ params: {
+ operationId,
+ pageTitle: summary,
+ },
+ }));
+ },
+};
diff --git a/docs/pages/protocol/s2.md b/docs/pages/protocol/s2.md
new file mode 100644
index 0000000..497c207
--- /dev/null
+++ b/docs/pages/protocol/s2.md
@@ -0,0 +1,8 @@
+---
+aside: false
+outline: false
+---
+
+# S2
+
+The [S2](https://github.com/s2-streamstore/s2) protocol facade. Default HTTP port is `4437`. Endpoints are in the sidebar.
diff --git a/docs/pages/protocol/s2/[operationId].md b/docs/pages/protocol/s2/[operationId].md
new file mode 100644
index 0000000..8039ec9
--- /dev/null
+++ b/docs/pages/protocol/s2/[operationId].md
@@ -0,0 +1,13 @@
+---
+aside: false
+outline: false
+---
+
+
+
+
diff --git a/docs/pages/protocol/s2/[operationId].paths.ts b/docs/pages/protocol/s2/[operationId].paths.ts
new file mode 100644
index 0000000..636727f
--- /dev/null
+++ b/docs/pages/protocol/s2/[operationId].paths.ts
@@ -0,0 +1,15 @@
+import { usePaths } from 'vitepress-openapi';
+import { s2Spec } from '../../../.vitepress/specs';
+
+export default {
+ paths() {
+ return usePaths({ spec: s2Spec })
+ .getPathsByVerbs()
+ .map(({ operationId, summary }) => ({
+ params: {
+ operationId,
+ pageTitle: summary,
+ },
+ }));
+ },
+};
diff --git a/metadata/src/main/java/io/streamstack/metadata/raft/MetadataNode.java b/metadata/src/main/java/io/streamstack/metadata/raft/MetadataNode.java
index da60b22..058a473 100644
--- a/metadata/src/main/java/io/streamstack/metadata/raft/MetadataNode.java
+++ b/metadata/src/main/java/io/streamstack/metadata/raft/MetadataNode.java
@@ -364,6 +364,39 @@ public CompletableFuture removePeer(PeerId peer) {
return future;
}
+ public void archiveFinalSnapshot(long timeoutMs) throws InterruptedException {
+ if (Objects.isNull(snapshotArchive) || !node.isLeader()) {
+ return;
+ }
+
+ long target = stateMachine.appliedIndex();
+
+ if (snapshotArchive.lastArchivedIndex() >= target) {
+ return;
+ }
+
+ try {
+ triggerSnapshot();
+ } catch (Exception e) {
+ LOGGER.warn("failed to trigger final metadata snapshot nodeId={}: {}", nodeId, e.getMessage());
+ }
+
+ long deadline = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
+
+ while (System.nanoTime() < deadline) {
+ if (snapshotArchive.lastArchivedIndex() >= target) {
+ LOGGER.info("archived final metadata snapshot nodeId={} appliedIndex={}", nodeId, target);
+ return;
+ }
+
+ Thread.sleep(50);
+ }
+
+ LOGGER.warn(
+ "timed out archiving final metadata snapshot nodeId={} appliedIndex={} lastArchivedIndex={}",
+ nodeId, target, snapshotArchive.lastArchivedIndex());
+ }
+
public void triggerSnapshot() throws InterruptedException {
CompletableFuture future = new CompletableFuture<>();
diff --git a/server/openapi.yml b/server/openapi.yml
new file mode 100644
index 0000000..01370f7
--- /dev/null
+++ b/server/openapi.yml
@@ -0,0 +1,409 @@
+openapi: 3.1.0
+info:
+ title: StreamStack Admin
+ version: "1.0"
+ license:
+ name: Apache 2.0
+ description: Admin plane on a separate port from the protocol facade. Default port is 9090.
+servers:
+ - url: http://127.0.0.1:9090
+tags:
+ - name: Health
+ - name: Cluster
+ - name: Membership
+ - name: Streams
+ - name: Snapshots
+paths:
+ /health:
+ get:
+ operationId: health
+ tags: [Health]
+ summary: Liveness
+ description: Returns as soon as the process is up, before raft and storage are ready.
+ responses:
+ "200":
+ description: Alive
+ content:
+ text/plain:
+ schema:
+ type: string
+ example: ok
+ /ready:
+ get:
+ operationId: ready
+ tags: [Health]
+ summary: Readiness
+ description: Ready once raft has a leader, the node is registered, and storage started.
+ responses:
+ "200":
+ description: Ready
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Readiness"
+ "503":
+ description: Not ready
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Readiness"
+ /admin/cluster:
+ get:
+ operationId: cluster
+ tags: [Cluster]
+ summary: Cluster and raft status
+ responses:
+ "200":
+ description: Cluster status
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Cluster"
+ /admin/nodes:
+ get:
+ operationId: nodes
+ tags: [Cluster]
+ summary: Registered nodes
+ responses:
+ "200":
+ description: Nodes
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Nodes"
+ /admin/streams/{name}:
+ get:
+ operationId: stream
+ tags: [Streams]
+ summary: Stream owner and metadata
+ parameters:
+ - name: name
+ in: path
+ required: true
+ description: Stream path without the leading slash. Nested paths are allowed.
+ schema:
+ type: string
+ example: demo/orders
+ responses:
+ "200":
+ description: Stream
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Stream"
+ "404":
+ $ref: "#/components/responses/Error"
+ /admin/peers:
+ post:
+ operationId: addPeer
+ tags: [Membership]
+ summary: Add a raft peer
+ description: Leader only.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/PeerBody"
+ responses:
+ "200":
+ description: Added
+ content:
+ application/json:
+ schema:
+ type: object
+ required: [added]
+ properties:
+ added:
+ type: string
+ example: 127.0.0.1:8092
+ "400":
+ $ref: "#/components/responses/Error"
+ "409":
+ $ref: "#/components/responses/NotLeader"
+ /admin/peers/{peer}:
+ delete:
+ operationId: removePeer
+ tags: [Membership]
+ summary: Remove a raft peer
+ description: Leader only.
+ parameters:
+ - name: peer
+ in: path
+ required: true
+ description: Raft peer as host:port.
+ schema:
+ type: string
+ example: 127.0.0.1:8092
+ responses:
+ "200":
+ description: Removed
+ content:
+ application/json:
+ schema:
+ type: object
+ required: [removed]
+ properties:
+ removed:
+ type: string
+ "400":
+ $ref: "#/components/responses/Error"
+ "409":
+ $ref: "#/components/responses/NotLeader"
+ /admin/transfer-leader:
+ post:
+ operationId: transferLeader
+ tags: [Membership]
+ summary: Transfer raft leadership
+ description: Leader only.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/PeerBody"
+ responses:
+ "200":
+ description: Transferred
+ content:
+ application/json:
+ schema:
+ type: object
+ required: [transferredTo]
+ properties:
+ transferredTo:
+ type: string
+ "400":
+ $ref: "#/components/responses/Error"
+ "409":
+ $ref: "#/components/responses/NotLeader"
+ "500":
+ $ref: "#/components/responses/Error"
+ /admin/snapshot:
+ post:
+ operationId: triggerSnapshot
+ tags: [Snapshots]
+ summary: Trigger a metadata raft snapshot
+ responses:
+ "200":
+ description: Snapshot triggered
+ content:
+ application/json:
+ schema:
+ type: object
+ required: [appliedIndex]
+ properties:
+ appliedIndex:
+ type: integer
+ format: int64
+ /admin/snapshots:
+ get:
+ operationId: snapshots
+ tags: [Snapshots]
+ summary: Archived metadata snapshots
+ responses:
+ "200":
+ description: Archive status
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SnapshotArchive"
+ "404":
+ $ref: "#/components/responses/Error"
+components:
+ schemas:
+ Readiness:
+ type: object
+ required: [ready, started, leaderKnown, registered]
+ properties:
+ ready:
+ type: boolean
+ started:
+ type: boolean
+ leaderKnown:
+ type: boolean
+ registered:
+ type: boolean
+ Cluster:
+ type: object
+ required:
+ - clusterId
+ - nodeId
+ - nodeEpoch
+ - advertisedAddress
+ - registered
+ - raft
+ - streamCount
+ - objectCount
+ - destroyedObjectBacklog
+ properties:
+ clusterId:
+ type: string
+ nodeId:
+ type: integer
+ nodeEpoch:
+ type: integer
+ format: int64
+ advertisedAddress:
+ type: string
+ registered:
+ type: boolean
+ raft:
+ $ref: "#/components/schemas/Raft"
+ streamCount:
+ type: integer
+ objectCount:
+ type: integer
+ destroyedObjectBacklog:
+ type: integer
+ Raft:
+ type: object
+ required: [isLeader, appliedIndex, applySuccessCount, applyFailCount]
+ properties:
+ leader:
+ type: string
+ nullable: true
+ isLeader:
+ type: boolean
+ appliedIndex:
+ type: integer
+ format: int64
+ applySuccessCount:
+ type: integer
+ format: int64
+ applyFailCount:
+ type: integer
+ format: int64
+ peers:
+ type: array
+ nullable: true
+ items:
+ type: string
+ Nodes:
+ type: object
+ required: [nodes]
+ properties:
+ nodes:
+ type: array
+ items:
+ $ref: "#/components/schemas/Node"
+ Node:
+ type: object
+ required: [nodeId, nodeEpoch, local]
+ properties:
+ nodeId:
+ type: integer
+ nodeEpoch:
+ type: integer
+ format: int64
+ advertisedAddress:
+ type: string
+ nullable: true
+ local:
+ type: boolean
+ Stream:
+ type: object
+ required: [name, ownerLocal]
+ properties:
+ name:
+ type: string
+ streamId:
+ type: integer
+ format: int64
+ nullable: true
+ ownerLocal:
+ type: boolean
+ ownerNodeId:
+ type: integer
+ ownerAdvertisedAddress:
+ type: string
+ meta:
+ $ref: "#/components/schemas/StreamMeta"
+ StreamMeta:
+ type: object
+ properties:
+ streamId:
+ type: integer
+ format: int64
+ contentType:
+ type: string
+ ttlSeconds:
+ type: integer
+ nullable: true
+ expiresAt:
+ type: string
+ nullable: true
+ startOffset:
+ type: string
+ nextOffset:
+ type: string
+ closed:
+ type: boolean
+ PeerBody:
+ type: object
+ required: [peer]
+ properties:
+ peer:
+ type: string
+ example: 127.0.0.1:8092
+ SnapshotArchive:
+ type: object
+ required: [archiveSuccessCount, archiveFailureCount, lastArchivedIndex, snapshots]
+ properties:
+ archiveSuccessCount:
+ type: integer
+ format: int64
+ archiveFailureCount:
+ type: integer
+ format: int64
+ lastArchivedIndex:
+ type: integer
+ format: int64
+ snapshots:
+ type: array
+ items:
+ $ref: "#/components/schemas/ArchivedSnapshot"
+ ArchivedSnapshot:
+ type: object
+ required: [key, appliedIndex, timestampMs, size]
+ properties:
+ key:
+ type: string
+ appliedIndex:
+ type: integer
+ format: int64
+ timestampMs:
+ type: integer
+ format: int64
+ size:
+ type: integer
+ format: int64
+ Error:
+ type: object
+ required: [error]
+ properties:
+ error:
+ type: string
+ NotLeader:
+ type: object
+ required: [error]
+ properties:
+ error:
+ type: string
+ example: not raft leader
+ leader:
+ type: string
+ nullable: true
+ responses:
+ Error:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Error"
+ NotLeader:
+ description: Not raft leader
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotLeader"
diff --git a/server/src/main/java/io/streamstack/server/StreamStackNode.java b/server/src/main/java/io/streamstack/server/StreamStackNode.java
index 233f5f2..336807c 100644
--- a/server/src/main/java/io/streamstack/server/StreamStackNode.java
+++ b/server/src/main/java/io/streamstack/server/StreamStackNode.java
@@ -48,6 +48,7 @@ public final class StreamStackNode implements AutoCloseable {
private static final int STORAGE_READINESS_MAX_ATTEMPTS = 10;
private static final long STORAGE_READINESS_INITIAL_BACKOFF_MS = 1_000;
private static final long STORAGE_READINESS_MAX_BACKOFF_MS = 30_000;
+ private static final long FINAL_SNAPSHOT_ARCHIVE_TIMEOUT_MS = 15_000;
private final ServerConfig config;
private final SnapshotArchive snapshotArchive;
@@ -305,7 +306,19 @@ public void drainBeforeShutdown() {
@Override
public void close() {
ready.set(false);
+ closeStreamingLayer();
+ archiveFinalSnapshot();
+ closeObjectStorages();
+ closeMetadata();
+ if (Objects.nonNull(adminServer)) {
+ adminServer.close();
+ }
+
+ started.set(false);
+ }
+
+ private void closeStreamingLayer() {
try {
for (var stream : new ArrayList<>(streamService.openStreamSnapshot())) {
try {
@@ -332,7 +345,17 @@ public void close() {
storage.shutdown();
} catch (Exception ignored) {
}
+ }
+ private void archiveFinalSnapshot() {
+ try {
+ metadataNode.archiveFinalSnapshot(FINAL_SNAPSHOT_ARCHIVE_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private void closeObjectStorages() {
if (Objects.nonNull(walObjectStorage)) {
try {
walObjectStorage.close();
@@ -344,18 +367,14 @@ public void close() {
objectStorage.close();
} catch (Exception ignored) {
}
+ }
+ private void closeMetadata() {
metadataNode.close();
if (Objects.nonNull(snapshotArchive)) {
snapshotArchive.close();
}
-
- if (Objects.nonNull(adminServer)) {
- adminServer.close();
- }
-
- started.set(false);
}
private record WalBundle(WriteAheadLog wal, ObjectStorage objectStorage) {
diff --git a/server/src/test/java/io/streamstack/server/MetadataArchiveRestoreIntegrationTest.java b/server/src/test/java/io/streamstack/server/MetadataArchiveRestoreIntegrationTest.java
index 2e83953..ad2b48c 100644
--- a/server/src/test/java/io/streamstack/server/MetadataArchiveRestoreIntegrationTest.java
+++ b/server/src/test/java/io/streamstack/server/MetadataArchiveRestoreIntegrationTest.java
@@ -79,6 +79,44 @@ void archivesSnapshotsAndRestoresMetadataFromStorage() throws Exception {
}
}
+ @Test
+ void acknowledgedTailSurvivesGracefulShutdownAndRestore() throws Exception {
+ Path dataDir = tempDir.resolve("data");
+ Path objectDir = tempDir.resolve("objects");
+
+ try (StreamStackNode node = new StreamStackNode(
+ config(dataDir, objectDir, 1, false, freePort(), 104857600L))) {
+ node.start();
+ StreamService services = node.service();
+
+ assertTrue(services.lifecycle().create(new CreateCommand(
+ "/streams/tail", "text/plain", null, null, false, new byte[0])).created());
+ assertTrue(services.append().append(new AppendCommand(
+ "/streams/tail",
+ List.of("acked-tail".getBytes(StandardCharsets.UTF_8)),
+ "text/plain",
+ null,
+ null,
+ false)).applied());
+ }
+
+ deleteRecursively(dataDir);
+
+ try (StreamStackNode restored = new StreamStackNode(
+ config(dataDir, objectDir, 2, true, freePort(), 104857600L))) {
+ restored.start();
+ assertTrue(restored.metadataNode().restoredFromArchive());
+ StreamService services = restored.service();
+ StreamMeta head = services.lifecycle().head("/streams/tail").orElseThrow();
+
+ assertEquals(1, head.nextOffset().recordOffset());
+ ReadResult batch = services.read().read("/streams/tail", OffsetToken.beginning(), 1024, 0);
+
+ assertEquals(1, batch.records().size());
+ assertEquals("acked-tail", new String(batch.records().get(0).payload(), StandardCharsets.UTF_8));
+ }
+ }
+
@Test
void restoreSkippedWhenLocalSnapshotExists() throws Exception {
Path dataDir = tempDir.resolve("data");
@@ -108,6 +146,11 @@ void restoreFailsWithoutArchivedSnapshot() {
private ServerConfig config(Path dataDir, Path objectDir, long nodeEpoch, boolean restore, int raftPort)
throws Exception {
+ return config(dataDir, objectDir, nodeEpoch, restore, raftPort, 1L);
+ }
+
+ private ServerConfig config(Path dataDir, Path objectDir, long nodeEpoch, boolean restore, int raftPort,
+ long walUploadThreshold) throws Exception {
ServerConfig.Builder builder = ServerConfig.builder()
.nodeId(1)
.nodeEpoch(nodeEpoch)
@@ -122,7 +165,7 @@ private ServerConfig config(Path dataDir, Path objectDir, long nodeEpoch, boolea
.routingMode(RoutingMode.LOCAL_ALWAYS)
.restoreFromStorage(restore);
- builder.streamConfig().walUploadThreshold(1L);
+ builder.streamConfig().walUploadThreshold(walUploadThreshold);
return builder.build();
}