diff --git a/.vitepress/config.mts b/.vitepress/config.mts deleted file mode 100644 index 3aa45736..00000000 --- a/.vitepress/config.mts +++ /dev/null @@ -1,139 +0,0 @@ -import { transformerTwoslash } from '@shikijs/vitepress-twoslash'; -import tailwindcss from '@tailwindcss/vite'; -import { defineConfig, loadEnv } from 'vitepress'; -import { fileURLToPath, URL } from 'node:url'; -import { getSidebar } from './sidebar'; -import { - groupIconMdPlugin, - groupIconVitePlugin, -} from 'vitepress-plugin-group-icons'; - -// Charger les variables d'environnement -const env = loadEnv('', process.cwd()); - -// https://vitepress.dev/reference/site-config -export default defineConfig({ - title: 'iExec documentation', - description: - 'Build decentralized applications that combine ownership, privacy, and monetization.', - cleanUrls: true, - lastUpdated: true, - vite: { - plugins: [tailwindcss(), groupIconVitePlugin()], - resolve: { - alias: { - '@': fileURLToPath(new URL('../src', import.meta.url)), - }, - }, - // Expose environment variables to the client - define: { - 'import.meta.env.VITE_REOWN_PROJECT_ID': JSON.stringify( - env.VITE_REOWN_PROJECT_ID - ), - }, - }, - srcDir: './src', - markdown: { - codeTransformers: [transformerTwoslash()], - config(md) { - md.use(groupIconMdPlugin); - }, - }, - - head: [ - ['link', { rel: 'icon', href: '/Logo-RLC-Yellow.png' }], - [ - 'link', - { - rel: 'stylesheet', - href: 'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap', - }, - ], - [ - 'script', - {}, - ` - window.axeptioSettings = { - clientId: "6413111857e4d2a6342cd5c6", - cookiesVersion: "iexec-en", - }; - - (function(d, s) { - var t = d.getElementsByTagName(s)[0], e = d.createElement(s); - e.async = true; e.src = "//static.axept.io/sdk.js"; - t.parentNode.insertBefore(e, t); - })(document, "script"); - `, - ], - // Mava widget - [ - 'script', - { - defer: '', - src: 'https://widget.mava.app', - 'widget-version': 'v2', - id: 'MavaWebChat', - 'enable-sdk': 'false', - 'data-token': - '8e4e10aad5750451e8726768e8c639dae54f461beeb176f5ebd687371c9390f2', - }, - ], - // Hotjar Tracking Script - [ - 'script', - {}, - ` - (function(h,o,t,j,a,r){ - h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; - h._hjSettings={hjid:5303222,hjsv:6}; - a=o.getElementsByTagName('head')[0]; - r=o.createElement('script');r.async=1; - r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; - a.appendChild(r); - })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); - `, - ], - ], - - themeConfig: { - // https://vitepress.dev/reference/default-theme-config - nav: [ - { text: 'Get Started', link: '/get-started/welcome' }, - { text: 'Guides', link: '/guides/build-iapp/' }, - { text: 'References', link: '/references/dataProtector' }, - { - component: 'ChainSelector', - props: { - className: 'w-48', - }, - }, - ], - outline: { - level: [2, 4], - }, - - sidebar: getSidebar(), - - search: { - provider: 'local', - }, - - socialLinks: [ - { icon: 'github', link: 'https://github.com/iExecBlockchainComputing' }, - { icon: 'x', link: 'https://twitter.com/iEx_ec' }, - { icon: 'discord', link: 'https://discord.com/invite/pbt9m98wnU' }, - ], - - editLink: { - pattern: - 'https://github.com/iExecBlockchainComputing/documentation/blob/main/:path', - text: 'Suggest changes to this page', - }, - - logo: { - light: '/Logo-RLC-Yellow.png', - dark: '/Logo-RLC-Yellow.png', - alt: 'iExec logo', - }, - }, -}); diff --git a/.vitepress/config.ts b/.vitepress/config.ts new file mode 100644 index 00000000..a6e94155 --- /dev/null +++ b/.vitepress/config.ts @@ -0,0 +1,142 @@ +import { transformerTwoslash } from '@shikijs/vitepress-twoslash'; +import tailwindcss from '@tailwindcss/vite'; +import { defineConfig, loadEnv } from 'vitepress'; +import { fileURLToPath, URL } from 'node:url'; +import { getSidebar } from './sidebar'; +import { + groupIconMdPlugin, + groupIconVitePlugin, +} from 'vitepress-plugin-group-icons'; +import { withMermaid } from 'vitepress-plugin-mermaid'; + +// Charger les variables d'environnement +const env = loadEnv('', process.cwd()); + +// https://vitepress.dev/reference/site-config +export default withMermaid( + defineConfig({ + title: 'iExec documentation', + description: + 'Build decentralized applications that combine ownership, privacy, and monetization.', + cleanUrls: true, + lastUpdated: true, + vite: { + plugins: [tailwindcss(), groupIconVitePlugin()], + resolve: { + alias: { + '@': fileURLToPath(new URL('../src', import.meta.url)), + }, + }, + // Expose environment variables to the client + define: { + 'import.meta.env.VITE_REOWN_PROJECT_ID': JSON.stringify( + env.VITE_REOWN_PROJECT_ID + ), + }, + }, + srcDir: './src', + markdown: { + codeTransformers: [transformerTwoslash()], + config(md) { + md.use(groupIconMdPlugin); + }, + }, + + head: [ + ['link', { rel: 'icon', href: '/Logo-RLC-Yellow.png' }], + [ + 'link', + { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap', + }, + ], + [ + 'script', + {}, + ` + window.axeptioSettings = { + clientId: "6413111857e4d2a6342cd5c6", + cookiesVersion: "iexec-en", + }; + + (function(d, s) { + var t = d.getElementsByTagName(s)[0], e = d.createElement(s); + e.async = true; e.src = "//static.axept.io/sdk.js"; + t.parentNode.insertBefore(e, t); + })(document, "script"); + `, + ], + // Mava widget + [ + 'script', + { + defer: '', + src: 'https://widget.mava.app', + 'widget-version': 'v2', + id: 'MavaWebChat', + 'enable-sdk': 'false', + 'data-token': + '8e4e10aad5750451e8726768e8c639dae54f461beeb176f5ebd687371c9390f2', + }, + ], + // Hotjar Tracking Script + [ + 'script', + {}, + ` + (function(h,o,t,j,a,r){ + h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; + h._hjSettings={hjid:5303222,hjsv:6}; + a=o.getElementsByTagName('head')[0]; + r=o.createElement('script');r.async=1; + r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; + a.appendChild(r); + })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); + `, + ], + ], + + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Get Started', link: '/get-started/welcome' }, + { text: 'Guides', link: '/guides/build-iapp/' }, + { text: 'References', link: '/references/dataProtector' }, + { + component: 'ChainSelector', + props: { + className: 'w-48', + }, + }, + ], + outline: { + level: [2, 4], + }, + + sidebar: getSidebar(), + + search: { + provider: 'local', + }, + + socialLinks: [ + { icon: 'github', link: 'https://github.com/iExecBlockchainComputing' }, + { icon: 'x', link: 'https://twitter.com/iEx_ec' }, + { icon: 'discord', link: 'https://discord.com/invite/pbt9m98wnU' }, + ], + + editLink: { + pattern: + 'https://github.com/iExecBlockchainComputing/documentation/blob/main/:path', + text: 'Suggest changes to this page', + }, + + logo: { + light: '/Logo-RLC-Yellow.png', + dark: '/Logo-RLC-Yellow.png', + alt: 'iExec logo', + }, + }, + }) +); diff --git a/.vitepress/sidebar.ts b/.vitepress/sidebar.ts index e77aac5f..5df5d996 100644 --- a/.vitepress/sidebar.ts +++ b/.vitepress/sidebar.ts @@ -127,6 +127,16 @@ export function getSidebar() { }, ], }, + { + text: 'TEE Technology', + collapsed: true, + items: [ + { + text: 'Intel SGX Technology Overview', + link: '/get-started/protocol/tee/intel-sgx-technology', + }, + ], + }, ], }, ], @@ -175,6 +185,44 @@ export function getSidebar() { text: 'Debugging', link: '/guides/build-iapp/debugging', }, + { + text: 'Advanced', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/guides/build-iapp/advanced/overview', + }, + { + text: 'Quick Start for Developers', + link: '/guides/build-iapp/advanced/quick-start-for-developers', + }, + { + text: 'Build your first application', + link: '/guides/build-iapp/advanced/your-first-app', + }, + { + text: 'Build your first SGX app (SCONE)', + link: '/guides/build-iapp/advanced/create-your-first-sgx-app', + }, + { + text: 'End-to-end Encryption', + link: '/guides/build-iapp/advanced/end-to-end-encryption', + }, + { + text: 'SGX Encrypted Dataset', + link: '/guides/build-iapp/advanced/sgx-encrypted-dataset', + }, + { + text: 'Access Confidential Assets', + link: '/guides/build-iapp/advanced/access-confidential-assets', + }, + { + text: 'Build Intel TDX app', + link: '/guides/build-iapp/advanced/create-your-first-tdx-app', + }, + ], + }, ], }, { @@ -562,5 +610,5 @@ export function getSidebar() { link: '/references/glossary', }, ], - } satisfies DefaultTheme.Sidebar; + } as DefaultTheme.Sidebar; } diff --git a/README.md b/README.md index cedd359a..8be4a0fb 100644 --- a/README.md +++ b/README.md @@ -192,3 +192,4 @@ for input parameters: - migrate github SDK doc here - migrate pay-per-task page into a guide - check pages (introduction & getting-started) for use-iapp guide +- Rework Advanced iApp building guides. (from "old" protocol doc) diff --git a/package-lock.json b/package-lock.json index 22226739..ab28cdd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,11 +29,12 @@ "viem": "^2.33.1", "vitepress-plugin-google-analytics": "^1.0.2", "vitepress-plugin-group-icons": "^1.6.1", + "vitepress-plugin-mermaid": "^2.0.17", "vue": "^3.5.17" }, "devDependencies": { "@iconify/vue": "^5.0.0", - "@shikijs/vitepress-twoslash": "^3.8.0", + "@shikijs/vitepress-twoslash": "^3.9.2", "@types/figlet": "^1.7.0", "@types/prop-types": "^15.7.15", "@types/react": "^18.3.23", @@ -48,7 +49,6 @@ }, "node_modules/@algolia/autocomplete-core": { "version": "1.17.7", - "dev": true, "license": "MIT", "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", @@ -57,7 +57,6 @@ }, "node_modules/@algolia/autocomplete-plugin-algolia-insights": { "version": "1.17.7", - "dev": true, "license": "MIT", "dependencies": { "@algolia/autocomplete-shared": "1.17.7" @@ -68,7 +67,6 @@ }, "node_modules/@algolia/autocomplete-preset-algolia": { "version": "1.17.7", - "dev": true, "license": "MIT", "dependencies": { "@algolia/autocomplete-shared": "1.17.7" @@ -80,7 +78,6 @@ }, "node_modules/@algolia/autocomplete-shared": { "version": "1.17.7", - "dev": true, "license": "MIT", "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -89,7 +86,6 @@ }, "node_modules/@algolia/client-abtesting": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -103,7 +99,6 @@ }, "node_modules/@algolia/client-analytics": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -117,7 +112,6 @@ }, "node_modules/@algolia/client-common": { "version": "5.33.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 14.0.0" @@ -125,7 +119,6 @@ }, "node_modules/@algolia/client-insights": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -139,7 +132,6 @@ }, "node_modules/@algolia/client-personalization": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -153,7 +145,6 @@ }, "node_modules/@algolia/client-query-suggestions": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -167,7 +158,6 @@ }, "node_modules/@algolia/client-search": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -181,7 +171,6 @@ }, "node_modules/@algolia/ingestion": { "version": "1.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -195,7 +184,6 @@ }, "node_modules/@algolia/monitoring": { "version": "1.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -209,7 +197,6 @@ }, "node_modules/@algolia/recommend": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0", @@ -223,7 +210,6 @@ }, "node_modules/@algolia/requester-browser-xhr": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0" @@ -234,7 +220,6 @@ }, "node_modules/@algolia/requester-fetch": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0" @@ -245,7 +230,6 @@ }, "node_modules/@algolia/requester-node-http": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-common": "5.33.0" @@ -285,6 +269,8 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -292,6 +278,8 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -299,6 +287,8 @@ }, "node_modules/@babel/parser": { "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "license": "MIT", "dependencies": { "@babel/types": "^7.28.0" @@ -318,7 +308,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.1", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -408,6 +400,13 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", + "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", + "license": "MIT", + "peer": true + }, "node_modules/@chainsafe/is-ip": { "version": "2.1.0", "license": "MIT" @@ -419,6 +418,50 @@ "@chainsafe/is-ip": "^2.0.1" } }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/@coinbase/wallet-sdk": { "version": "4.3.6", "license": "Apache-2.0", @@ -460,12 +503,10 @@ }, "node_modules/@docsearch/css": { "version": "3.8.2", - "dev": true, "license": "MIT" }, "node_modules/@docsearch/js": { "version": "3.8.2", - "dev": true, "license": "MIT", "dependencies": { "@docsearch/react": "3.8.2", @@ -474,7 +515,6 @@ }, "node_modules/@docsearch/react": { "version": "3.8.2", - "dev": true, "license": "MIT", "dependencies": { "@algolia/autocomplete-core": "1.17.7", @@ -716,7 +756,6 @@ }, "node_modules/@iconify-json/simple-icons": { "version": "1.2.43", - "dev": true, "license": "CC0-1.0", "dependencies": { "@iconify/types": "*" @@ -1207,25 +1246,6 @@ "npm": ">=7.0.0" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "license": "ISC", @@ -1318,6 +1338,39 @@ "@lit-labs/ssr-dom-shim": "^1.4.0" } }, + "node_modules/@mermaid-js/mermaid-mindmap": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-mindmap/-/mermaid-mindmap-9.3.0.tgz", + "integrity": "sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@braintree/sanitize-url": "^6.0.0", + "cytoscape": "^3.23.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.1.0", + "d3": "^7.0.0", + "khroma": "^2.0.0", + "non-layered-tidy-tree-layout": "^2.0.2" + } + }, + "node_modules/@mermaid-js/mermaid-mindmap/node_modules/@braintree/sanitize-url": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", + "license": "MIT", + "optional": true + }, + "node_modules/@mermaid-js/parser": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.2.tgz", + "integrity": "sha512-+PO02uGF6L6Cs0Bw8RpGhikVvMWEysfAyl27qTlroUB8jSWr1lL0Sf6zi78ZxlSnmgSY2AMMKVgghnN9jTtwkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "langium": "3.3.1" + } + }, "node_modules/@metamask/eth-json-rpc-provider": { "version": "1.0.1", "dependencies": { @@ -2187,43 +2240,94 @@ } }, "node_modules/@shikijs/engine-javascript": { - "version": "3.8.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.9.2.tgz", + "integrity": "sha512-kUTRVKPsB/28H5Ko6qEsyudBiWEDLst+Sfi+hwr59E0GLHV0h8RfgbQU7fdN5Lt9A8R1ulRiZyTvAizkROjwDA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.0", + "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, + "node_modules/@shikijs/engine-javascript/node_modules/@shikijs/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz", + "integrity": "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.8.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.9.2.tgz", + "integrity": "sha512-Vn/w5oyQ6TUgTVDIC/BrpXwIlfK6V6kGWDVVz2eRkF2v13YoENUvaNwxMsQU/t6oCuZKzqp9vqtEtEzKl9VegA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.0", + "@shikijs/types": "3.9.2", "@shikijs/vscode-textmate": "^10.0.2" } }, + "node_modules/@shikijs/engine-oniguruma/node_modules/@shikijs/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz", + "integrity": "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/@shikijs/langs": { - "version": "3.8.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.9.2.tgz", + "integrity": "sha512-X1Q6wRRQXY7HqAuX3I8WjMscjeGjqXCg/Sve7J2GWFORXkSrXud23UECqTBIdCSNKJioFtmUGJQNKtlMMZMn0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.9.2" + } + }, + "node_modules/@shikijs/langs/node_modules/@shikijs/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz", + "integrity": "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.0" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, "node_modules/@shikijs/themes": { - "version": "3.8.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.9.2.tgz", + "integrity": "sha512-6z5lBPBMRfLyyEsgf6uJDHPa6NAGVzFJqH4EAZ+03+7sedYir2yJBRu2uPZOKmj43GyhVHWHvyduLDAwJQfDjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.9.2" + } + }, + "node_modules/@shikijs/themes/node_modules/@shikijs/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz", + "integrity": "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.8.0" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, "node_modules/@shikijs/transformers": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/core": "2.5.0", @@ -2232,7 +2336,6 @@ }, "node_modules/@shikijs/transformers/node_modules/@shikijs/core": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/engine-javascript": "2.5.0", @@ -2245,7 +2348,6 @@ }, "node_modules/@shikijs/transformers/node_modules/@shikijs/engine-javascript": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/types": "2.5.0", @@ -2255,7 +2357,6 @@ }, "node_modules/@shikijs/transformers/node_modules/@shikijs/engine-oniguruma": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/types": "2.5.0", @@ -2264,7 +2365,6 @@ }, "node_modules/@shikijs/transformers/node_modules/@shikijs/types": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -2273,7 +2373,6 @@ }, "node_modules/@shikijs/transformers/node_modules/oniguruma-to-es": { "version": "3.1.1", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex-xs": "^1.0.0", @@ -2304,7 +2403,9 @@ } }, "node_modules/@shikijs/vitepress-twoslash": { - "version": "3.8.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/vitepress-twoslash/-/vitepress-twoslash-3.9.2.tgz", + "integrity": "sha512-s1pQyHr6QJG37MMPVZeGBfNjb359e/ndKhqh5b5OTfLO+a3BHe9qKAc6YZCBLhx/2aclYcbrNSUpm0RqLP6EkA==", "dev": true, "license": "MIT", "dependencies": { @@ -2313,15 +2414,14 @@ "mdast-util-from-markdown": "^2.0.2", "mdast-util-gfm": "^3.1.0", "mdast-util-to-hast": "^13.2.0", - "shiki": "3.8.0", - "twoslash": "^0.3.2", - "twoslash-vue": "^0.3.2", - "vue": "^3.5.17" + "shiki": "3.9.2", + "twoslash": "^0.3.3", + "twoslash-vue": "^0.3.3", + "vue": "^3.5.18" } }, "node_modules/@shikijs/vscode-textmate": { "version": "10.0.2", - "dev": true, "license": "MIT" }, "node_modules/@socket.io/component-emitter": { @@ -2729,127 +2829,411 @@ "@types/node": "*" } }, - "node_modules/@types/debug": { - "version": "4.1.12", + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", "license": "MIT", + "peer": true, "dependencies": { - "@types/ms": "*" + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-selection": "*" } }, - "node_modules/@types/dns-packet": { - "version": "5.6.5", + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", "license": "MIT", + "peer": true, "dependencies": { - "@types/node": "*" + "@types/d3-selection": "*" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "license": "MIT" + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT", + "peer": true }, - "node_modules/@types/figlet": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@types/figlet/-/figlet-1.7.0.tgz", - "integrity": "sha512-KwrT7p/8Eo3Op/HBSIwGXOsTZKYiM9NpWRBJ5sVjWP/SmlS+oxxRvJht/FNAtliJvja44N3ul1yATgohnVBV0Q==", - "dev": true, - "license": "MIT" + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT", + "peer": true }, - "node_modules/@types/hast": { - "version": "3.0.4", - "dev": true, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", "license": "MIT", + "peer": true, "dependencies": { - "@types/unist": "*" + "@types/d3-array": "*", + "@types/geojson": "*" } }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "dev": true, - "license": "MIT" + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT", + "peer": true }, - "node_modules/@types/markdown-it": { - "version": "14.1.2", - "dev": true, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "peer": true, "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" + "@types/d3-selection": "*" } }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "dev": true, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", "license": "MIT", + "peer": true, "dependencies": { - "@types/unist": "*" + "@types/d3-dsv": "*" } }, - "node_modules/@types/mdurl": { - "version": "2.0.0", - "dev": true, - "license": "MIT" + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT", + "peer": true }, - "node_modules/@types/ms": { - "version": "2.1.0", - "license": "MIT" + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT", + "peer": true }, - "node_modules/@types/node": { - "version": "24.1.0", + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "license": "MIT", + "peer": true, "dependencies": { - "undici-types": "~7.8.0" + "@types/geojson": "*" } }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, - "license": "MIT" + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT", + "peer": true }, - "node_modules/@types/react": { - "version": "18.3.23", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", - "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", - "devOptional": true, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "license": "MIT", + "peer": true, "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" + "@types/d3-color": "*" } }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "license": "MIT" + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT", + "peer": true }, - "node_modules/@types/unist": { - "version": "3.0.3", - "dev": true, - "license": "MIT" + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT", + "peer": true }, - "node_modules/@types/web-bluetooth": { - "version": "0.0.21", - "license": "MIT" + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT", + "peer": true }, - "node_modules/@typescript/vfs": { - "version": "1.6.1", - "dev": true, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "license": "MIT", + "peer": true, "dependencies": { - "debug": "^4.1.1" - }, - "peerDependencies": { - "typescript": "*" + "@types/d3-time": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "dev": true, - "license": "ISC" + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/dns-packet": { + "version": "5.6.5", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/@types/figlet": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@types/figlet/-/figlet-1.7.0.tgz", + "integrity": "sha512-KwrT7p/8Eo3Op/HBSIwGXOsTZKYiM9NpWRBJ5sVjWP/SmlS+oxxRvJht/FNAtliJvja44N3ul1yATgohnVBV0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.1.0", + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "license": "MIT" + }, + "node_modules/@typescript/vfs": { + "version": "1.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "license": "ISC" }, "node_modules/@uniswap/lib": { "version": "1.1.1", @@ -2878,7 +3262,6 @@ }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", - "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -2889,46 +3272,56 @@ } }, "node_modules/@volar/language-core": { - "version": "2.4.17", + "version": "2.4.22", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.22.tgz", + "integrity": "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg==", "dev": true, "license": "MIT", "dependencies": { - "@volar/source-map": "2.4.17" + "@volar/source-map": "2.4.22" } }, "node_modules/@volar/source-map": { - "version": "2.4.17", + "version": "2.4.22", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.22.tgz", + "integrity": "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA==", "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-core": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.18.tgz", + "integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@vue/shared": "3.5.17", + "@babel/parser": "^7.28.0", + "@vue/shared": "3.5.18", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz", + "integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.17", - "@vue/shared": "3.5.17" + "@vue/compiler-core": "3.5.18", + "@vue/shared": "3.5.18" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz", + "integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@vue/compiler-core": "3.5.17", - "@vue/compiler-dom": "3.5.17", - "@vue/compiler-ssr": "3.5.17", - "@vue/shared": "3.5.17", + "@babel/parser": "^7.28.0", + "@vue/compiler-core": "3.5.18", + "@vue/compiler-dom": "3.5.18", + "@vue/compiler-ssr": "3.5.18", + "@vue/shared": "3.5.18", "estree-walker": "^2.0.2", "magic-string": "^0.30.17", "postcss": "^8.5.6", @@ -2936,15 +3329,19 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz", + "integrity": "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.17", - "@vue/shared": "3.5.17" + "@vue/compiler-dom": "3.5.18", + "@vue/shared": "3.5.18" } }, "node_modules/@vue/compiler-vue2": { "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", "dev": true, "license": "MIT", "dependencies": { @@ -2980,18 +3377,20 @@ } }, "node_modules/@vue/language-core": { - "version": "3.0.1", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.0.5.tgz", + "integrity": "sha512-gCEjn9Ik7I/seHVNIEipOm8W+f3/kg60e8s1IgIkMYma2wu9ZGUTMv3mSL2bX+Md2L8fslceJ4SU8j1fgSRoiw==", "dev": true, "license": "MIT", "dependencies": { - "@volar/language-core": "2.4.17", + "@volar/language-core": "2.4.22", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^2.0.5", - "minimatch": "^10.0.1", "muggle-string": "^0.4.1", - "path-browserify": "^1.0.1" + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" @@ -3002,44 +3401,67 @@ } } }, + "node_modules/@vue/language-core/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@vue/reactivity": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.18.tgz", + "integrity": "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.17" + "@vue/shared": "3.5.18" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.18.tgz", + "integrity": "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.17", - "@vue/shared": "3.5.17" + "@vue/reactivity": "3.5.18", + "@vue/shared": "3.5.18" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz", + "integrity": "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.17", - "@vue/runtime-core": "3.5.17", - "@vue/shared": "3.5.17", + "@vue/reactivity": "3.5.18", + "@vue/runtime-core": "3.5.18", + "@vue/shared": "3.5.18", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.18.tgz", + "integrity": "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.17", - "@vue/shared": "3.5.17" + "@vue/compiler-ssr": "3.5.18", + "@vue/shared": "3.5.18" }, "peerDependencies": { - "vue": "3.5.17" + "vue": "3.5.18" } }, "node_modules/@vue/shared": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -3069,7 +3491,6 @@ }, "node_modules/@vueuse/integrations": { "version": "12.8.2", - "dev": true, "license": "MIT", "dependencies": { "@vueuse/core": "12.8.2", @@ -3134,7 +3555,6 @@ }, "node_modules/@vueuse/integrations/node_modules/@vueuse/core": { "version": "12.8.2", - "dev": true, "license": "MIT", "dependencies": { "@types/web-bluetooth": "^0.0.21", @@ -3148,7 +3568,6 @@ }, "node_modules/@vueuse/integrations/node_modules/@vueuse/metadata": { "version": "12.8.2", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" @@ -5492,7 +5911,6 @@ }, "node_modules/algoliasearch": { "version": "5.33.0", - "dev": true, "license": "MIT", "dependencies": { "@algolia/client-abtesting": "5.33.0", @@ -5514,7 +5932,9 @@ } }, "node_modules/alien-signals": { - "version": "2.0.5", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-2.0.6.tgz", + "integrity": "sha512-P3TxJSe31bUHBiblg59oU1PpaWPtmxF9GhJ/cB7OkgJ0qN/ifFSKUI25/v8ZhsT+lIG6ac8DpTOplXxORX6F3Q==", "dev": true, "license": "MIT" }, @@ -6014,7 +6434,6 @@ }, "node_modules/ccount": { "version": "2.0.1", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6042,7 +6461,6 @@ }, "node_modules/character-entities-html4": { "version": "2.1.0", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6051,7 +6469,6 @@ }, "node_modules/character-entities-legacy": { "version": "3.0.0", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6062,6 +6479,34 @@ "version": "0.7.0", "license": "MIT" }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, "node_modules/chokidar": { "version": "4.0.3", "license": "MIT", @@ -6215,7 +6660,6 @@ }, "node_modules/comma-separated-tokens": { "version": "2.0.3", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -6348,6 +6792,15 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/crc-32": { "version": "1.2.2", "license": "Apache-2.0", @@ -6383,23 +6836,538 @@ "sha.js": "^2.4.8" } }, - "node_modules/cross-fetch": { - "version": "3.2.0", - "license": "MIT", + "node_modules/cross-fetch": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/crossws": { + "version": "0.3.5", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC", + "peer": true + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "node-fetch": "^2.7.0" + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/crossws": { - "version": "0.3.5", - "license": "MIT", + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { - "uncrypto": "^0.1.3" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/csstype": { - "version": "3.1.3", - "license": "MIT" + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } }, "node_modules/dag-jose": { "version": "5.1.1", @@ -6413,12 +7381,25 @@ "version": "13.1.3", "license": "Apache-2.0 OR MIT" }, + "node_modules/dagre-d3-es": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz", + "integrity": "sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==", + "license": "MIT", + "peer": true, + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, "node_modules/dayjs": { "version": "1.11.13", "license": "MIT" }, "node_modules/de-indent": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true, "license": "MIT" }, @@ -6489,9 +7470,17 @@ "version": "6.1.4", "license": "MIT" }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/dequal": { "version": "2.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6521,7 +7510,6 @@ }, "node_modules/devlop": { "version": "1.1.0", - "dev": true, "license": "MIT", "dependencies": { "dequal": "^2.0.0" @@ -6545,6 +7533,16 @@ "node": ">=6" } }, + "node_modules/dompurify": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", + "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/drbg.js": { "version": "1.0.1", "license": "MIT", @@ -6688,7 +7686,6 @@ }, "node_modules/emoji-regex-xs": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/encode-utf8": { @@ -7202,6 +8199,8 @@ }, "node_modules/estree-walker": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, "node_modules/eth-block-tracker": { @@ -7558,7 +8557,6 @@ }, "node_modules/focus-trap": { "version": "7.6.5", - "dev": true, "license": "MIT", "dependencies": { "tabbable": "^6.2.0" @@ -7761,6 +8759,13 @@ "uncrypto": "^0.1.3" } }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT", + "peer": true + }, "node_modules/has-flag": { "version": "3.0.0", "license": "MIT", @@ -7875,7 +8880,6 @@ }, "node_modules/hast-util-to-html": { "version": "9.0.5", - "dev": true, "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -7897,7 +8901,6 @@ }, "node_modules/hast-util-whitespace": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -7909,6 +8912,8 @@ }, "node_modules/he": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", "bin": { @@ -7931,7 +8936,6 @@ }, "node_modules/html-void-elements": { "version": "3.0.0", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -8099,6 +9103,15 @@ "version": "6.0.3", "license": "Apache-2.0 OR MIT" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/ipfs-unixfs": { "version": "11.2.5", "license": "Apache-2.0 OR MIT", @@ -8429,6 +9442,33 @@ "setimmediate": "^1.0.5" } }, + "node_modules/katex": { + "version": "0.16.22", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", + "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "peer": true, + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/keccak": { "version": "3.0.4", "hasInstallScript": true, @@ -8458,6 +9498,11 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, "node_modules/kolorist": { "version": "1.8.0", "license": "MIT" @@ -8516,6 +9561,29 @@ "node": "^18 || >=20" } }, + "node_modules/langium": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", + "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", + "license": "MIT", + "peer": true, + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, "node_modules/lie": { "version": "3.3.0", "license": "MIT", @@ -8805,6 +9873,13 @@ "node": ">=8" } }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT", + "peer": true + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "license": "MIT" @@ -8870,7 +9945,6 @@ }, "node_modules/mark.js": { "version": "8.11.1", - "dev": true, "license": "MIT" }, "node_modules/markdown-it": { @@ -8898,6 +9972,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.1.2.tgz", + "integrity": "sha512-rNQt5EvRinalby7zJZu/mB+BvaAY2oz3wCuCjt1RDrWNpS1Pdf9xqMOeC9Hm5adBdcV/3XZPJpG58eT+WBc0XQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "license": "MIT", @@ -9063,7 +10150,6 @@ }, "node_modules/mdast-util-to-hast": { "version": "13.2.0", - "dev": true, "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -9135,6 +10221,49 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.9.0.tgz", + "integrity": "sha512-YdPXn9slEwO0omQfQIsW6vS84weVQftIyyTGAZCwM//MGhPzL1+l6vO6bkf0wnP4tHigH1alZ5Ooy3HXI2gOag==", + "license": "MIT", + "peer": true, + "dependencies": { + "@braintree/sanitize-url": "^7.0.4", + "@iconify/utils": "^2.1.33", + "@mermaid-js/parser": "^0.6.2", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.11", + "dayjs": "^1.11.13", + "dompurify": "^3.2.5", + "katex": "^0.16.22", + "khroma": "^2.1.0", + "lodash-es": "^4.17.21", + "marked": "^16.0.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" + } + }, + "node_modules/mermaid/node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/micro-ftch": { "version": "0.3.1", "license": "MIT" @@ -9310,7 +10439,6 @@ }, "node_modules/micromark-util-character": { "version": "2.1.1", - "dev": true, "funding": [ { "type": "GitHub Sponsors", @@ -9425,7 +10553,6 @@ }, "node_modules/micromark-util-encode": { "version": "2.0.1", - "dev": true, "funding": [ { "type": "GitHub Sponsors", @@ -9491,7 +10618,6 @@ }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.1", - "dev": true, "funding": [ { "type": "GitHub Sponsors", @@ -9532,7 +10658,6 @@ }, "node_modules/micromark-util-symbol": { "version": "2.0.1", - "dev": true, "funding": [ { "type": "GitHub Sponsors", @@ -9547,7 +10672,6 @@ }, "node_modules/micromark-util-types": { "version": "2.0.2", - "dev": true, "funding": [ { "type": "GitHub Sponsors", @@ -9591,20 +10715,6 @@ "license": "MIT", "optional": true }, - "node_modules/minimatch": { - "version": "10.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/minimist": { "version": "1.2.8", "license": "MIT", @@ -9621,7 +10731,6 @@ }, "node_modules/minisearch": { "version": "7.1.2", - "dev": true, "license": "MIT" }, "node_modules/minizlib": { @@ -9698,6 +10807,8 @@ }, "node_modules/muggle-string": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "dev": true, "license": "MIT" }, @@ -9786,6 +10897,13 @@ "version": "1.0.1", "license": "MIT" }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==", + "license": "MIT", + "optional": true + }, "node_modules/normalize-path": { "version": "3.0.0", "license": "MIT", @@ -9841,11 +10959,15 @@ }, "node_modules/oniguruma-parser": { "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", "dev": true, "license": "MIT" }, "node_modules/oniguruma-to-es": { "version": "4.3.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.3.tgz", + "integrity": "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==", "dev": true, "license": "MIT", "dependencies": { @@ -10048,9 +11170,18 @@ }, "node_modules/path-browserify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true, "license": "MIT" }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT", + "peer": true + }, "node_modules/path-exists": { "version": "4.0.0", "license": "MIT", @@ -10161,6 +11292,24 @@ "node": ">=10.13.0" } }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT", + "peer": true + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/pony-cause": { "version": "2.1.11", "license": "0BSD", @@ -10344,7 +11493,6 @@ }, "node_modules/property-information": { "version": "7.1.0", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -10537,7 +11685,6 @@ }, "node_modules/regex": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" @@ -10545,7 +11692,6 @@ }, "node_modules/regex-recursion": { "version": "6.0.2", - "dev": true, "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" @@ -10553,7 +11699,6 @@ }, "node_modules/regex-utilities": { "version": "2.3.0", - "dev": true, "license": "MIT" }, "node_modules/registry-auth-token": { @@ -10677,6 +11822,12 @@ "version": "1.0.10", "license": "ISC" }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.45.1", "license": "MIT", @@ -10961,6 +12112,19 @@ "win32" ] }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/run-async": { "version": "4.0.5", "license": "MIT", @@ -10989,6 +12153,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, "node_modules/safe-buffer": { "version": "5.1.2", "license": "MIT" @@ -11021,7 +12191,6 @@ }, "node_modules/search-insights": { "version": "2.17.3", - "dev": true, "license": "MIT", "peer": true }, @@ -11114,16 +12283,42 @@ "license": "MIT" }, "node_modules/shiki": { - "version": "3.8.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.9.2.tgz", + "integrity": "sha512-t6NKl5e/zGTvw/IyftLcumolgOczhuroqwXngDeMqJ3h3EQiTY/7wmfgPlsmloD8oYfqkEDqxiaH37Pjm1zUhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.9.2", + "@shikijs/engine-javascript": "3.9.2", + "@shikijs/engine-oniguruma": "3.9.2", + "@shikijs/langs": "3.9.2", + "@shikijs/themes": "3.9.2", + "@shikijs/types": "3.9.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/shiki/node_modules/@shikijs/core": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.9.2.tgz", + "integrity": "sha512-3q/mzmw09B2B6PgFNeiaN8pkNOixWS726IHmJEpjDAcneDPMQmUg2cweT9cWXY4XcyQS3i6mOOUgQz9RRUP6HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.9.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/shiki/node_modules/@shikijs/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz", + "integrity": "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/core": "3.8.0", - "@shikijs/engine-javascript": "3.8.0", - "@shikijs/engine-oniguruma": "3.8.0", - "@shikijs/langs": "3.8.0", - "@shikijs/themes": "3.8.0", - "@shikijs/types": "3.8.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } @@ -11212,7 +12407,6 @@ }, "node_modules/space-separated-tokens": { "version": "2.0.2", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -11299,7 +12493,6 @@ }, "node_modules/stringify-entities": { "version": "4.0.4", - "dev": true, "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", @@ -11330,6 +12523,13 @@ "node": ">=0.10.0" } }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT", + "peer": true + }, "node_modules/superjson": { "version": "2.2.2", "license": "MIT", @@ -11359,7 +12559,6 @@ }, "node_modules/tabbable": { "version": "6.2.0", - "dev": true, "license": "MIT" }, "node_modules/table-layout": { @@ -11502,7 +12701,6 @@ }, "node_modules/trim-lines": { "version": "3.0.1", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -11553,6 +12751,16 @@ "node": ">=8" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-essentials": { "version": "7.0.3", "license": "MIT", @@ -11577,30 +12785,36 @@ "optional": true }, "node_modules/twoslash": { - "version": "0.3.2", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.4.tgz", + "integrity": "sha512-RtJURJlGRxrkJmTcZMjpr7jdYly1rfgpujJr1sBM9ch7SKVht/SjFk23IOAyvwT1NLCk+SJiMrvW4rIAUM2Wug==", "dev": true, "license": "MIT", "dependencies": { "@typescript/vfs": "^1.6.1", - "twoslash-protocol": "0.3.2" + "twoslash-protocol": "0.3.4" }, "peerDependencies": { "typescript": "^5.5.0" } }, "node_modules/twoslash-protocol": { - "version": "0.3.2", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.4.tgz", + "integrity": "sha512-HHd7lzZNLUvjPzG/IE6js502gEzLC1x7HaO1up/f72d8G8ScWAs9Yfa97igelQRDl5h9tGcdFsRp+lNVre1EeQ==", "dev": true, "license": "MIT" }, "node_modules/twoslash-vue": { - "version": "0.3.2", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/twoslash-vue/-/twoslash-vue-0.3.4.tgz", + "integrity": "sha512-R9hHbmfQMAiHG2UjB0tVFanEzz0SHDa9ZSxowAQFQMPPZSUSuP0meVG2BW2O+q7NAWzya8aJh/eXtPIMX3qsxA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/language-core": "^3.0.1", - "twoslash": "0.3.2", - "twoslash-protocol": "0.3.2" + "@vue/language-core": "^3.0.5", + "twoslash": "0.3.4", + "twoslash-protocol": "0.3.4" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -11783,7 +12997,6 @@ }, "node_modules/unist-util-is": { "version": "6.0.0", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -11795,7 +13008,6 @@ }, "node_modules/unist-util-position": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -11807,7 +13019,6 @@ }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -11819,7 +13030,6 @@ }, "node_modules/unist-util-visit": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -11833,7 +13043,6 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -11932,7 +13141,6 @@ }, "node_modules/vfile": { "version": "6.0.3", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -11945,7 +13153,6 @@ }, "node_modules/vfile-message": { "version": "4.0.2", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -12166,7 +13373,6 @@ }, "node_modules/vitepress": { "version": "1.6.3", - "dev": true, "license": "MIT", "dependencies": { "@docsearch/css": "3.8.2", @@ -12221,9 +13427,21 @@ "vite": ">=3" } }, + "node_modules/vitepress-plugin-mermaid": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/vitepress-plugin-mermaid/-/vitepress-plugin-mermaid-2.0.17.tgz", + "integrity": "sha512-IUzYpwf61GC6k0XzfmAmNrLvMi9TRrVRMsUyCA8KNXhg/mQ1VqWnO0/tBVPiX5UoKF1mDUwqn5QV4qAJl6JnUg==", + "license": "MIT", + "optionalDependencies": { + "@mermaid-js/mermaid-mindmap": "^9.3.0" + }, + "peerDependencies": { + "mermaid": "10 || 11", + "vitepress": "^1.0.0 || ^1.0.0-alpha" + } + }, "node_modules/vitepress/node_modules/@shikijs/core": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/engine-javascript": "2.5.0", @@ -12236,7 +13454,6 @@ }, "node_modules/vitepress/node_modules/@shikijs/engine-javascript": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/types": "2.5.0", @@ -12246,7 +13463,6 @@ }, "node_modules/vitepress/node_modules/@shikijs/engine-oniguruma": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/types": "2.5.0", @@ -12255,7 +13471,6 @@ }, "node_modules/vitepress/node_modules/@shikijs/langs": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/types": "2.5.0" @@ -12263,7 +13478,6 @@ }, "node_modules/vitepress/node_modules/@shikijs/themes": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/types": "2.5.0" @@ -12271,7 +13485,6 @@ }, "node_modules/vitepress/node_modules/@shikijs/types": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -12280,7 +13493,6 @@ }, "node_modules/vitepress/node_modules/@vueuse/core": { "version": "12.8.2", - "dev": true, "license": "MIT", "dependencies": { "@types/web-bluetooth": "^0.0.21", @@ -12294,7 +13506,6 @@ }, "node_modules/vitepress/node_modules/@vueuse/metadata": { "version": "12.8.2", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" @@ -12302,7 +13513,6 @@ }, "node_modules/vitepress/node_modules/oniguruma-to-es": { "version": "3.1.1", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex-xs": "^1.0.0", @@ -12312,7 +13522,6 @@ }, "node_modules/vitepress/node_modules/shiki": { "version": "2.5.0", - "dev": true, "license": "MIT", "dependencies": { "@shikijs/core": "2.5.0", @@ -12325,15 +13534,72 @@ "@types/hast": "^3.0.4" } }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "peer": true, + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "peer": true, + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT", + "peer": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT", + "peer": true + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "license": "MIT", + "peer": true + }, "node_modules/vue": { - "version": "3.5.17", + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.18.tgz", + "integrity": "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.17", - "@vue/compiler-sfc": "3.5.17", - "@vue/runtime-dom": "3.5.17", - "@vue/server-renderer": "3.5.17", - "@vue/shared": "3.5.17" + "@vue/compiler-dom": "3.5.18", + "@vue/compiler-sfc": "3.5.18", + "@vue/runtime-dom": "3.5.18", + "@vue/server-renderer": "3.5.18", + "@vue/shared": "3.5.18" }, "peerDependencies": { "typescript": "*" @@ -12715,7 +13981,6 @@ }, "node_modules/zwitch": { "version": "2.0.4", - "dev": true, "license": "MIT", "funding": { "type": "github", diff --git a/package.json b/package.json index 461cd501..b2334164 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,8 @@ { "name": "iexec-documentation", "version": "0.0.0", + "private": true, + "type": "module", "scripts": { "dev": "vitepress dev", "build": "vitepress build", @@ -30,11 +32,12 @@ "viem": "^2.33.1", "vitepress-plugin-google-analytics": "^1.0.2", "vitepress-plugin-group-icons": "^1.6.1", + "vitepress-plugin-mermaid": "^2.0.17", "vue": "^3.5.17" }, "devDependencies": { "@iconify/vue": "^5.0.0", - "@shikijs/vitepress-twoslash": "^3.8.0", + "@shikijs/vitepress-twoslash": "^3.9.2", "@types/figlet": "^1.7.0", "@types/prop-types": "^15.7.15", "@types/react": "^18.3.23", diff --git a/src/get-started/protocol/tee/intel-sgx-technology.md b/src/get-started/protocol/tee/intel-sgx-technology.md new file mode 100644 index 00000000..62ab37ff --- /dev/null +++ b/src/get-started/protocol/tee/intel-sgx-technology.md @@ -0,0 +1,84 @@ +# Overview + +**Confidential Computing** (or **Trusted Execution Environments -** **'TEE'**) +ensures computation confidentiality through mechanisms of memory encryption at +the hardware level. Applications being executed and data being processed are +safeguarded against even the most privileged access levels (OS, Hypervisor...). +Only authorized code can run inside this protected area and manipulate its data. + +In some cases, ensuring that code runs correctly without any third party +altering the execution, is even more important than hiding the computation's +data. This concept is called **Trusted Computing.** + +These guarantees are critical for a decentralized cloud where code is being +executed on a remote machine, that is not controlled by the requester. They are +also required to prevent leakage while monetizing data sets. + +## Intel® Software Guard Extension (Intel® SGX) + +[Intel® SGX](https://software.intel.com/en-us/sgx) is a technology that enables +**Trusted Computing** and **Confidential Computing**. At its core, it relies on +the creation of a special zone in the memory called an “enclave”. This enclave +can be considered as a vault, to which only the CPU can have access. Neither +privileged access-levels such as root, nor the operating system itself is +capable of inspecting the content of this region. The code, as well as the data +inside the protected zone, is totally unreadable and unalterable from the +outside. This guarantees non-disclosure of data as well as tamper-proof +execution of the code. + +An application's code can be separated into "trusted" and "untrusted" parts +where sensitive data is manipulated inside the protected area. + +## Confidential Computing with iExec + +Here is a general overview of how a TEE application runs on iExec: + +```mermaid +graph TD + Req[Requester] --> |1 . Buy task| Chain + Chain[Blockchain] --> |2 . Notify task to compute| Worker[Worker/Workerpool] + Worker --> |3 . Launch TEE application| App[TEE application pre-starting] + App --> |4 . Send report containing integrity information of the enclave| SMS{SMS Is integrity and authenticity
of the requesting enclave valid?} + SMS --> |No| AppFailed[TEE application run aborted] + SMS --> |Yes| AppStarted[TEE application started] + + style AppFailed color:red + style AppStarted color:green +``` + +To build such Confidential Computing (TEE) application, a developer would need +to use the Intel® SGX SDK. With iExec, you don't need to manipulate it. Instead +iExec supports the high-level Scone framework. + +At a high-level, Scone protects the confidentiality and integrity of the data +and the code without needing to modify or recompile the application. With native +Intel® SGX technology, the OS is not a part of the Trusted Computing Base (TCB) +hence system calls and kernel services are not available from an Intel® SGX +enclave. This can be limiting as the application will not be able to use File +System and sockets directly from the code running inside the enclave. The +[Scone](https://scontain.com/) framework resolves this and reduces the burden of +porting the application to Intel® SGX. + +More precisely, Scone provides a C standard library interface to container +processes. System calls are executed outside of the enclave, but they are +shielded by transparently encrypting/decrypting application data. Files stored +outside of the enclave are therefore encrypted, and network communication is +protected by Transport Layer Security (TLS). + +For a deeper understanding, you can have a look to the official +[Scone documentation](https://sconedocs.github.io/). + +## Let's build + +::: warning + +Following steps will show you how to build a Confidential Computing application. +The environment you are about to use is a "develop" environment: + +- which can be reset at any time +- where configurations and secrets might be inspected (debug enclaves) + +When your developer discovery journey is complete, please reach the +[production section](/guides/build-iapp/build-&-deploy#go-to-production). + +::: diff --git a/src/guides/build-iapp/advanced/access-confidential-assets.md b/src/guides/build-iapp/advanced/access-confidential-assets.md new file mode 100644 index 00000000..7d705204 --- /dev/null +++ b/src/guides/build-iapp/advanced/access-confidential-assets.md @@ -0,0 +1,63 @@ +# Access confidential assets from your app + +::: warning + +Before going any further, make sure you managed to +[Build your first application with Scone framework](create-your-first-sgx-app.md). + +::: + +## Secret Management Service (SMS) + +You can use confidential assets on iExec thanks to the _iExec Secret Management +Service_. This service verifies that the enclave asking for secrets is +authorized to do so. Any user - as a confidential asset provider - declares on +the blockchain which enclaves are authorized to access it. For each task, the +SMS will query the blockchain to determine if the enclave requesting secrets is +indeed whitelisted for it. + +The SMS currently supports 3 types of secrets: + +1. [Application developer secret](/guides/build-iapp/build-&-deploy#application-developer-secret): + This secret is directly accessible from the application as an environment + variable. It is owned by the developer of the application. It can be any kind + of data (API key, private key, token, ..) as long as it respects the size + limit (max. 4096 kB). +2. [Requester secrets](/guides/build-iapp/inputs-and-outputs#access-requester-secrets): + These secrets are directly accessible from the application as environment + variables, as long as the requester has decided to share them with it. These + secrets can be any kind of data as long as they respect the size limit (max. + 4096 kB). Before buying a task, a requester secret is pushed into the SMS and + is not linked to any application. When a requester buys a task, the requester + can declare which secrets can be accessed by the application. Doing so, a + single requester secret can be shared with multiple applications. +3. [Dataset secret](sgx-encrypted-dataset.md): A dataset secret is not directly + accessible from the application but its decrypted content is. If a dataset is + requested and authorized to be used in it, its content will be automatically + decrypted in the application enclave. To monetize such a dataset on iExec, + the original dataset must be encrypted using the iExec SDK, its encrypted + counterpart must be publicly available and its encryption key pushed into the + SMS. + +Here is a general overview of how confidential assets are used on iExec: + +```mermaid +graph TD + Req[Requester] -->|1.a. Push secret| SMS[SMS] + AppDev[Application developer] -->|1.b. Push secret| SMS + DatasetOwn[Dataset owner] -->|1.c. Push secret| SMS + Req --> |2 . Buy task| Chain + Chain[Blockchain] --> |3 . Notify task to compute| Worker[Worker/Workerpool] + Worker --> |4 . Launch TEE application| App[TEE application] + App --> |5.a. Get secrets for task| SMS + SMS --> |5.b. Check authorization for secrets| Chain +``` + +## Next step? + +You now understand how these three kinds of confidential assets work on iExec, +you can go one step further by learning how to manipulate them: + +- [Attach a secret to your app](/guides/build-iapp/build-&-deploy#application-developer-secret) +- [Access requester secrets](/guides/build-iapp/inputs-and-outputs#access-requester-secrets) +- [Access a confidential dataset](sgx-encrypted-dataset.md) diff --git a/src/guides/build-iapp/advanced/create-your-first-sgx-app.md b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md new file mode 100644 index 00000000..b53a4584 --- /dev/null +++ b/src/guides/build-iapp/advanced/create-your-first-sgx-app.md @@ -0,0 +1,306 @@ +# Build your first application with Scone framework + +In this tutorial, you will learn how to build and run a Confidential Computing +application with the Scone TEE framework. + +::: warning + +Before going any further, make sure you managed to +[Build your first application](./your-first-app). + +::: + +::: tip Prerequisites: + +- [Docker](https://docs.docker.com/install/) 17.05 or higher on the daemon and + client. +- [iExec SDK](https://www.npmjs.com/package/iexec) 8.0.0 or higher. + [Install the iExec SDK](./quick-start-for-developers.md#install-the-iexec-sdk) +- Familiarity with the basic concepts of + [Intel® SGX](/get-started/protocol/tee/intel-sgx-technology) and + [SCONE](https://scontain.com) framework. + +::: + +In order to follow this tutorial, you will need to register a +[free SCONE Account](https://scontain.com) to access SCONE build tools and +curated images from the [SCONE registry](https://gitlab.scontain.com/). + +Once your account is activated, you need to +[request access to the SCONE build tools for iExec](mailto:info@scontain.com?cc=scone-access@iex.ec&subject=iExec%20Build%20Tools&body=Hi%20SCONE%20Team%2C%0D%0A%0D%0AI%20would%20like%20to%20get%20access%20to%20the%20SCONE%20build%20tools%20for%20iExec:%0A%20-%20scone-production/iexec-sconify-image%0A%20-%20sconecuratedimages%20%28all%20curated%20images%20such%20as%20nodejs%2C%20python...%29%0A%0AMy%20DockerID%20is%20...%0A%0ABest%20regards%0A%0A...). + +```bash +# when your account is ready, run `docker login` to connect the SCONE registry +docker login registry.scontain.com +``` + +## Prepare your application + +::: warning + +For demo purposes, we omitted some development best practices in these examples. + +Make sure to check your field's best practices before going to production. + +::: + +Before going further, your `/hello-world:1.0.0` image built +previously is required. + +If you missed that part, please go back to +[Build your first application](./your-first-app). + +For this tutorial, you can reuse the same directory tree or create a new one. + +To create a new directory tree, execute the following commands in +`~/iexec-projects/`. + +```bash +cd ~/iexec-projects +mkdir tee-hello-world-app && cd tee-hello-world-app +iexec init --skip-wallet +mkdir src +touch Dockerfile +touch sconify.sh +chmod +x sconify.sh +``` + +### Update chain json + +Make sure your `chain.json` content is as follows: + +```json +{ + "default": "bellecour", + "chains": { + "bellecour": { + "sms": { "scone": "https://sms.scone-debug.v8-bellecour.iex.ec" } + } + } +} +``` + +If you start from a new firectory tree, you will need to replay the following +steps from [Build your first application](./your-first-app): + +- [Write the app](./your-first-app.md#write-the-app) Javascript or Python source + code in `src/` +- [Dockerize your app](./your-first-app.md#dockerize-your-app) +- [Push your app to Dockerhub](./your-first-app.md#push-your-app-to-dockerhub) + +As we mentioned earlier, the advantage of using **SCONE** is the ability to make +the application **Intel® SGX-enabled** without changing the source code. The +only thing we are going to do is rebuilding the app using the +Trusted-Execution-Environment tooling provided by **SCONE**. + +::: info + +SCONE provides TEE conversion tooling (Python, Java, ..) plus eventually TEE +base images for other languages (NodeJs). + +::: + +## Build the TEE docker image + +We will use the following script to wrap the sconification process, copy the +`sconify.sh` script in the current directory: + +::: code-group + +```bash [for Javascript] +#!/bin/bash + +# Declare the app entrypoint +ENTRYPOINT="node /app/app.js" + +# Declare image related variables +IMG_NAME=tee-scone-hello-world +IMG_FROM=/hello-world:1.0.0 +IMG_TO=/${IMG_NAME}:1.0.0-debug + +# Run the sconifier to build the TEE image based on the non-TEE image +docker run -it --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + registry.scontain.com/scone-production/iexec-sconify-image:5.9.1-v16\ + sconify_iexec \ + --name=${IMG_NAME} \ + --from=${IMG_FROM} \ + --to=${IMG_TO} \ + --binary-fs \ + --fs-dir=/app \ + --host-path=/etc/hosts \ + --host-path=/etc/resolv.conf \ + --binary=/usr/local/bin/node \ + --heap=1G \ + --dlopen=1 \ + --no-color \ + --verbose \ + --command=${ENTRYPOINT} \ + && echo -e "\n------------------\n" \ + && echo "successfully built TEE docker image => ${IMG_TO}" \ + && echo "application mrenclave.fingerprint is $(docker run --rm -e SCONE_HASH=1 ${IMG_TO})" +``` + +```bash [for Python] +#!/bin/bash + +# Declare the app entrypoint +ENTRYPOINT="python3 /app/app.py" + +# Declare image related variables +IMG_NAME=tee-scone-hello-world +IMG_FROM=/hello-world:1.0.0 +IMG_TO=/${IMG_NAME}:1.0.0-debug + +# Run the sconifier to build the TEE image based on the non-TEE image +docker run -it \ + -v /var/run/docker.sock:/var/run/docker.sock \ + registry.scontain.com/scone-production/iexec-sconify-image:5.9.1-v16\ + sconify_iexec \ + --name=${IMG_NAME} \ + --from=${IMG_FROM} \ + --to=${IMG_TO} \ + --binary-fs \ + --fs-dir=/app \ + --host-path=/etc/hosts \ + --host-path=/etc/resolv.conf \ + --binary=/usr/local/bin/python3 \ + --heap=1G \ + --dlopen=1 \ + --no-color \ + --verbose \ + --command=${ENTRYPOINT} \ + && echo -e "\n------------------\n" \ + && echo "successfully built TEE docker image => ${IMG_TO}" \ + && echo "application mrenclave.fingerprint is $(docker run --rm -e SCONE_HASH=1 ${IMG_TO})" +``` + +::: + +Run the `sconify.sh` script to build the Scone TEE application: + +```bash +./sconify.sh +``` + +Push your image on DockerHub: + +```bash +docker push /tee-scone-hello-world:1.0.0-debug +``` + +Congratulations, you just built your Scone TEE application. + +::: info + +You may have noticed the `tee-debug` flag in the image name, the built image is +actually in TEE debug mode, this allows you to have some debug features while +developping the app. + +Once you are happy with the debug app, contact us to go to production! + +::: + +## Test your app on iExec + +At this stage, your application is ready to be tested on iExec. The process is +similar to testing any type of application on the platform, with these minor +exceptions: + +### Deploy the TEE app on iExec + +TEE applications require some additional information to be filled in during +deployment. + +```bash +# prepare the TEE application template +iexec app init --tee +``` + +Edit `iexec.json` and fill in the standard keys and the `mrenclave` object: + +```json +{ + ... + "app": { + "owner": "", // starts with 0x + "name": "tee-scone-hello-world", // application name + "type": "DOCKER", + "multiaddr": "docker.io//tee-scone-hello-world:1.0.0-debug", // app image + "checksum": "", // starts with 0x, update it with your own image digest + "mrenclave": { + "framework": "SCONE", // TEE framework (keep default value) + "version": "v5.9", // Scone version (keep default value) + "entrypoint": "node /app/app.js" OR "python3 /app/app.py", // update it with your own image entrypoint + "heapSize": 1073741824, // heap size in bytes, update it with --heap option value used in sconify.sh script during TEE image build + "fingerprint": "" // fingerprint of the enclave code (mrenclave), without 0x prefix, see how to retrieve it below + } + }, + ... +} +``` + +::: info + +See +[Create your identity on the blockchain](./quick-start-for-developers.md#create-your-identity-on-the-blockchain) +to retrieve `` value. + +See [Deploy your app on iExec](./your-first-app.md#deploy-your-app-on-iexec) to +retrieve your image ``. + +Run your TEE image with `SCONE_HASH=1` to get the enclave fingerprint +(mrenclave): + +```bash +docker run --rm -e SCONE_HASH=1 /tee-scone-hello-world:1.0.0-debug +``` + +::: + +Deploy the app with the standard command: + +```bash +iexec app deploy +``` + +### Run the TEE app + +Specify the tag `--tag tee,scone` in `iexec app run` command to run a tee app. + +One last thing, in order to run a **TEE-debug** app you will also need to select +a debug workerpool, use the debug workerpool +`debug-v8-learn.main.pools.iexec.eth`. + +You are now ready to run the app + +```bash +iexec app run --tag tee,scone --workerpool debug-v8-learn.main.pools.iexec.eth --watch +``` + +::: info + +You noticed we used `debug-v8-learn.main.pools.iexec.eth` instead of an ethereum +address, this is an ENS name. + +The [ENS (Ethereum Name Service)](https://ens.domains/) protocol enables +associating decentralized naming to ethereum addresses. + +::: + +::: info + +Remember, you can access task and app logs by following the instructions on page +[Debug your tasks](/guides/build-iapp/debugging). + +::: + +## Next step? + +In this tutorial, you learned how to leverage your application with the power of +Trusted Execution Environments using iExec. But according to your use case, you +may need to use some confidential data to get the full potential of the +**Confidential Computing** paradigm. Check out next chapters to see how: + +- [Access confidential assets from your app](access-confidential-assets.md) +- [Protect the result](end-to-end-encryption.md) diff --git a/src/guides/build-iapp/advanced/create-your-first-tdx-app.md b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md new file mode 100644 index 00000000..1047ab3b --- /dev/null +++ b/src/guides/build-iapp/advanced/create-your-first-tdx-app.md @@ -0,0 +1,112 @@ +# Build Intel TDX app + +In this tutorial, you will learn how to build and run a Confidential Computing +application with the TDX framework. + +::: info + +**Request access to the experimental feature** + +- The TDX-powered workerpool is currently in a development environment and not + intended for production use. +- Expect occasional instability or incomplete features. Service is subject to + change or discontinuation +- Development environment only - do not share sensitive data or secrets. +- Please share any bug reports, suggestions for improvement, or general feedback + on your experience. +- To request early access, please [contact us](https://discord.gg/9h25DQFSCU) + +::: + +## Prerequisites + +- [Docker](https://docs.docker.com/install/) 17.05 or higher on the daemon and + client. +- [iExec SDK 8.13.0-tdx](https://github.com/aimen-djari/iexec-sdk/tree/feature/tdx). + Contact us to have this special release. + +## Build your application + +Thanks to **Intel TDX**, neither the source code or the binaries of your +application need to be changed in order to run securely in a TEE. Only two files +need to be changed compared to the usual SGX workflow: `chain.json` and +`iexec.json`. + +iApps for the TDX framework follow the same format as non-TEE applications; +follow the instructions on [Build your first application](./your-first-app) to +create and Dockerize your iApp. + +After this step, the Docker image of your iApp should be published on Docker Hub +(e.g. `/hello-world:1.0.0`). + +### Update `chain.json` + +Modify your `chain.json` as follows to reference the TDX Workerpool: + +```json +{ + "default": "bellecour", + "chains": { + "bellecour": { + "sms": { "tdx": "https://sms.labs.iex.ec" } + } + } +} +``` + +### Update `iexec.json` + +TEE applications need a few more keys in the `iexec.json` file; run this to add +them automatically: + +```bash +iexec app init --tee-framework tdx +``` + +Your `iexec.json` should now look like this example: + +```json +{ + ... + "app": { + "owner": "", // starts with 0x + "name": "tee-scone-hello-world", // application name + "type": "DOCKER", + "multiaddr": "/hello-world:1.0.0", // app image + "checksum": "", // starts with 0x, update it with your own image digest + "mrenclave": { + "framework": "TDX", // TEE framework (keep default value) + } + }, + ... +} +``` + +::: info + +See [Deploy your app on iExec](./your-first-app.md#deploy-your-app-on-iexec) to +retrieve your image ``. + +::: + +### Deploy and run the TEE app + +Deploy the app with the standard command: + +```bash +iexec app deploy +``` + +To execute the app in TDX, ddd `--tag tee,tdx` to the `iexec app run` and select +the TDX workerpool (`tdx-labs.pools.iexec.eth`). + +```bash +iexec app run --tag tee,tdx --workerpool tdx-labs.pools.iexec.eth --watch +``` + +::: info + +Remember, you can access task and app logs by following the instructions on page +[Debug your tasks](/guides/build-iapp/debugging). + +::: diff --git a/src/guides/build-iapp/advanced/end-to-end-encryption.md b/src/guides/build-iapp/advanced/end-to-end-encryption.md new file mode 100644 index 00000000..13d09447 --- /dev/null +++ b/src/guides/build-iapp/advanced/end-to-end-encryption.md @@ -0,0 +1,136 @@ +# Protect the result + +In previous tutorials, we saw how to build +[Confidential Computing applications](/get-started/protocol/tee/intel-sgx-technology) +that run securely inside enclaves and combine them with confidential assets to +get the most out of confidential computing advantages. In this chapter, we will +push things further to protect the workflow in an end to end mode. That means +the next step would be encrypting results. + +::: warning + +Before going any further, make sure you managed to +[Build your first application with Scone framework](create-your-first-sgx-app.md). + +::: + +::: tip Prerequisites: + +- [Docker](https://docs.docker.com/install/) 17.05 or higher on the daemon and + client. +- [iExec SDK](https://www.npmjs.com/package/iexec) 8.0.0 or higher. + [Install the iExec SDK](./quick-start-for-developers.md#install-the-iexec-sdk) +- Familiarity with the basic concepts of + [Intel® SGX](/get-started/protocol/tee/intel-sgx-technology) and + [SCONE](https://scontain.com) framework. + +::: + +::: info + +You don't need to change your application's code or redeploy it to add this +feature. + +::: + +Assuming your application is deployed (if not please check how to do it +[with Scone](create-your-first-sgx-app.md#deploy-the-tee-app-on-iexec)), before +triggering an execution you need to generate an RSA key-pair, then push the +public key to the +[Secret Management Service](/get-started/protocol/tee/intel-sgx-technology). The +latter, in turn, will provide it, at runtime, to the enclave running your +Confidential Computing application. + +To generate the key-pair, go to `~/iexec-projects` and use the following SDK +command: + +Make sure your [`chain.json`](create-your-first-sgx-app.md#update-chain-json) +content is correct. + +```bash +iexec result generate-encryption-keypair +``` + +This generates two files in `.secrets/beneficiary/`. Make sure to back up the +private key in the file `<0x-your-wallet-address>_key`. + +```bash +.secrets +├── beneficiary +│ ├── <0x-you-wallet-address>_key +│ └── <0x-you-wallet-address>_key.pub +... +``` + +Now, push the public key to the SMS: + +```bash +iexec result push-encryption-key --tee-framework scone +``` + +And check it using: + +```bash +iexec result check-encryption-key --tee-framework scone +``` + +Now to see that in action, you'd need to trigger a task and specify yourself as +the beneficiary in the command: + +```bash +iexec app run <0x-your-app-address> \ + --workerpool debug-v8-learn.main.pools.iexec.eth \ + --tag tee,scone \ + --encrypt-result \ + --watch +``` + +Wait for the task to be `COMPLETED` and download the result: + +```bash +iexec task show <0x-your-task-id> --download +``` + +If you extract the obtained zip and try to read the content of the file +`iexec_out/result.zip.aes` you will find it encrypted: + +```bash +mkdir /tmp/trash && \ + unzip <0x-your-task-id>.zip -d /tmp/trash && \ + cat /tmp/trash/iexec_out/result.zip.aes +``` + +`iexec_out/result.zip` : + +```bash +)3�Xq��Yv��ȿzE�fRu<\�ݵm�m���疞r���c��(a���{{'��ܼ���͛�q/[{����H�t>��������h��gD$g��\.�k��j�����"�s?"�h�J�_Q41�_[{��X��������Ԛ��a�蘟v���E����r����肽 +�����Յ]9W�TL�*��� + �t��d���z��O`����!���e�&snoL3�K6L9���% +``` + +Now you should decrypt the result by running: + +```bash +iexec result decrypt <0x-your-task-id.zip> +``` + +A new zip file appears in the current folder under the name `results.zip`. +Eventually, unzip it: + +```bash +unzip results.zip -d my-decrypted-result +``` + +And you can see the content of your result file: + +```bash +$ cat my-decrypted-result/result.txt +Hello, world! +``` + +Voilà! By finishing this part, you should be able to use confidential computing +on iExec like a Ninja. All parts of the workflow are protected: the execution, +the dataset, and the result. + +You can go to the advanced section and learn more about managing orders on the +iExec to effectively monetize your applications and datasets. diff --git a/src/guides/build-iapp/advanced/overview.md b/src/guides/build-iapp/advanced/overview.md new file mode 100644 index 00000000..f3cc0be7 --- /dev/null +++ b/src/guides/build-iapp/advanced/overview.md @@ -0,0 +1,32 @@ +--- +title: Advanced iApp Building +description: + Legacy, low-level guides for building confidential iApps (Docker, SGX, TDX, + SCONE/Gramine, E2E encryption) +--- + +# ⚙️ Advanced iApp Building + +::: warning Important + +This section contains legacy, low-level material. Please note: + +- Terminology and some concepts may have changed in the current documentation. +- These topics are intentionally advanced and can be complex to understand. +- In most cases, you should not need to dive into this section — we’ve + simplified and streamlined recommended paths elsewhere in the docs. + +If you believe you truly need these advanced flows or you’re unsure which path +to take, please contact our support so we can understand your use case and help +you efficiently: [Join our Discord](https://discord.gg/9h25DQFSCU). + +::: + +- **[Quick Start for Developers](./quick-start-for-developers)** +- **[Build your first application](./your-first-app)** +- **[Intel SGX Technology Overview](/get-started/protocol/tee/intel-sgx-technology)** +- **[Build your first SGX app (SCONE)](./create-your-first-sgx-app)** +- **[End-to-end Encryption](./end-to-end-encryption)** +- **[SGX Encrypted Dataset](./sgx-encrypted-dataset)** +- **[Access Confidential Assets](./access-confidential-assets)** +- **[Build Intel TDX app](./create-your-first-tdx-app)** diff --git a/src/guides/build-iapp/advanced/quick-start-for-developers.md b/src/guides/build-iapp/advanced/quick-start-for-developers.md new file mode 100644 index 00000000..32908455 --- /dev/null +++ b/src/guides/build-iapp/advanced/quick-start-for-developers.md @@ -0,0 +1,347 @@ +# Quick Start + +> In this tutorial we will show you how you can create decentralized application +> over the iExec infrastructure. + +iExec enables decentralized docker app deployment and monetization on the +blockchain. + +In this guide, we will use the iExec SDK command-line interface to deploy an +iExec app on a test blockchain. + +## Install the iExec SDK + +Requirements: +[![npm version](https://img.shields.io/badge/nodejs-%3E=18.0.0-brightgreen.svg)](https://nodejs.org/en/) + +```bash +npm -g install iexec # install the cli +iexec --version +iexec --help +``` + +## Create your identity on the blockchain + +On the blockchain, your identity is defined by your **wallet,** constisting of +cryptochraphically encrypted **private key** and **public address.** What you +own on the blockchain is associated with your address. The applications you +deploy on iExec are associated with your wallet. + +Let's set up your wallet. + +Create a new Wallet file + +```text +iexec wallet create +``` + +You will be asked to choose a password to protect your wallet, don't forget it +since there is no way to recover it. The SDK creates a wallet file that contains +a randomly generated private key encrypted by the chosen password and the +derived public address. Make sure to back up the wallet file in a safe place and +write down your address. + +::: tip Your wallet is stored in the ethereum keystore, the location depends on +your OS: + +- On Linux: ~/.ethereum/keystore +- On Mac : ~/Library/Ethereum/keystore +- On Windows: ~/AppData/Roaming/Ethereum/keystore + +Wallet file name follow the pattern `UTC----
` + +::: + +::: info + +iExec SDK uses standard Ethereum wallet, you can reuse or import existing +Ethereum wallet. See iExec SDK documentation +[wallet command](https://github.com/iExecBlockchainComputing/iexec-sdk/blob/v8.1.5/CLI.md#iexec-wallet). + +::: + +## Initialize your iExec project + +Create a new folder for your iExec project and initialize the project: + +```text +mkdir ~/iexec-projects +cd ~/iexec-projects +iexec init --skip-wallet +``` + +::: info + +The iExec SDK creates the minimum configuration files: + +- `iexec.json` contains the project configuration +- `chain.json` contains the blockchain connection configuration +- we use `--skip-wallet` to skip wallet creation as we already created it + +::: + +You can now connect to the blockchain. In the following steps, we will use the +[iExec sidechain (also called Bellecour)](/get-started/tooling-and-explorers/blockchain-explorer#bellecour) + +You can now check your wallet content: + +```text +iexec wallet show +``` + +## Deploy your app on iExec + +iExec enables decentralized deployment of dockerized applications. The +applications deployed on iExec are Smart Contracts identified by their Ethereum +address and referencing a public docker image. Each iExec application has an +owner who can set the execution permissions on iExec platform. + +Let's deploy an iExec app! + +Initialize a new application + +```text +iexec app init +``` + +The iExec SDK writes the minimum app configuration in `iexec.json` + +| **key** | **description** | +| --------- | --------------------------------------------------------------------------- | +| owner | app owner ethereum address \(default your wallet address\) | +| name | name of the application | +| type | type of application \("DOCKER" for docker container\) | +| multiaddr | download URI of the application \(a public docker registry\) | +| checksum | checksum of the app \("0x" + docker image digest\) | +| mrenclave | app fingerprint used for confidential computing use cases \(default empty\) | + +::: info + +The default app is the public docker image +[iexechub/python-hello-world](https://hub.docker.com/repository/docker/iexechub/python-hello-world). + +Given an input string, the application generates an ASCII art greeting. + +::: + +You can deploy this application on iExec, it will run out of the box. When you +are confident with iExec concept, you can read +[Your first app](your-first-app.md) and learn how to setup your own app on +iExec. + +You will now deploy your app on iExec, this will be your first transaction on +the blockchain: + +```text +iexec app deploy +``` + +::: tip + +While running `iexec app deploy` you sent your first transaction on the +bellecour blockchain. + +::: + +You can check your deployed apps with their index, let's check your last +deployed app: + +```text +iexec app show +``` + +## Run your app on iExec + +iExec allows you to run applications on a decentralized infrastructure with +payment in **RLC** tokens \(the native cryptocurrency of iExec\). + +::: info + +To run an application you must have enough RLC staked on your iExec account to +pay for the computing resources. + +Your iExec account is managed by smart contracts \(and not owned by iExec\). + +When you request an execution the price for the task is locked from your +account's stake then transferred to accounts of the workers contributing to the +task \(read more about +[Proof of Contribution](/get-started/protocol/proof-of-contribution) protocol\). + +At any time you can: + +- view your balance + +```sh +iexec account show +``` + +- deposit RLC from your wallet to your iExec Account + +```sh +iexec account deposit +``` + +- withdraw RLC from your iExec account to your wallet \(only stake can be + withdrawn\) + +```sh +iexec account withdraw +``` + +::: + +Currently, iExec sponsors applications running on Bellecour, and you won't have +to pay for the computation. + +Everything is ready to run your application! + +```text +iexec app run --args --workerpool prod-v8-learn.main.pools.iexec.eth --watch +``` + +::: info + +`iexec app run` allows to run an application on iExec at the market price. + +Useful options: + +- `--args ` specify the app execution arguments +- `--watch` watch execution status changes +- `--workerpool
` specify the workerpool to use (eg: + `--workerpool prod-v8-learn.main.pools.iexec.eth`) + +Discover more option with `iexec app run --help` + +::: + +::: tip Congratulation you requested the execution of +[iexechub/python-hello-world](https://hub.docker.com/repository/docker/iexechub/python-hello-world). + +This will generate an ASCII art greeting with your name. + +::: + +The execution of tasks on the iExec network is asynchronous by design. + +```mermaid +graph TD + Requester["Requester (or anyone)"] --> |"1 . Match compatible orders \n(request, application, dataset & workerpool orders) \n & Wait result" | Blockchain + Blockchain --> |2 . Notify new deal with tasks to compute| Scheduler + Worker --> |3 . Request new task to compute| Scheduler + Worker --> |4 . Run application| Application[Application image] + Worker --> |5.a. Push result| ResultStorage["Result Storage"] + Worker --> |5.b. Commit result proof| Blockchain + Workerpool --> |6 . Publish result link or callback| Blockchain + + subgraph Workerpool + Scheduler + Worker + Application + end +``` + +Guaranties about completion times (fast/slow) are available in the +[category section](/get-started/protocol/pay-per-task): + +- maximum deal/task time +- maximum computing time + +Once the task is completed copy the taskid from `iexec app run` output \(taskid +is a 32Bytes hexadecimal string\). + +Download the result of your task + +```text +iexec task show --download my-result +``` + +You can get your taskid with the command: + +```text +iexec deal show +``` + +::: info + +A task result is a zip file containing the output files of the application. + +::: + +[iexechub/python-hello-world](https://hub.docker.com/repository/docker/iexechub/python-hello-world) +produce an text file in `result.txt`. + +Let's discover the result of the computation. + +```text +unzip my-result.zip -d my-result +cat my-result/result.txt +``` + +Congratulations! You successfully executed your application on iExec! + +## Publish your app on the iExec Marketplace + +Your application is deployed on iExec and you completed an execution on iExec. +For now, only you can request an execution of your application. The next step is +to publish it on the iExec Marketplace, making it available for anyone to use. + +As the owner of this application, you can define the conditions under which it +can be used + +::: info + +iExec uses orders signed by the resource owner's wallet to ensure resources +governance. + +The conditions to use an app are defined in the **apporder**. + +::: + +Publish a new apporder for your application. + +```text +iexec app publish +``` + +::: info + +`iexec app publish` options allows to define custom access rules to the app +\(run `iexec app publish --help` to discover all the possibilities\). + +You will learn more about orders management later, keep the apporder default +values for now. + +::: + +Your application is now available for everyone on iExec marketplace on the +conditions defined in apporder. + +You can check the published apporders for your app + +```text +iexec orderbook app +``` + +Congratulation you just created a decentralized application! Anyone can now +trigger an execution of your application on the iExec decentralized +infrastructure. + +- With the iexec SDK CLI + `iexec app run --workerpool prod-v8-learn.main.pools.iexec.eth` +- On iExec marketplace + +## What's next? + +You are now familiar with the following key iExec concepts for developers: + +- Your wallet is your on-chain ID and blockchain account +- You can deploy decentralized applications on iExec +- Anyone can run tasks against payment in RLC on iExec +- Payments are processed by the decentralized platform between users' iExec + Accounts +- Resource governance is managed by orders + +Continue with these guides: + +- [Learn how to build your first application running on iExec](your-first-app.md) +- [Learn how to manage your apporders](/guides/build-iapp/build-&-deploy#manage-your-apporders) diff --git a/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md b/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md new file mode 100644 index 00000000..eee484e9 --- /dev/null +++ b/src/guides/build-iapp/advanced/sgx-encrypted-dataset.md @@ -0,0 +1,368 @@ +# Access a confidential dataset + +In this tutorial, you will learn how to leverage an encrypted dataset by using +the `IEXEC_DATASET_FILENAME` environment variable in your application. + +::: tip Prerequisites: + +- Familiarity with the basic concepts of + [Intel® SGX](/get-started/protocol/tee/intel-sgx-technology) and + [SCONE](https://scontain.com) framework. +- [Build With a Scone TEE application](create-your-first-sgx-app.md) + +::: + +Trusted Execution Environments offer a huge advantage from a security +perspective. They guarantee that the behavior of execution does not change even +when launched on an untrusted remote machine. The data inside this type of +environment is also protected, which allows its monetization while preventing +leakage. + +With iExec, it is possible to authorize only applications you trust to use your +datasets and get paid for it. Data is encrypted using standard encryption +mechanisms and the plain version never leaves your machine. The encrypted +version is made available for usage and the encryption key is pushed into the +[SMS](/get-started/protocol/tee/intel-sgx-technology#secret-management-service-sms). +After you deploy the dataset on iExec it is you, and only you, who decides which +application is allowed to get the secret to decrypt it. + +::: warning + +Datasets are only decrypted inside authorized +[enclaves](/get-started/protocol/tee/intel-sgx-technology) and never leave them. +The same thing applies to secrets. + +::: + +::: info + +Your secrets are transferred with the SDK from your machine to the SMS over a +TLS channel. + +::: + +Let's see how to do all of that! + +## Encrypt the dataset + +Before starting, let's make sure we are inside the `~/iexec-projects` folder +previously created during the [quick start](./quick-start-for-developers.md) +tutorial. + +```bash +cd ~/iexec-projects +mkdir tee-dataset-app && cd tee-dataset-app +iexec init --skip-wallet +``` + +Make sure your `chain.json` content is the same as the one described +[here](create-your-first-sgx-app.md#update-chain-json). + +Init the dataset configuration. + +```bash +iexec dataset init --encrypted +``` + +This command will create the `datasets/encrypted`, `datasets/original` and +`.secrets/datasets` folders. A new `dataset` section will be added to the +`iexec.json` file as well. + +```bash +. +├── datasets +│ ├── encrypted +│ └── original +└── .secrets + └── datasets +``` + +We will create a dummy file that has `"Hello, world!"` as content inside +`datasets/original`. Alternatively, you can put your own dataset file. + +```bash +echo "Hello, confidential world!" > datasets/original/my-first-dataset.txt +``` + +```bash +datasets +├── encrypted +└── original + └── my-first-dataset.txt +``` + +Now run the following command to encrypt the file: + +```bash +iexec dataset encrypt +``` + +::: info + +`iexec dataset encrypt` will output a checksum, keep this value for a later use. + +::: + +```bash +datasets +├── encrypted +│ └── my-first-dataset.txt.enc +└── original + └── my-first-dataset.txt +``` + +As you can see, the command generated the file +`datasets/encrypted/my-first-dataset.txt.enc`. That file is the encrypted +version of your dataset, you should push it somewhere accessible because the +worker will download it during the execution process. You will enter this file's +URI in the `iexec.json`file (`multiaddr` attribute) when you will deploy your +dataset. Make sure that the URI is a **DIRECT** download link (not a link to a +web page for example). + +::: info + +You can use Github for example to publish the file but you should add **/raw/** +to the URI like this: +[https://github.com/<username>/<repo>/raw/master/my-first-dataset.txt.enc](https://github.com///raw/master/my-first-dataset.txt.enc) + +::: + +The file `.secrets/datasets/my-first-dataset.txt.key` is the encryption key, +make sure to back it up securely. The file `.secrets/datasets/dataset.key` is +just an "alias" in the sense that it is the key of the last encrypted dataset. + +```bash +.secrets +└── datasets + ├── dataset.key + └── my-first-dataset.txt.key +``` + +## Deploy the dataset + +Fill in the fields of the `iexec.json` file. Choose a `name` for your dataset, +put the encrypted file's URI in `multiaddr` (the URI you got after publishing +the file) and fill the `checksum` field. The `checksum` of the dataset consists +of a `0x` prefix followed by the `sha256sum` of the dataset. This `checksum` is +printed when running the `iexec dataset encrypt` command. If you missed it, you +can retrieve the `sha256sum` of the dataset by running +`sha256sum datasets/encrypted/my-first-dataset.txt.enc`. + +```bash +$ cat iexec.json +{ + "description": "My iExec ressource description...", + + ... + + "dataset": { + "owner": "0x-your-wallet-address", + "name": "Encrypted hello world dataset", + "multiaddr": "/ipfs/QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ", + "checksum": "<0x-sha256sum-of-the-dataset>" // starts with 0x + } +} +``` + +To deploy your dataset run: + +```bash +iexec dataset deploy +``` + +You will get a hexadecimal address for your deployed dataset. Use that address +to push the encryption key to the +[SMS](/get-started/protocol/tee/intel-sgx-technology) so it is available for +authorized applications. + +For simplicity, we will use the dataset with a TEE-debug app on a debug +workerpool. The debug workerpool is connected to a debug Secret Management +Service so we will send the dataset encryption key to this SMS (this is fine for +debugging but do not use to store production secrets). + +### Push the dataset secret to the SMS + +```bash +iexec dataset push-secret +``` + +### Check secret availability on the SMS + +```bash +iexec dataset check-secret +``` + +We saw in this section how to encrypt a dataset and deploy it on iExec. In +addition, we learned how to push the encryption secret to the +[SMS](/get-started/protocol/tee/intel-sgx-technology). Now we need to build the +application that is going to consume this dataset. + +## Prepare your application + +::: warning + +For demo purposes, we omitted some development best practices in these examples. + +Make sure to check your field's best practices before going to production. + +::: + +Let's create a directory tree for this app in `~/iexec-projects/`. + +```bash +cd ~/iexec-projects/tee-dataset-app +mkdir src +touch Dockerfile +touch sconify.sh +chmod +x sconify.sh +``` + +In the folder `src/` create the file `app.js` or `app.py` then copy this code +inside: + +The application reads the content of the dataset and writes it into the result's +folder: + +::: code-group + +```javascript [src/app.js] +const fsPromises = require('fs').promises; + +(async () => { + try { + const iexecOut = process.env.IEXEC_OUT; + const iexecIn = process.env.IEXEC_IN; + const datasetFileName = process.env.IEXEC_DATASET_FILENAME; + + // Use some confidential assets + let text = ''; + try { + const confidentialFile = await fsPromises.readFile( + `${iexecIn}/${datasetFileName}` + ); + text = confidentialFile.toString(); + } catch (e) { + console.log('confidential file does not exist'); + } + // Append some results + await fsPromises.writeFile(`${iexecOut}/result.txt`, text); + console.log(text); + // Declare everything is computed + const computedJsonObj = { + 'deterministic-output-path': `${iexecOut}/result.txt`, + }; + await fsPromises.writeFile( + `${iexecOut}/computed.json`, + JSON.stringify(computedJsonObj) + ); + } catch (e) { + console.log(e); + process.exit(1); + } +})(); +``` + +```python [src/app.py] +import json +import os + +iexec_out = os.environ['IEXEC_OUT'] +iexec_in = os.environ['IEXEC_IN'] +dataset_filename = os.environ['IEXEC_DATASET_FILENAME'] + +text = '' + +# Check the confidential file exists and open it +try: + dataset_file = open(iexec_in + '/' + dataset_filename, 'r') + dataset = dataset_file.read() + text = dataset +except OSError: + print('confidential file does not exists') + exit(1) + +print(text) + +# Append some results in /iexec_out/ +with open(iexec_out + '/result.txt', 'w+') as fout: + fout.write(text) + +# Declare everything is computed +with open(iexec_out + '/computed.json', 'w+') as f: + json.dump({"deterministic-output-path": iexec_out + '/result.txt'}, f) +``` + +::: + +## Build the TEE docker image + +Create the `Dockerfile` as described in +[Build your first application](./your-first-app.md#dockerize-your-app). + +Build the Docker image: + +```bash +docker build . --tag /hello-world-with-dataset:1.0.0 +``` + +Follow the steps described in +[Build Scone app > Build the TEE docker image](create-your-first-sgx-app.md#build-the-tee-docker-image). + +Update the `sconify.sh` script with the variables as follow: + +```bash +# declare related variables +IMG_NAME=tee-scone-hello-world-with-dataset +IMG_FROM=/hello-world-with-dataset:1.0.0 +IMG_TO=/${IMG_NAME}:1.0.0-debug +``` + +Run the `sconify.sh` script to build the Scone TEE application: + +```bash +./sconify.sh +``` + +```bash +docker push /tee-scone-hello-world-with-dataset:1.0.0-debug +``` + +## Test your app on iExec + +At this stage, your application is ready to be tested on iExec. + +### Deploy the TEE app on iExec + +Deploy the application as described in +[Build Scone app](create-your-first-sgx-app.md#deploy-the-tee-app-on-iexec). + +### Run the TEE app + +Specify the tag `--tag tee,scone` and the dataset to use +`--dataset ` in `iexec app run` command to run a tee app with a +dataset. + +One last thing, in order to run a **TEE-debug** app you will also need to select +a debug workerpool, use the debug workerpool +`debug-v8-learn.main.pools.iexec.eth`. + +You are now ready to run the app + +```bash +iexec app run \ + --tag tee,scone \ + --dataset \ + --workerpool debug-v8-learn.main.pools.iexec.eth \ + --watch +``` + +## Next step? + +Thanks to the explained confidential computing workflow, you now know how to use +an encrypted dataset in a Confidential Computing application. + +To go further, check out how to: + +- [Attach a secret to your app](/guides/build-iapp/build-&-deploy#application-developer-secret) +- [Access requester secrets](/guides/build-iapp/inputs-and-outputs#access-requester-secrets) +- [Protect the result](end-to-end-encryption.md) diff --git a/src/guides/build-iapp/advanced/your-first-app.md b/src/guides/build-iapp/advanced/your-first-app.md new file mode 100644 index 00000000..b12802da --- /dev/null +++ b/src/guides/build-iapp/advanced/your-first-app.md @@ -0,0 +1,425 @@ +--- +description: >- + In this section we will show you how you can create a Docker dapp over the + iExec infrastructure. +--- + +# Build your first application + +> In this section we will show you how you can create a Docker dapp over the +> iExec infrastructure. + +::: tip Prerequisites + +- [Docker](https://docs.docker.com/install/) 17.05 or higher on the daemon and + client. +- [Dockerhub](https://hub.docker.com/) account. +- [iExec SDK](https://www.npmjs.com/package/iexec) 8.0.0 or higher. + [Install the iExec SDK](quick-start-for-developers.md#install-the-iexec-sdk). +- [Quickstart](quick-start-for-developers.md) tutorial completed + +::: + +In this guide, we will prepare an iExec app based on an existing docker image +and we will run it on iExec decentralized infrastructure. + +## Understand what is an iExec decentralized application? + +iExec leverage [Docker](https://www.docker.com/why-docker) containers to ensure +the execution of your application on a decentralized infrastructure. iExec +supports Linux-based docker images. + +### Why using Docker containers? + +- Docker Engine is the most **widely used** container engine. +- A Docker container image is a **standard** unit of software that packages up + code and all its dependencies so the application runs quickly and reliably + from one computing environment to another. This allows for computations to be + **run on any worker** connected to the decentralized infrastructure. +- Docker also enables the creation of new layers on top of existing images. This + allows for any iExec **apps to be easily built on top of existing docker + images**. + +### What kind of application can I build on iExec? + +Today you can run any application as a task. This means services are not +supported for now. + +## Build your app + +Create the folder tree for your application in `~/iexec-projects/`. + +```bash +cd ~/iexec-projects +mkdir hello-world-app +cd hello-world-app +mkdir src +touch Dockerfile +``` + +### Write the app + +::: warning + +For demo purposes, we omitted some development best practices in these examples. + +Make sure to check your field's best practices before going to production. + +::: + +The following examples only feature Javascript and Python use cases for +simplicity concerns but remember that you can run on iExec anything which is +Dockerizable. + +**Copy the following content** in `src/` . + +::: code-group + +```javascript [src/app.js] +const fsPromises = require('fs').promises; + +(async () => { + try { + const iexecOut = process.env.IEXEC_OUT; + // Do whatever you want (let's write hello world here) + const message = process.argv.length > 2 ? process.argv[2] : 'World'; + + const text = `Hello, ${message}!`; + console.log(text); + // Append some results in /iexec_out/ + await fsPromises.writeFile(`${iexecOut}/result.txt`, text); + // Declare everything is computed + const computedJsonObj = { + 'deterministic-output-path': `${iexecOut}/result.txt`, + }; + await fsPromises.writeFile( + `${iexecOut}/computed.json`, + JSON.stringify(computedJsonObj) + ); + } catch (e) { + console.log(e); + process.exit(1); + } +})(); +``` + +```python [src/app.py] +import os +import sys +import json + +iexec_out = os.environ['IEXEC_OUT'] + +# Do whatever you want (let's write hello world here) +text = 'Hello, {}!'.format(sys.argv[1] if len(sys.argv) > 1 else "World") +print(text) + +# Append some results in /iexec_out/ +with open(iexec_out + '/result.txt', 'w+') as fout: + fout.write(text) + +# Declare everything is computed +with open(iexec_out + '/computed.json', 'w+') as f: + json.dump({ "deterministic-output-path" : iexec_out + '/result.txt' }, f) +``` + +::: + +::: warning + +As a developer, make it a rule to never log sensitive information in your +application. Execution logs are accessible by: + +- worker(s) involved in the task +- the workerpool manager +- the requester of the task + +::: + +### Dockerize your app + +**Copy the following content** in `Dockerfile` . + +::: code-group + +```bash [Dockerfile for JavaScript] +FROM node:22-alpine3.21 +### install your dependencies if you have some +RUN mkdir /app && cd /app +COPY ./src /app +ENTRYPOINT [ "node", "/app/app.js"] +``` + +```bash [Dockerfile for Python] +FROM python:3.13.3-alpine3.21 +### install python dependencies if you have some +COPY ./src /app +ENTRYPOINT ["python3", "/app/app.py"] +``` + +::: + +Build the docker image. + +::: warning + +iExec expects your Docker container to be built for the `linux/amd64` platform. +However, if you develop on a **Mac** with Apple **M processor**, the platform is +`linux/arm64`, which is different. To prepare your application, you will need to +install `buildkit` and then prepare your docker image for both platforms. + +```bash +brew install buildkit +# ARM64 variant for local testing only +docker buildx build --platform linux/arm64 --tag /hello-world . +# AMD64 variant to deploy on iExec +docker buildx build --platform linux/amd64 --tag /hello-world . +``` + +::: + +```bash +docker build --tag hello-world . +``` + +::: tip + +`docker build` produce an image id, using `--tag ` option is a convenient +way to name the image to reuse it in the next steps. + +::: + +**Congratulations you built your first docker image for iExec!** + +## Test your app locally + +### Basic test + +Create local volumes to simulate input and output directories. + +```bash +mkdir -p ./tmp/iexec_in +mkdir -p ./tmp/iexec_out +``` + +Run your application locally \(container volumes bound with local volumes\). + +```bash +docker run --rm \ + -v ./tmp/iexec_in:/iexec_in \ + -v ./tmp/iexec_out:/iexec_out \ + -e IEXEC_IN=/iexec_in \ + -e IEXEC_OUT=/iexec_out \ + hello-world arg1 arg2 arg3 +``` + +::: tip Docker run \[options\] image \[args\] + +**docker run usage:** + +`docker run [OPTIONS] IMAGE [COMMAND] [ARGS...]` + +Use `[COMMAND]` and `[ARGS...]` to simulate the requester arguments + +**useful options for iExec:** + +`-v` : Bind mount a volume. Use it to bind input and output directories +(`/iexec_in` and `/iexec_out`) + +`-e`: Set environnement variable. Use it to simulate iExec Runtime variables + +::: + +### Test with input files + +Starting with the basic test you can simulate input files. + +For each input file: + +- Copy it in the local volume bound to `/iexec_in` . +- Add `-e IEXEC_INPUT_FILE_NAME_x=NAME` to docker run options \(`x` is the index + of the file starting by 1 and `NAME` is the name of the file\) + +Add `-e IEXEC_INPUT_FILES_NUMBER=n` to docker run options \(`n` is the total +number of input files\). + +Example with two inputs files: + +```bash +touch ./tmp/iexec_in/file1 && \ +touch ./tmp/iexec_in/file2 && \ +docker run \ + -v ./tmp/iexec_in:/iexec_in \ + -v ./tmp/iexec_out:/iexec_out \ + -e IEXEC_IN=/iexec_in \ + -e IEXEC_OUT=/iexec_out \ + -e IEXEC_INPUT_FILE_NAME_1=file1 \ + -e IEXEC_INPUT_FILE_NAME_2=file2 \ + -e IEXEC_INPUT_FILES_NUMBER=2 \ + hello-world \ + arg1 arg2 arg3 +``` + +## Test your app on iExec + +### Push your app to Dockerhub + +Login to your Dockerhub account. + +```bash +docker login +``` + +Tag your application image to push it to your dockerhub public repository. + +```bash +docker tag hello-world /hello-world:1.0.0 +``` + +::: warning + +replace `` with your docker user name + +::: + +Push the image to Dockerhub. + +```bash +docker push /hello-world:1.0.0 +``` + +**Congratulations, your app is ready to be deployed on iExec!** + +### Deploy your app on iExec + +You already learned how to deploy the default app on iExec in the +[previous tutorial](quick-start-for-developers.md). + +Go back to the `iexec-project` folder. + +```bash +cd ~/iexec-projects/ +``` + +You will need a few configurations in `iexec.json` to deploy your app: + +- Replace app **name** with your application name \(display only\) +- Replace app **multiaddr** with your app image download URI \(should looks like + `docker.io//hello-world:1.0.0`\) +- Replace app **checksum** with your application image checksum \(see tip + below\) + +::: info + +The checksum of your app is the sha256 digest of the docker image prefixed with +`0x` , you can use the following command to get it. + +```bash +docker pull /hello-world:1.0.0 | grep "Digest: sha256:" | sed 's/.*sha256:/0x/' +``` + +::: + +Deploy your app on iExec + +```bash +iexec app deploy +``` + +Verify the deployed app \(name, multiaddr, checksum, owner\) + +```bash +iexec app show +``` + +### Run your app on iExec + +```bash +iexec app run --workerpool debug-v8-learn.main.pools.iexec.eth --watch +``` + +::: info + +**Using arguments:** + +You can pass arguments to the app using `--args ` option. + +With `--args "dostuff --with-option"` the app will receive +`["dostuff", "--with-option"]` as process args. + +**Using input files:** + +You can pass input files to the app using `--input-files ` option. + +With +`--input-files https://example.com/file-A.txt,https://example.com/file-B.zip` +the iExec worker will download the files before running the app in `IEXEC_IN`, +and let the app access them throug variables: + +- `file-A.txt` as`IEXEC_INPUT_FILE_NAME_1` +- `file-B.zip` as`IEXEC_INPUT_FILE_NAME_2` + +::: + +Once the run is completed copy the taskid from `iexec app run` output to +download and check the result + +```bash +iexec task show --download my-app-result \ + && unzip my-app-result.zip -d my-app-result +``` + +**Congratulations your app successfully ran on iExec!** + +## Manage your app's output + +iExec enables running apps producing output files, you will need a place for +storing your apps outputs. + +::: info + +iExec provides a default storage solution based on [IPFS](https://ipfs.io/). +This solution ensures your result to be publicly accessible through a +decentralized network. + +To ensure your business data remains secure and private, iExec offers optional +RSA result encryption and the ability to push results to private storage +providers. For more information, refer to `iexec storage --help` and +the[iExec SDK](https://github.com/iExecBlockchainComputing/iexec-sdk). + +::: + +## Access to app and task logs on iExec + +Sometimes things don't work out right the first time and you may need to +[Debug your tasks](/guides/build-iapp/debugging). + +## Publish your app on the iExec marketplace + +```bash +iexec app publish +``` + +**Congratulations your application is now available on iExec!** + +## What's next? + +In this tutorial you learned about the key concepts for building an app on +iExec: + +- iExec app inputs and outputs +- iExec app must produce a `computed.json` file \(required for the proof of + execution\) +- using docker to package your app with all its dependencies +- testing an iExec app locally +- publishing on dockerhub + +Resources: + +- A list of iExec applications with their Docker images can be found at + [https://github.com/iExecBlockchainComputing/iexec-apps](https://github.com/iExecBlockchainComputing/iexec-apps) + +Continue with these articles: + +- [Confidential app](/guides/build-iapp/build-&-deploy#confidential-app) +- [Learn how to manage your apporders](/guides/build-iapp/build-&-deploy#manage-your-apporders) diff --git a/src/guides/build-iapp/index.md b/src/guides/build-iapp/index.md index b9fc823a..c488ba73 100644 --- a/src/guides/build-iapp/index.md +++ b/src/guides/build-iapp/index.md @@ -29,6 +29,11 @@ creating, testing, and deploying confidential iApps. - **[Using TDX (Experimental)](/guides/build-iapp/using-tdx)** - Next-gen TEE technology +## ⚙️ Advanced iApp Building + +- **[Advanced Overview](/guides/build-iapp/advanced/overview)** - Deep dive: + Docker, SGX/TDX, SCONE/Gramine, datasets & E2E + ## 📚 What's Next? After mastering these guides, explore: