diff --git a/.gitattributes b/.gitattributes
index 526c8a38..19956fce 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,4 @@
-*.sh text eol=lf
\ No newline at end of file
+*.sh text eol=lf
+# Built by website/graph-viz/build.mjs: minified and obfuscated, never hand-edited.
+website/static/graph-viz/** linguist-generated -diff
+website/src/data/graphViz.js linguist-generated
diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index d0bb3933..80a94030 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -211,6 +211,10 @@ const config = {
}),
stylesheets: [
+ {
+ href: 'https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@100&display=swap',
+ type: 'text/css',
+ },
{
href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css',
type: 'text/css',
diff --git a/website/graph-viz/build.mjs b/website/graph-viz/build.mjs
new file mode 100644
index 00000000..e4664dab
--- /dev/null
+++ b/website/graph-viz/build.mjs
@@ -0,0 +1,281 @@
+#!/usr/bin/env node
+// Builds the landing page's graph widget (entry.jsx) into static/graph-viz/.
+//
+// panorama, the graph library, is private: the docs CI cannot install it, so
+// this runs locally against a checkout and its output is committed. The
+// build tools come from that checkout's node_modules (run `npm install`
+// there first); only the obfuscator, an EBA concern, is the website's own.
+//
+// cd website
+// PANORAMA_DIR=../../panorama node graph-viz/build.mjs
+//
+// Nothing readable of panorama ships:
+// - no source maps;
+// - its GLSL shaders lose their comments and layout before bundling;
+// - third-party libraries are split into vendor-* chunks, and every other
+// chunk (panorama and entry.jsx only) is obfuscated, which also encodes its
+// strings, shaders included;
+// - chunk names are bare hashes, so file names don't mirror panorama's modules.
+// Vendor chunks stay as their libraries publish them, with their licences in
+// THIRD_PARTY_LICENSES.txt. Code that runs in a browser can always be
+// reverse-engineered with effort; this makes that effort substantial.
+import { execFileSync } from "node:child_process";
+import { createHash } from "node:crypto";
+import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
+import { createRequire } from "node:module";
+import { dirname, join, resolve, sep } from "node:path";
+import { fileURLToPath } from "node:url";
+import JavaScriptObfuscator from "javascript-obfuscator";
+
+const here = dirname(fileURLToPath(import.meta.url));
+const outDir = resolve(here, "../static/graph-viz");
+// File names are content-hashed so browsers never run a stale build; the
+// page learns the current names from this generated module.
+const manifestPath = resolve(here, "../src/data/graphViz.js");
+const SCOPE = ".eba-graph";
+
+const fail = (msg) => {
+ console.error(`graph-viz: ${msg}`);
+ process.exit(1);
+};
+
+if (!process.env.PANORAMA_DIR) fail("set PANORAMA_DIR to a local panorama checkout.");
+const panoramaDir = resolve(process.env.PANORAMA_DIR);
+if (!existsSync(join(panoramaDir, "node_modules"))) fail(`${panoramaDir} has no node_modules; run \`npm install\` there.`);
+
+const req = createRequire(join(panoramaDir, "package.json"));
+const { build } = req("vite");
+const react = req("@vitejs/plugin-react").default;
+const { compile, optimize } = req("@tailwindcss/node");
+const { Scanner } = req("@tailwindcss/oxide");
+const postcss = req("postcss");
+
+// The panorama commit this build came from, so it can be reproduced.
+const git = (...args) => execFileSync("git", ["-C", panoramaDir, ...args], { encoding: "utf8" }).trim();
+const panorama = { commit: git("rev-parse", "HEAD"), dirty: git("status", "--porcelain").length > 0 };
+if (panorama.dirty) console.warn("graph-viz: warning: panorama has uncommitted changes; this build cannot be reproduced from its commit.");
+
+// ------------------------------------------------------------------ GLSL
+
+/** Strips comments and layout from GLSL; preprocessor lines keep their own line. */
+function minifyGlsl(text) {
+ const lines = text
+ .replace(/\/\*[\s\S]*?\*\//g, "")
+ .replace(/\/\/[^\n]*/g, "")
+ .split("\n")
+ .map((l) => l.trim().replace(/\s+/g, " "))
+ .filter(Boolean);
+ let out = "";
+ for (const line of lines) {
+ if (line.startsWith("#")) out += (out && !out.endsWith("\n") ? "\n" : "") + line + "\n";
+ else out += (out && !out.endsWith("\n") ? " " : "") + line;
+ }
+ // An interpolation next to this part may hold a preprocessor line.
+ return (/^\s*\n/.test(text) ? "\n" : "") + out + (/\n\s*$/.test(text) ? "\n" : "");
+}
+
+/** Minifies every `/* glsl *\/` template literal; ${...} interpolations are kept as written. */
+function minifyGlslTemplates(code) {
+ const tag = /\/\*\s*glsl\s*\*\/\s*`/g;
+ let out = "";
+ let last = 0;
+ for (let m; (m = tag.exec(code)); ) {
+ let i = m.index + m[0].length;
+ out += code.slice(last, i);
+ let part = "";
+ for (;;) {
+ const c = code[i];
+ if (c === undefined) throw new Error("unterminated glsl template");
+ if (c === "\\") {
+ part += code.slice(i, i + 2);
+ i += 2;
+ } else if (c === "`") {
+ out += minifyGlsl(part) + "`";
+ i++;
+ break;
+ } else if (c === "$" && code[i + 1] === "{") {
+ let depth = 0;
+ let j = i + 1;
+ do {
+ if (code[j] === "{") depth++;
+ else if (code[j] === "}") depth--;
+ j++;
+ } while (depth > 0);
+ out += minifyGlsl(part) + code.slice(i, j);
+ part = "";
+ i = j;
+ } else {
+ part += c;
+ i++;
+ }
+ }
+ last = tag.lastIndex = i;
+ }
+ return out + code.slice(last);
+}
+
+const panoramaSrc = join(panoramaDir, "src") + sep;
+const glslPlugin = {
+ name: "eba-glsl-minify",
+ enforce: "pre",
+ transform(code, id) {
+ if (!resolve(id.split("?")[0]).startsWith(panoramaSrc) || !code.includes("glsl")) return null;
+ return { code: minifyGlslTemplates(code), map: null };
+ },
+};
+
+// ------------------------------------------------------- vendor & licences
+
+const packageOf = (id) => id.replaceAll("\\", "/").match(/\/node_modules\/((?:@[^/]+\/)?[^/]+)\//)?.[1] ?? null;
+
+// Libraries are grouped by when they load: the UI's with the page, the 3D
+// renderer's and the icon set's on demand. The rest are the 2D renderer's,
+// which loads only if a visitor switches to it. A new eager dependency of
+// panorama belongs in "ui", or the 2D libraries start loading with the page.
+const VENDOR_GROUPS = [
+ { name: "vendor-react", test: /^(react|react-dom|scheduler)$/ },
+ { name: "vendor-ui", test: /^(zustand|lucide-react|@radix-ui\/.*)$/ },
+ { name: "vendor-three", test: /^(three|camera-controls|postprocessing)$/ },
+ { name: "vendor-icons", test: /^lucide$/ },
+ { name: "vendor-2d", test: /./ },
+].map(({ name, test }) => ({ name, test: (id) => test.test(packageOf(id) ?? "") }));
+
+const author = (meta) => (typeof meta.author === "string" ? meta.author : meta.author?.name);
+
+/** Each bundled package's licence, as its own LICENSE file states it. */
+function thirdPartyLicenses(moduleIds) {
+ const packages = new Map();
+ for (const id of moduleIds) {
+ const pkg = packageOf(id);
+ if (!pkg || packages.has(pkg)) continue;
+ const norm = id.replaceAll("\\", "/");
+ const dir = norm.slice(0, norm.lastIndexOf(`/node_modules/${pkg}/`) + `/node_modules/${pkg}`.length);
+ const meta = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
+ const file = readdirSync(dir).find((f) => /^(licen[cs]e|copying)(\.|$)/i.test(f));
+ packages.set(pkg, { meta, text: file ? readFileSync(join(dir, file), "utf8").trim() : null });
+ }
+ const sections = [...packages.entries()]
+ .sort(([a], [b]) => a.localeCompare(b))
+ .map(([name, { meta, text }]) => {
+ const head = `${name}@${meta.version} (${meta.license ?? "see below"})`;
+ return `${head}\n${"-".repeat(head.length)}\n${text ?? `No licence file shipped. package.json declares ${meta.license}${author(meta) ? `, author ${author(meta)}` : ""}.`}\n`;
+ });
+ return `Third-party software bundled in the EBA graph widget.\n\n${sections.join("\n")}`;
+}
+
+// ------------------------------------------------------------ obfuscation
+
+const OBFUSCATION = {
+ compact: true,
+ // Fixed so an unchanged input rebuilds to the same files.
+ seed: 0x5eed,
+ identifierNamesGenerator: "mangled-shuffled",
+ stringArray: true,
+ stringArrayEncoding: ["base64"],
+ stringArrayThreshold: 1,
+ stringArrayRotate: true,
+ stringArrayShuffle: true,
+ stringArrayIndexShift: true,
+ stringArrayWrappersCount: 2,
+ stringArrayWrappersType: "function",
+ // Off: they slow the render loop or break module exports.
+ controlFlowFlattening: false,
+ deadCodeInjection: false,
+ renameGlobals: false,
+ selfDefending: false,
+ debugProtection: false,
+ transformObjectKeys: true,
+ sourceMap: false,
+ target: "browser",
+ reservedStrings: ["!~\{", "\.js$"],
+};
+
+const obfuscate = (code) => JavaScriptObfuscator.obfuscate(code, OBFUSCATION).getObfuscatedCode();
+
+const licenseIds = new Set();
+// Runs in renderChunk, before file names are hashed, so a name changes
+// whenever the shipped code does. Import paths stay literal: at this point
+// they hold the bundler's hash placeholders (!~{001}~), which it rewrites later.
+const obfuscatePlugin = {
+ name: "eba-obfuscate",
+ renderChunk(code, chunk) {
+ for (const id of chunk.moduleIds) licenseIds.add(id);
+ const vendor = chunk.moduleIds.filter(packageOf);
+ if (vendor.length === chunk.moduleIds.length && vendor.length > 0) return null;
+ if (vendor.length > 0)
+ fail(`chunk ${chunk.fileName} mixes panorama and third-party code: ${[...new Set(vendor.map(packageOf))].join(", ")}`);
+ return { code: obfuscate(code), map: null };
+ },
+};
+
+// ----------------------------------------------------------------- build
+
+const result = await build({
+ configFile: false,
+ root: here,
+ base: "./",
+ logLevel: "warn",
+ plugins: [glslPlugin, react(), obfuscatePlugin],
+ resolve: {
+ alias: { panorama: join(panoramaDir, "src/index.ts") },
+ dedupe: ["react", "react-dom"],
+ },
+ worker: {
+ format: "iife",
+ plugins: () => [glslPlugin, obfuscatePlugin],
+ rolldownOptions: { output: { entryFileNames: "assets/[hash].js" } },
+ },
+ build: {
+ outDir,
+ emptyOutDir: true,
+ sourcemap: false,
+ modulePreload: false,
+ target: "es2022",
+ chunkSizeWarningLimit: 1024,
+ rolldownOptions: {
+ input: { "graph-viz": join(here, "entry.jsx") },
+ preserveEntrySignatures: "exports-only",
+ output: {
+ format: "es",
+ entryFileNames: "[name]-[hash].js",
+ // Vendor chunks keep their library's name; panorama's are bare hashes.
+ chunkFileNames: (chunk) => (chunk.name.startsWith("vendor-") ? "chunks/[name]-[hash].js" : "chunks/[hash].js"),
+ assetFileNames: "assets/[hash][extname]",
+ comments: { legal: false },
+ codeSplitting: { groups: VENDOR_GROUPS },
+ },
+ },
+ },
+});
+
+// panorama styles itself with Tailwind classes. The CSS is generated here,
+// then scoped under SCOPE and taken out of cascade layers: the site's own
+// unlayered CSS would otherwise beat every layered rule.
+const source = `@import "tailwindcss" source(none);\n@source "${join(panoramaDir, "src").replaceAll("\\", "/")}";\n`;
+const compiler = await compile(source, { base: panoramaDir, onDependency: () => {} });
+const scanner = new Scanner({ sources: compiler.sources });
+const generated = optimize(compiler.build(scanner.scan()), { minify: false }).code;
+
+const scopeSelector = (sel) => (/^(:root|:host|html|body)$/.test(sel.trim()) ? SCOPE : `${SCOPE} ${sel.trim()}`);
+const scoped = postcss([
+ {
+ postcssPlugin: "eba-graph-scope",
+ Once(root) {
+ root.walkAtRules("layer", (at) => (at.nodes ? at.replaceWith(at.nodes) : at.remove()));
+ root.walkRules((rule) => {
+ if (rule.parent?.type === "atrule" && /keyframes$/.test(rule.parent.name)) return;
+ rule.selectors = [...new Set(rule.selectors.map(scopeSelector))];
+ });
+ },
+ },
+]).process(generated, { from: undefined }).css;
+
+const css = optimize(scoped, { minify: true }).code;
+const style = `graph-viz-${createHash("sha256").update(css).digest("base64url").slice(0, 8)}.css`;
+writeFileSync(join(outDir, style), css);
+
+writeFileSync(join(outDir, "THIRD_PARTY_LICENSES.txt"), thirdPartyLicenses(licenseIds));
+
+const script = [result].flat().flatMap((r) => r.output).find((o) => o.type === "chunk" && o.isEntry).fileName;
+writeFileSync(manifestPath, `// Generated by graph-viz/build.mjs.\nexport default ${JSON.stringify({ script, style, panorama }, null, 2)};\n`);
+console.log(`graph-viz: built ${script} and ${style} into ${outDir} from panorama ${panorama.commit.slice(0, 7)}${panorama.dirty ? " (dirty)" : ""}`);
diff --git a/website/graph-viz/entry.jsx b/website/graph-viz/entry.jsx
new file mode 100644
index 00000000..8ebb83c6
--- /dev/null
+++ b/website/graph-viz/entry.jsx
@@ -0,0 +1,113 @@
+// The landing page's live graph: a static EBA sample drawn with panorama.
+// Built by build.mjs into static/graph-viz/; the page calls mount() at runtime.
+import { StrictMode, useEffect } from "react";
+import { createRoot } from "react-dom/client";
+import { GraphViz, PanoramaProvider, buildGraphDoc, useScene } from "panorama";
+
+// The landing page's look, passed to panorama as its starting defaults.
+// Only what differs from panorama's own defaults is listed here.
+const HOP_SHELLS_OPTIONS = {
+ nodes: { labelBudget: 0 },
+ edges: { scheduler: "height-ordered" },
+ // Draws the graph right of centre, leaving the left for the page's overlay text.
+ camera: { offsetX: 0.18 },
+ effects: { background: "#000000" },
+ // "auto" visibility draws only the outermost shell, so these are switched on.
+ hops: { 0: { visible: "on", opacity: 0.25 }, 1: { visible: "on", opacity: 0.1 } },
+};
+
+const CONFIG = {
+ storageKey: "eba-landing-graph",
+ // Every visit starts from these defaults; a visitor's tweaks last until reload.
+ persist: false,
+ defaultRenderer: "hop-shells-3d",
+ defaultRendererOptions: { "hop-shells-3d": HOP_SHELLS_OPTIONS },
+ nodeStyles: {
+ script: { color: "#3b82f6", shape: "sphere", icon: "wallet" },
+ tx: { color: "#f59e0b", shape: "octahedron", icon: "arrow-left-right" },
+ block: { color: "#8b5cf6", shape: "cube", icon: "box" },
+ },
+ formatValue: (sats) => `${(sats / 1e8).toLocaleString(undefined, { maximumFractionDigits: 8 })} BTC`,
+};
+
+const TYPES = {
+ block: { label: "Block", key: "Height", key_type: "integer", caption: "Height" },
+ tx: { label: "Tx", key: "Txid", key_type: "string", caption: "Txid" },
+ script: { label: "Script", key: "SHA256Hash", key_type: "string", caption: "Address" },
+};
+
+// The sample is the whole graph: nothing to fetch, nothing expands.
+const SCENE_OPTIONS = {
+ fetcher: { expand: async () => ({ doc: null, hasMore: false }) },
+ canExpand: () => false,
+};
+
+function propertyNames(items) {
+ const byType = new Map();
+ for (const item of items) {
+ const names = byType.get(item.type) ?? new Set();
+ for (const k of Object.keys(item.props ?? {})) names.add(k);
+ byType.set(item.type, names);
+ }
+ return byType;
+}
+
+function schemaOf(doc) {
+ return {
+ node_types: [...propertyNames(doc.nodes)].map(([type, names]) => {
+ const t = TYPES[type] ?? { label: type, key: "id", key_type: "string", caption: "id" };
+ return { type, ...t, lookup: [t.key], properties: [...names].filter((n) => n !== t.key) };
+ }),
+ relationship_types: [...propertyNames(doc.edges)].map(([type, names]) => ({ type, properties: [...names] })),
+ semantics: { edge_value: "Value", edge_height: "Height", node_height: "Height" },
+ identities: {},
+ limits: {
+ expand_per_direction: 0,
+ expand_max: 0,
+ query_default: 0,
+ query_max: 0,
+ lookup_max: 0,
+ pattern_max_hops: 0,
+ max_response_elements: doc.nodes.length + doc.edges.length,
+ },
+ loaded_at: "",
+ };
+}
+
+function Graph({ doc, roots, schema }) {
+ const scene = useScene(SCENE_OPTIONS, schema);
+ useEffect(() => {
+ if (scene.getState().revision === 0) scene.getState().seed(doc, roots);
+ }, [scene, doc, roots]);
+ return ;
+}
+
+/** Draws the graph at dataUrl into el; resolves to a function that removes it. */
+export async function mount(el, { dataUrl }) {
+ const res = await fetch(dataUrl);
+ if (!res.ok) throw new Error(`${dataUrl}: HTTP ${res.status}`);
+ const payload = await res.json();
+ const doc = buildGraphDoc(payload);
+ if (!doc) throw new Error(`${dataUrl}: no graph data`);
+ const roots = Array.isArray(payload.roots) ? payload.roots : [];
+ // The graph sits in the page, so the plain wheel scrolls the page and only
+ // ctrl+wheel (or a trackpad pinch, which sets ctrlKey) reaches the graph to
+ // zoom. Stopped while capturing, before the graph's own listeners see it;
+ // without preventDefault the browser still scrolls. Panels keep scrolling.
+ const onWheel = (e) => {
+ if (!e.ctrlKey && e.target instanceof HTMLCanvasElement) e.stopPropagation();
+ };
+ el.addEventListener("wheel", onWheel, { capture: true });
+ const root = createRoot(el);
+ root.render(
+
+
+
+
+ ,
+ );
+ return () => {
+ root.unmount();
+ el.removeEventListener("wheel", onWheel, { capture: true });
+ };
+}
diff --git a/website/package-lock.json b/website/package-lock.json
index 995c64af..fb6e448d 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -28,7 +28,8 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.9.2",
- "@docusaurus/types": "^3.9.2"
+ "@docusaurus/types": "^3.9.2",
+ "javascript-obfuscator": "^5.8.1"
},
"engines": {
"node": ">=18.0"
@@ -4169,6 +4170,108 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@inversifyjs/common": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/@inversifyjs/common/-/common-1.5.2.tgz",
+ "integrity": "sha512-WlzR9xGadABS9gtgZQ+luoZ8V6qm4Ii6RQfcfC9Ho2SOlE6ZuemFo7PKJvKI0ikm8cmKbU8hw5UK6E4qovH21w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@inversifyjs/container": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/@inversifyjs/container/-/container-1.15.0.tgz",
+ "integrity": "sha512-U2xYsPrJTz5za2TExi5lg8qOWf8TEVBpN+pQM7B8BVA2rajtbRE9A66SLRHk8c1eGXmg+0K4Hdki6tWAsSQBUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inversifyjs/common": "1.5.2",
+ "@inversifyjs/core": "9.2.0",
+ "@inversifyjs/plugin": "0.2.0",
+ "@inversifyjs/reflect-metadata-utils": "1.4.1"
+ },
+ "peerDependencies": {
+ "reflect-metadata": "~0.2.2"
+ }
+ },
+ "node_modules/@inversifyjs/core": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/@inversifyjs/core/-/core-9.2.0.tgz",
+ "integrity": "sha512-Nm7BR6KmpgshIHpVQWuEDehqRVb6GBm8LFEuhc2s4kSZWrArZ15RmXQzROLk4m+hkj4kMXgvMm5Qbopot/D6Sg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inversifyjs/common": "1.5.2",
+ "@inversifyjs/prototype-utils": "0.1.3",
+ "@inversifyjs/reflect-metadata-utils": "1.4.1"
+ }
+ },
+ "node_modules/@inversifyjs/plugin": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@inversifyjs/plugin/-/plugin-0.2.0.tgz",
+ "integrity": "sha512-R/JAdkTSD819pV1zi0HP54mWHyX+H2m8SxldXRgPQarS3ySV4KPyRdosWcfB8Se0JJZWZLHYiUNiS6JvMWSPjw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@inversifyjs/prototype-utils": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@inversifyjs/prototype-utils/-/prototype-utils-0.1.3.tgz",
+ "integrity": "sha512-EzRamZzNgE9Sn3QtZ8NncNa2lpPMZfspqbK6BWFguWnOpK8ymp2TUuH46ruFHZhrHKnknPd7fG22ZV7iF517TQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inversifyjs/common": "1.5.2"
+ }
+ },
+ "node_modules/@inversifyjs/reflect-metadata-utils": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@inversifyjs/reflect-metadata-utils/-/reflect-metadata-utils-1.4.1.tgz",
+ "integrity": "sha512-Cp77C4d2wLaHXiUB7iH6Cxb7i1lD/YDuTIHLTDzKINqGSz0DCSoL/Dg2wVkW/6Qx03r/yQMLJ+32Agl32N2X8g==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "reflect-metadata": "~0.2.2"
+ }
+ },
+ "node_modules/@javascript-obfuscator/escodegen": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@javascript-obfuscator/escodegen/-/escodegen-2.4.2.tgz",
+ "integrity": "sha512-3N7EUdYxuldwvtOtZIlAxNwPW1qTUFwWt3PxNkik6hB1uSSXLXj9JMlSyUbTCXK3Osjn0Nu0s/aa4mbvkGouXQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@javascript-obfuscator/estraverse": "^5.3.0",
+ "esprima": "^4.0.1",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/@javascript-obfuscator/escodegen/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@javascript-obfuscator/estraverse": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/@javascript-obfuscator/estraverse/-/estraverse-5.4.0.tgz",
+ "integrity": "sha512-CZFX7UZVN9VopGbjTx4UXaXsi9ewoM1buL0kY7j1ftYdSs7p2spv9opxFjHlQ/QGTgh4UqufYqJJ0WKLml7b6w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/@jest/schemas": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
@@ -5317,6 +5420,13 @@
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"license": "MIT"
},
+ "node_modules/@types/minimatch": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
@@ -5477,6 +5587,13 @@
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
+ "node_modules/@types/validator": {
+ "version": "13.15.10",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz",
+ "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
@@ -5507,6 +5624,63 @@
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
"license": "ISC"
},
+ "node_modules/@vercel/blob": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/@vercel/blob/-/blob-2.8.0.tgz",
+ "integrity": "sha512-Nu+HWKpkgovCh/ezlG7wCVwF7RErTzLzZMbGKFBdGBCbTKyK+s5VXPLl+0+TpNEQPH8AVaGzOpIsXUOtkqylCQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@vercel/oidc": "^3.6.1",
+ "async-retry": "^1.3.3",
+ "is-buffer": "^2.0.5",
+ "is-node-process": "^1.2.0",
+ "throttleit": "^2.1.0",
+ "undici": "^6.23.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@vercel/cli-config": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@vercel/cli-config/-/cli-config-0.3.1.tgz",
+ "integrity": "sha512-sISbygqlFXYb8qfPu/+2Cf/A8IjrlAuZePdag3EDQr2PRA455s7UZtl9Ro674CWsB/saBRmz3jEkw0YsQs8OoQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "xdg-app-paths": "5",
+ "zod": "4.1.11"
+ }
+ },
+ "node_modules/@vercel/cli-exec": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@vercel/cli-exec/-/cli-exec-1.0.1.tgz",
+ "integrity": "sha512-g9XerViJ/paZujufXYcu5XYI2vU2rtB4sgdpjUHde5RnOkdmpu0ngH46LCFGHoPXO/C+qDPSczIHIRN+8Q2YKQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "execa": "5.1.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/@vercel/oidc": {
+ "version": "3.8.10",
+ "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.8.10.tgz",
+ "integrity": "sha512-sPw1kIfQEA6/2dB+zlAJHnhhNBRJ8t/t4HfFvKO+g0EPBA7NbCKyGovuhgAV6Mnl865ka7HqCEguIy596czdAw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@vercel/cli-config": "0.3.1",
+ "@vercel/cli-exec": "1.0.1",
+ "jose": "^5.9.6"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
@@ -5721,6 +5895,16 @@
"node": ">=0.4.0"
}
},
+ "node_modules/acorn-import-attributes": {
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
+ "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^8"
+ }
+ },
"node_modules/acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -5965,6 +6149,16 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
+ "node_modules/array-differ": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
+ "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -5980,6 +6174,30 @@
"node": ">=8"
}
},
+ "node_modules/arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/assert": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
+ "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "is-nan": "^1.3.2",
+ "object-is": "^1.1.5",
+ "object.assign": "^4.1.4",
+ "util": "^0.12.5"
+ }
+ },
"node_modules/astring": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
@@ -5989,6 +6207,16 @@
"astring": "bin/astring"
}
},
+ "node_modules/async-retry": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz",
+ "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "retry": "0.13.1"
+ }
+ },
"node_modules/autoprefixer": {
"version": "10.4.22",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz",
@@ -6026,6 +6254,22 @@
"postcss": "^8.1.0"
}
},
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/babel-loader": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz",
@@ -6352,14 +6596,14 @@
}
},
"node_modules/call-bind": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
- "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
+ "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
"license": "MIT",
"dependencies": {
- "call-bind-apply-helpers": "^1.0.0",
- "es-define-property": "^1.0.0",
- "get-intrinsic": "^1.2.4",
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "get-intrinsic": "^1.3.0",
"set-function-length": "^1.2.2"
},
"engines": {
@@ -6487,6 +6731,13 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chance": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.13.tgz",
+ "integrity": "sha512-V6lQCljcLznE7tUYUM9EOAnnKXbctE6j/rdQkYOHIWbfGQbrzTsAXNW9CdU5XCo4ArXQCj/rb6HgxPlmGJcaUg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/char-regex": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
@@ -6536,6 +6787,16 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/cheerio": {
"version": "1.0.0-rc.12",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
@@ -6649,6 +6910,18 @@
"node": ">=8"
}
},
+ "node_modules/class-validator": {
+ "version": "0.14.3",
+ "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz",
+ "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/validator": "^13.15.3",
+ "libphonenumber-js": "^1.11.1",
+ "validator": "^13.15.20"
+ }
+ },
"node_modules/clean-css": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
@@ -7141,6 +7414,16 @@
"node": ">= 8"
}
},
+ "node_modules/crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/crypto-random-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz",
@@ -8187,6 +8470,13 @@
"node": ">=4.0.0"
}
},
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -8583,6 +8873,22 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/env-paths": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz",
+ "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-safe-filename": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/error-ex": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
@@ -8712,6 +9018,19 @@
"node": ">=8.0.0"
}
},
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -9078,6 +9397,13 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"license": "MIT"
},
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/fast-uri": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
@@ -9340,6 +9666,22 @@
}
}
},
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/form-data-encoder": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
@@ -9425,6 +9767,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/generator-function": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+ "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -9725,6 +10077,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-yarn": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz",
@@ -10466,6 +10834,18 @@
"loose-envify": "^1.0.0"
}
},
+ "node_modules/inversify": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/inversify/-/inversify-7.11.0.tgz",
+ "integrity": "sha512-yZDprSSr8TyVeMGI/AOV4ws6gwjX22hj9Z8/oHAVpJORY6WRFTcUzhnZtibBUHEw2U8ArvHcR+i863DplQ3Cwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inversifyjs/common": "1.5.2",
+ "@inversifyjs/container": "1.15.0",
+ "@inversifyjs/core": "9.2.0"
+ }
+ },
"node_modules/ipaddr.js": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
@@ -10499,6 +10879,23 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/is-arguments": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
+ "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -10517,6 +10914,43 @@
"node": ">=8"
}
},
+ "node_modules/is-buffer": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-ci": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
@@ -10596,6 +11030,26 @@
"node": ">=8"
}
},
+ "node_modules/is-generator-function": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+ "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "generator-function": "^2.0.0",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -10667,6 +11121,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-nan": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
+ "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-network-error": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz",
@@ -10679,6 +11150,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-node-process": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
+ "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/is-npm": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz",
@@ -10742,6 +11220,25 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-regexp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
@@ -10751,6 +11248,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-safe-filename": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz",
+ "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -10763,6 +11273,22 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -10811,6 +11337,81 @@
"node": ">=0.10.0"
}
},
+ "node_modules/javascript-obfuscator": {
+ "version": "5.8.1",
+ "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-5.8.1.tgz",
+ "integrity": "sha512-ixwFAYb+H8QTxO7v8lk5Od1F2szqoYQHbYpTFZUDJJZaNSWhXgMyoI88fGybCylxkbVvH3ZSzmPNsi+jYI98ew==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@javascript-obfuscator/escodegen": "2.4.2",
+ "@javascript-obfuscator/estraverse": "5.4.0",
+ "@vercel/blob": ">=0.23.0",
+ "acorn": "8.15.0",
+ "acorn-import-attributes": "^1.9.5",
+ "assert": "2.1.0",
+ "chalk": "4.1.2",
+ "chance": "1.1.13",
+ "class-validator": "0.14.3",
+ "commander": "12.1.0",
+ "env-paths": "4.0.0",
+ "eslint-scope": "8.4.0",
+ "eslint-visitor-keys": "4.2.1",
+ "fast-deep-equal": "3.1.3",
+ "inversify": "7.11.0",
+ "js-string-escape": "1.0.1",
+ "md5": "2.3.0",
+ "multimatch": "5.0.0",
+ "process": "0.11.10",
+ "reflect-metadata": "0.2.2",
+ "string-template": "1.0.0",
+ "stringz": "2.1.0",
+ "tslib": "2.8.1"
+ },
+ "bin": {
+ "javascript-obfuscator": "bin/javascript-obfuscator"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/javascript-obfuscator/node_modules/commander": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
+ "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/javascript-obfuscator/node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/javascript-obfuscator/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/jest-util": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
@@ -10880,6 +11481,26 @@
"@sideway/pinpoint": "^2.0.0"
}
},
+ "node_modules/jose": {
+ "version": "5.10.0",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
+ "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/js-string-escape": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
+ "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -11071,6 +11692,27 @@
"node": ">=6"
}
},
+ "node_modules/levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/libphonenumber-js": {
+ "version": "1.13.14",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.14.tgz",
+ "integrity": "sha512-llihgCcx0BFLksecLP+x1J+6JDE1GsXS1RN/LoPF6qcwpeQcnjj0lcvZxY8AzbEpYwyZWPZW/nDuqkqzm3amiw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -11269,6 +11911,25 @@
"node": ">= 0.4"
}
},
+ "node_modules/md5": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+ "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "~1.1.6"
+ }
+ },
+ "node_modules/md5/node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/mdast-util-directive": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz",
@@ -13827,6 +14488,26 @@
"multicast-dns": "cli.js"
}
},
+ "node_modules/multimatch": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz",
+ "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/minimatch": "^3.0.3",
+ "array-differ": "^3.0.0",
+ "array-union": "^2.1.0",
+ "arrify": "^2.0.1",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
@@ -14051,6 +14732,23 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/object-is": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
+ "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -14148,6 +14846,34 @@
"opener": "bin/opener-bin.js"
}
},
+ "node_modules/optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-paths": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz",
+ "integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0"
+ }
+ },
"node_modules/p-cancelable": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
@@ -14515,6 +15241,16 @@
"points-on-curve": "0.2.0"
}
},
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@@ -15976,6 +16712,15 @@
"postcss": "^8.4.31"
}
},
+ "node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/pretty-error": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz",
@@ -16017,6 +16762,16 @@
"node": ">=6"
}
},
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -16475,6 +17230,14 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/reflect-metadata": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
+ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -17067,6 +17830,24 @@
],
"license": "MIT"
},
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -17723,6 +18504,13 @@
"safe-buffer": "~5.2.0"
}
},
+ "node_modules/string-template": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz",
+ "integrity": "sha512-SLqR3GBUXuoPP5MmYtD7ompvXiG87QjT6lzOszyXjTM86Uu7At7vNnt2xgyTLq5o9T4IxTYFyGxcULqpsmsfdg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@@ -17795,6 +18583,16 @@
"node": ">=4"
}
},
+ "node_modules/stringz": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/stringz/-/stringz-2.1.0.tgz",
+ "integrity": "sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "char-regex": "^1.0.2"
+ }
+ },
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -18053,6 +18851,19 @@
"tslib": "^2"
}
},
+ "node_modules/throttleit": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz",
+ "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/thunky": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
@@ -18168,6 +18979,19 @@
"license": "0BSD",
"peer": true
},
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/type-fest": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
@@ -18229,6 +19053,16 @@
"integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
"license": "MIT"
},
+ "node_modules/undici": {
+ "version": "6.29.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz",
+ "integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
@@ -18656,6 +19490,20 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/util": {
+ "version": "0.12.5",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
+ "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "is-arguments": "^1.0.4",
+ "is-generator-function": "^1.0.7",
+ "is-typed-array": "^1.1.3",
+ "which-typed-array": "^1.1.2"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -18695,6 +19543,16 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/validator": {
+ "version": "13.15.35",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz",
+ "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/value-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
@@ -19240,6 +20098,28 @@
"node": ">= 8"
}
},
+ "node_modules/which-typed-array": {
+ "version": "1.1.24",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.24.tgz",
+ "integrity": "sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/widest-line": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz",
@@ -19261,6 +20141,16 @@
"integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
"license": "MIT"
},
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
@@ -19380,6 +20270,20 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/xdg-app-paths": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.5.1.tgz",
+ "integrity": "sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "os-paths": "^4.0.1",
+ "xdg-portable": "^7.2.0"
+ },
+ "engines": {
+ "node": ">= 6.0"
+ }
+ },
"node_modules/xdg-basedir": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz",
@@ -19392,6 +20296,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/xdg-portable": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz",
+ "integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "os-paths": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6.0"
+ }
+ },
"node_modules/xml-js": {
"version": "1.6.11",
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
@@ -19422,6 +20339,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/zod": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz",
+ "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
diff --git a/website/package.json b/website/package.json
index 19de6c0d..dd0d4fa7 100644
--- a/website/package.json
+++ b/website/package.json
@@ -34,7 +34,8 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.9.2",
- "@docusaurus/types": "^3.9.2"
+ "@docusaurus/types": "^3.9.2",
+ "javascript-obfuscator": "^5.8.1"
},
"browserslist": {
"production": [
diff --git a/website/src/components/HomepageHero/RotatingPhrase.js b/website/src/components/HomepageHero/RotatingPhrase.js
new file mode 100644
index 00000000..20a7f69d
--- /dev/null
+++ b/website/src/components/HomepageHero/RotatingPhrase.js
@@ -0,0 +1,55 @@
+import {useEffect, useRef, useState} from 'react';
+
+import styles from './styles.module.css';
+
+const PHRASES = ['every payment', 'every peel chain', 'every mixer', 'every market move'];
+const PHRASE_HOLD_MS = 2000;
+const PHRASE_SLIDE_MS = 600;
+
+// Each phrase holds for PHRASE_HOLD_MS, then slides out right as the next
+// slides in, while the slot eases to the new phrase's width.
+export default function RotatingPhrase() {
+ const [{current, previous}, setPhrases] = useState({current: 0, previous: null});
+ const sizers = useRef([]);
+ const [widths, setWidths] = useState(null);
+
+ useEffect(() => {
+ const id = setInterval(
+ () => setPhrases(({current: c}) => ({current: (c + 1) % PHRASES.length, previous: c})),
+ PHRASE_HOLD_MS + PHRASE_SLIDE_MS,
+ );
+ return () => clearInterval(id);
+ }, []);
+
+ // Re-measured whenever a phrase's rendered width changes: font load, resize.
+ useEffect(() => {
+ const measure = () => setWidths(sizers.current.map((el) => el.getBoundingClientRect().width));
+ const observer = new ResizeObserver(measure);
+ sizers.current.forEach((el) => observer.observe(el));
+ return () => observer.disconnect();
+ }, []);
+
+ return (
+ <>
+
+ {previous !== null && (
+
+ {PHRASES[previous]}
+
+ )}
+
+ {PHRASES[current]}
+
+
+
+ {PHRASES.map((phrase, i) => (
+ (sizers.current[i] = el)}>
+ {phrase}
+
+ ))}
+
+ >
+ );
+}
diff --git a/website/src/components/HomepageHero/index.js b/website/src/components/HomepageHero/index.js
new file mode 100644
index 00000000..7c6953e4
--- /dev/null
+++ b/website/src/components/HomepageHero/index.js
@@ -0,0 +1,86 @@
+import {useEffect, useRef, useState} from 'react';
+import Link from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import graphViz from '@site/src/data/graphViz';
+import RotatingPhrase from './RotatingPhrase';
+
+import styles from './styles.module.css';
+
+function GraphOverlay() {
+ return (
+
+
+
+ EBA empowers
+
+ your model with
+
+
+
+ in Bitcoin's
+ complete history.
+
+
+ );
+}
+
+// The widget is prebuilt into static/graph-viz (see graph-viz/build.mjs) and
+// loaded at runtime, so webpack must not try to bundle it.
+export default function HomepageHero() {
+ const {siteConfig} = useDocusaurusContext();
+ const ref = useRef(null);
+ const widgetBase = useBaseUrl('/graph-viz/');
+ const dataUrl = useBaseUrl('/graph/sample.json');
+ const [failed, setFailed] = useState(false);
+
+ useEffect(() => {
+ let cancelled = false;
+ let unmount;
+ const css = document.createElement('link');
+ css.rel = 'stylesheet';
+ css.href = `${widgetBase}${graphViz.style}`;
+ document.head.appendChild(css);
+ import(/* webpackIgnore: true */ `${widgetBase}${graphViz.script}`)
+ .then((widget) => widget.mount(ref.current, {dataUrl}))
+ .then((remove) => {
+ if (cancelled) remove();
+ else unmount = remove;
+ })
+ .catch((err) => {
+ console.error('Graph visualization failed to load', err);
+ if (!cancelled) setFailed(true);
+ });
+ return () => {
+ cancelled = true;
+ unmount?.();
+ css.remove();
+ };
+ }, [widgetBase, dataUrl]);
+
+ return (
+