From 830714479757c47517e9f46f7c5f1fa37086ccac Mon Sep 17 00:00:00 2001 From: Justin Levine <20596508+jal-co@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:37:52 -0400 Subject: [PATCH 1/3] feat(marketplace): render paid previews as compiled artifacts Signed-off-by: Justin Levine <20596508+jal-co@users.noreply.github.com> --- apps/web/content/docs/open-source-credits.mdx | 2 + apps/web/package.json | 4 +- apps/web/src/components/collection-view.tsx | 30 ++- apps/web/src/lib/catalog-db.ts | 26 +- apps/web/src/lib/preview-obfuscate.ts | 50 ++++ .../src/routes/preview.$namespace.$name.tsx | 4 +- apps/web/test/preview-obfuscate.test.ts | 41 +++ pnpm-lock.yaml | 252 +++++++++++++----- 8 files changed, 309 insertions(+), 100 deletions(-) create mode 100644 apps/web/src/lib/preview-obfuscate.ts create mode 100644 apps/web/test/preview-obfuscate.test.ts diff --git a/apps/web/content/docs/open-source-credits.mdx b/apps/web/content/docs/open-source-credits.mdx index 8b03a4c..1a1818c 100644 --- a/apps/web/content/docs/open-source-credits.mdx +++ b/apps/web/content/docs/open-source-credits.mdx @@ -66,6 +66,8 @@ and isolated live component runtime. | [Pierre Diffs](https://github.com/pierrecomputer/pierre/tree/main/packages/diffs) (`@pierre/diffs`) | Apache-2.0 | Local curator source diffs; unpublished source is not sent to a third party. | | [Pierre Theme](https://github.com/pierrecomputer/pierre/tree/main/packages/theme) (`@pierre/theme`) | MIT | Light, dark, and color-vision-safe code palettes. | | [Shiki](https://shiki.style/) (`shiki`) | MIT | Syntax tokenization and highlighted source rendering. | +| [Sucrase](https://github.com/alangpierce/sucrase) (`sucrase`) | MIT | Server-side TypeScript/JSX compilation for paid preview builds. | +| [Terser](https://terser.org/) (`terser`) | BSD-2-Clause | Server-side minification and mangling of paid preview builds. | | [React CodeMirror](https://uiwjs.github.io/react-codemirror/) (`@uiw/react-codemirror`) | MIT | React integration for the source editor. | | [CodeMirror GitHub theme](https://uiwjs.github.io/react-codemirror/#/theme/data/github/light) (`@uiw/codemirror-theme-github`) | MIT | Base editor theme adapter; Modulora maps it to Pierre tokens. | | [CodeMirror CSS language](https://github.com/codemirror/lang-css) (`@codemirror/lang-css`) | MIT | CSS parsing and editor language support. | diff --git a/apps/web/package.json b/apps/web/package.json index f686034..6c7310d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -58,7 +58,9 @@ "react-icons": "^5.7.0", "shiki": "^4.3.1", "stripe": "^22.3.1", - "tailwind-merge": "^3.3.1" + "sucrase": "^3.35.1", + "tailwind-merge": "^3.3.1", + "terser": "^5.49.0" }, "devDependencies": { "@chromatic-com/storybook": "^5.2.1", diff --git a/apps/web/src/components/collection-view.tsx b/apps/web/src/components/collection-view.tsx index 827a1af..8f7adf4 100644 --- a/apps/web/src/components/collection-view.tsx +++ b/apps/web/src/components/collection-view.tsx @@ -132,33 +132,37 @@ export function CollectionView({ collection }: { collection: CollectionDetail })
- {member.locked ? ( + {(member.files ?? []).length > 0 ? ( + ({ path: f.path, content: f.content }))} + selectedDemo={demoPath} + theme={pageTheme} + className="h-[32rem]" + /> + ) : (
-

Purchase to preview

+

Preview unavailable

- {member.title} is a paid component — buying the collection unlocks it. + {member.title} could not be previewed — buying the collection unlocks the source and install.

- ) : ( - ({ path: f.path, content: f.content }))} - selectedDemo={demoPath} - theme={pageTheme} - className="h-[32rem]" - /> )} - {!member.locked ? ( + {member.locked ? ( +
+ Live preview only — buying the collection unlocks the readable source and install. +
+ ) : (
{memberCommand}
- ) : null} + )}
diff --git a/apps/web/src/lib/catalog-db.ts b/apps/web/src/lib/catalog-db.ts index cfccad1..4db6932 100644 --- a/apps/web/src/lib/catalog-db.ts +++ b/apps/web/src/lib/catalog-db.ts @@ -17,6 +17,7 @@ import { normalizeDomain } from "./domains"; import { hasCollectionEntitlement, hasEntitlement } from "./marketplace"; import { DIRECT_MARKETPLACE_ENABLED } from "./flags"; import { licenseTemplate, resolveLicenseText } from "./license"; +import { obfuscatePreviewFiles } from "./preview-obfuscate"; import { publicListsFor } from "./lists"; import { visibleProfileContent, @@ -310,12 +311,15 @@ export const fetchCatalogDetail = createServerFn({ method: "GET" }) : []; const evidence = row.version ? await loadEvidence(database, row.version.id) : []; + // Never send paid source to a viewer who hasn't purchased it. Unentitled + // viewers get a compiled preview artifact (or nothing if compilation fails). + const readable = files.map((file) => ({ path: file.path, content: file.content ?? "" })); + const shippedFiles = entitled ? readable : (await obfuscatePreviewFiles(readable)) ?? []; const item = toCatalogItem( row.namespace, row.component, row.version, - // Never send paid source to a viewer who hasn't purchased it. - entitled ? files.map((file) => ({ path: file.path, content: file.content ?? "" })) : [], + shippedFiles, evidence, ); // Record the view: approved + public only, never the owner's own visits. @@ -966,15 +970,17 @@ export const fetchCollectionDetail = createServerFn({ method: "GET" }) const entitled = !memberPrice ? true : owned || (await hasEntitlement(member.component.id, viewer?.id ?? null, row.ownerUserId)); - const files = entitled - ? await database - .select({ path: schema.componentFiles.path, content: schema.componentFiles.content }) - .from(schema.componentFiles) - .where(eq(schema.componentFiles.componentVersionId, member.version.id)) - .orderBy(schema.componentFiles.orderIndex) - : []; + const files = await database + .select({ path: schema.componentFiles.path, content: schema.componentFiles.content }) + .from(schema.componentFiles) + .where(eq(schema.componentFiles.componentVersionId, member.version.id)) + .orderBy(schema.componentFiles.orderIndex); + // Paid members still render a live preview: unentitled viewers get the + // compiled artifact, never the readable source (nothing on failure). + const readableMemberFiles = files.map((f) => ({ path: f.path, content: f.content ?? "" })); + const shippedMemberFiles = entitled ? readableMemberFiles : (await obfuscatePreviewFiles(readableMemberFiles)) ?? []; members.push({ - ...toCatalogItem(data.namespace, member.component, member.version, files.map((f) => ({ path: f.path, content: f.content ?? "" }))), + ...toCatalogItem(data.namespace, member.component, member.version, shippedMemberFiles), locked: !entitled, }); } diff --git a/apps/web/src/lib/preview-obfuscate.ts b/apps/web/src/lib/preview-obfuscate.ts new file mode 100644 index 0000000..72cc34a --- /dev/null +++ b/apps/web/src/lib/preview-obfuscate.ts @@ -0,0 +1,50 @@ +/** + * Preview builds for paid source. Unentitled viewers can render a live + * preview, but they receive a compiled artifact — types and comments are + * destroyed and local identifiers mangled server-side. This is lossy + * compilation, not keyed encryption: Modulora being open source does not + * weaken it, exactly as reading a minifier's source cannot un-minify its + * output. The readable source never leaves the server without entitlement, + * and any transform failure fails closed (no files at all). + */ +import { transform } from "sucrase"; +import { minify } from "terser"; + +export interface PreviewFile { + path: string; + content: string; +} + +const BANNER = "/* Modulora preview build — purchase unlocks the readable source. */\n"; +const SCRIPT_EXTENSIONS = /\.(tsx|ts|jsx|js|mjs)$/i; + +async function compileOne(file: PreviewFile): Promise { + if (!SCRIPT_EXTENSIONS.test(file.path)) return file; + const stripped = transform(file.content, { + transforms: ["typescript", "jsx"], + jsxRuntime: "automatic", + production: true, + filePath: file.path, + }).code; + const minified = await minify(stripped, { + module: true, + compress: { defaults: true, passes: 2 }, + mangle: { toplevel: false }, + format: { comments: false }, + }); + if (!minified.code) throw new Error(`empty terser output for ${file.path}`); + return { path: file.path, content: `${BANNER}${minified.code}` }; +} + +/** + * Compile every script file for an unentitled preview. Returns null when any + * file cannot be compiled — callers must treat null as "ship nothing". + */ +export async function obfuscatePreviewFiles(files: PreviewFile[]): Promise { + try { + return await Promise.all(files.map(compileOne)); + } catch (error) { + console.error("preview obfuscation failed; withholding files", error); + return null; + } +} diff --git a/apps/web/src/routes/preview.$namespace.$name.tsx b/apps/web/src/routes/preview.$namespace.$name.tsx index 2e2b05b..ae09a40 100644 --- a/apps/web/src/routes/preview.$namespace.$name.tsx +++ b/apps/web/src/routes/preview.$namespace.$name.tsx @@ -27,10 +27,10 @@ function PreviewPage() { const demoPath = files.find((f) => f.path.startsWith("src/demos/"))?.path ?? "src/demos/default.tsx"; if (files.length === 0) { - // Paid without entitlement (or no source): a quiet locked tile. + // No source, or a paid preview build could not be produced (fail closed). return (
- Purchase to preview + Preview unavailable
); } diff --git a/apps/web/test/preview-obfuscate.test.ts b/apps/web/test/preview-obfuscate.test.ts new file mode 100644 index 0000000..ad9ba3b --- /dev/null +++ b/apps/web/test/preview-obfuscate.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from "vitest"; + +import { obfuscatePreviewFiles } from "../src/lib/preview-obfuscate"; + +const component = `// secret implementation notes +import { useState } from "react"; + +interface CounterProps { + initialCount: number; +} + +export function Counter({ initialCount }: CounterProps) { + const [carefullyNamedCount, setCarefullyNamedCount] = useState(initialCount); + return ; +} +`; + +describe("preview obfuscation", () => { + it("destroys comments, types, and local names while preserving the module contract", async () => { + const result = await obfuscatePreviewFiles([ + { path: "components/ui/counter.tsx", content: component }, + { path: "styles.css", content: ".counter { color: red; }" }, + ]); + expect(result).not.toBeNull(); + const [compiled, css] = result!; + expect(compiled!.content).toContain("Modulora preview build"); + expect(compiled!.content).toContain("export"); + expect(compiled!.content).toContain("Counter"); + expect(compiled!.content).not.toContain("secret implementation notes"); + expect(compiled!.content).not.toContain("CounterProps"); + expect(compiled!.content).not.toContain("carefullyNamedCount"); + expect(css!.content).toBe(".counter { color: red; }"); + }); + + it("fails closed when a file cannot be compiled", async () => { + const result = await obfuscatePreviewFiles([ + { path: "components/ui/broken.tsx", content: "export function (((" }, + ]); + expect(result).toBeNull(); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a1eae3..2d9c331 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,7 +54,7 @@ importers: version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/react-start': specifier: ^1.132.0 - version: 1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + version: 1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@types/mdx': specifier: ^2.0.14 version: 2.0.14 @@ -87,7 +87,7 @@ importers: version: 4.0.0 better-auth: specifier: ^1.6.23 - version: 1.6.23(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.20.0)(kysely@0.29.3)(pg@8.22.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@3.2.7) + version: 1.6.23(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.20.0)(kysely@0.29.3)(pg@8.22.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@3.2.7) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -102,7 +102,7 @@ importers: version: 16.11.3(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@0.545.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3) fumadocs-mdx: specifier: ^15.1.0 - version: 15.1.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.3(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@0.545.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(react@19.2.7)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + version: 15.1.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.3(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@0.545.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(react@19.2.7)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) marked: specifier: ^18.0.6 version: 18.0.6 @@ -133,31 +133,37 @@ importers: stripe: specifier: ^22.3.1 version: 22.3.1(@types/node@26.1.1) + sucrase: + specifier: ^3.35.1 + version: 3.35.1 tailwind-merge: specifier: ^3.3.1 version: 3.6.0 + terser: + specifier: ^5.49.0 + version: 5.49.0 devDependencies: '@chromatic-com/storybook': specifier: ^5.2.1 version: 5.2.1(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7)) '@cloudflare/vite-plugin': specifier: ^1.14.0 - version: 1.44.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(workerd@1.20260708.1)(wrangler@4.110.0) + version: 1.44.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(workerd@1.20260708.1)(wrangler@4.110.0) '@storybook/addon-a11y': specifier: ^10.5.0 version: 10.5.0(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7)) '@storybook/addon-docs': specifier: ^10.5.0 - version: 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + version: 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@storybook/addon-mcp': specifier: ^0.7.0 version: 0.7.0(@storybook/addon-vitest@10.5.0(@vitest/browser@3.2.7)(@vitest/runner@3.2.7)(react@19.2.7)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vitest@3.2.7))(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3) '@storybook/tanstack-react': specifier: ^10.5.0 - version: 10.5.0(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)))(@tanstack/router-core@1.171.14)(@tanstack/start-client-core@1.170.13)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + version: 10.5.0(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)))(@tanstack/router-core@1.171.14)(@tanstack/start-client-core@1.170.13)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tailwindcss/vite': specifier: ^4.1.0 - version: 4.3.2(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + version: 4.3.2(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/react-query': specifier: ^5.101.2 version: 5.101.2(react@19.2.7) @@ -172,10 +178,10 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^5.0.0 - version: 5.2.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + version: 5.2.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@vitest/browser': specifier: 3.2.7 - version: 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(vitest@3.2.7) + version: 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(vitest@3.2.7) '@vitest/coverage-v8': specifier: 3.2.7 version: 3.2.7(@vitest/browser@3.2.7)(vitest@3.2.7) @@ -193,10 +199,10 @@ importers: version: 5.9.3 vite: specifier: ^7.1.0 - version: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + version: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) vitest: specifier: ^3.2.0 - version: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + version: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) wrangler: specifier: ^4.40.0 version: 4.110.0 @@ -1178,6 +1184,9 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -3194,6 +3203,9 @@ packages: resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} engines: {node: '>=14'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -3421,6 +3433,13 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + compute-scroll-into-view@3.1.1: resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} @@ -4201,6 +4220,9 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -4459,6 +4481,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.15: resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -4496,6 +4521,10 @@ packages: react-router-dom: optional: true + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + oniguruma-parser@0.12.2: resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} @@ -4591,6 +4620,10 @@ packages: picoquery@2.5.0: resolution: {integrity: sha512-j1kgOFxtaCyoFCkpoYG2Oj3OdGakadO7HZ7o5CqyRazlmBekKhbDoUnNnXASE07xSY4nDImWZkrZv7toSxMi/g==} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + playwright-core@1.61.1: resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==} engines: {node: '>=18'} @@ -4964,6 +4997,11 @@ packages: style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@10.2.2: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} @@ -4986,10 +5024,22 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + terser@5.49.0: + resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} + engines: {node: '>=10'} + hasBin: true + test-exclude@7.0.2: resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} engines: {node: '>=18'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -5036,6 +5086,9 @@ packages: resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} engines: {node: '>=6.10'} + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsconfig-paths@4.2.0: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} @@ -5547,12 +5600,12 @@ snapshots: optionalDependencies: workerd: 1.20260708.1 - '@cloudflare/vite-plugin@1.44.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(workerd@1.20260708.1)(wrangler@4.110.0)': + '@cloudflare/vite-plugin@1.44.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(workerd@1.20260708.1)(wrangler@4.110.0)': dependencies: '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260708.1) miniflare: 4.20260708.1 unenv: 2.0.0-rc.24 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) wrangler: 4.110.0 ws: 8.21.0 transitivePeerDependencies: @@ -6097,11 +6150,11 @@ snapshots: '@istanbuljs/schema@0.1.6': {} - '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) optionalDependencies: typescript: 5.9.3 @@ -6117,6 +6170,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -7319,10 +7377,10 @@ snapshots: axe-core: 4.12.1 storybook: 10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7) - '@storybook/addon-docs@10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@storybook/addon-docs@10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.17)(react@19.2.7) - '@storybook/csf-plugin': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@storybook/csf-plugin': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@storybook/icons': 2.1.0(react@19.2.7) '@storybook/react-dom-shim': 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7)) react: 19.2.7 @@ -7359,32 +7417,32 @@ snapshots: '@storybook/icons': 2.1.0(react@19.2.7) storybook: 10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7) optionalDependencies: - '@vitest/browser': 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(vitest@3.2.7) + '@vitest/browser': 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(vitest@3.2.7) '@vitest/runner': 3.2.7 - vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - react optional: true - '@storybook/builder-vite@10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@storybook/builder-vite@10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: - '@storybook/csf-plugin': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@storybook/csf-plugin': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) storybook: 10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7) ts-dedent: 2.3.0 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/csf-plugin@10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@storybook/csf-plugin@10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: storybook: 10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7) unplugin: 2.3.11 optionalDependencies: esbuild: 0.28.1 rollup: 4.62.2 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) '@storybook/global@5.0.0': {} @@ -7411,11 +7469,11 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@storybook/react-vite@10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@storybook/react-vite@10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@rollup/pluginutils': 5.4.0(rollup@4.62.2) - '@storybook/builder-vite': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@storybook/builder-vite': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@storybook/react': 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3) empathic: 2.0.1 magic-string: 0.30.21 @@ -7425,7 +7483,7 @@ snapshots: resolve: 1.22.12 storybook: 10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7) tsconfig-paths: 4.2.0 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -7452,19 +7510,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/tanstack-react@10.5.0(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)))(@tanstack/router-core@1.171.14)(@tanstack/start-client-core@1.170.13)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@storybook/tanstack-react@10.5.0(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)))(@tanstack/router-core@1.171.14)(@tanstack/start-client-core@1.170.13)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: - '@storybook/builder-vite': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@storybook/builder-vite': 10.5.0(esbuild@0.28.1)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@storybook/react': 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3) - '@storybook/react-vite': 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@storybook/react-vite': 10.5.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(storybook@10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7))(typescript@5.9.3)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/react-router': 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/router-core': 1.171.14 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) storybook: 10.5.0(@types/react@19.2.17)(prettier@3.9.5)(react@19.2.7) - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) optionalDependencies: - '@tanstack/react-start': 1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@tanstack/react-start': 1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/start-client-core': 1.170.13 transitivePeerDependencies: - '@types/react' @@ -7536,12 +7594,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 - '@tailwindcss/vite@4.3.2(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@tailwindcss/vite@4.3.2(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@tailwindcss/node': 4.3.2 '@tailwindcss/oxide': 4.3.2 tailwindcss: 4.3.2 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) '@tanstack/history@1.162.0': {} @@ -7569,14 +7627,14 @@ snapshots: react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@tanstack/react-start-rsc@0.1.26(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@tanstack/react-start-rsc@0.1.26(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@tanstack/react-router': 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/router-core': 1.171.14 '@tanstack/router-utils': 1.162.2 '@tanstack/start-client-core': 1.170.13 '@tanstack/start-fn-stubs': 1.162.0 - '@tanstack/start-plugin-core': 1.171.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@tanstack/start-plugin-core': 1.171.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/start-server-core': 1.169.16 '@tanstack/start-storage-context': 1.167.16 pathe: 2.0.3 @@ -7606,21 +7664,21 @@ snapshots: transitivePeerDependencies: - crossws - '@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@tanstack/react-router': 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/react-start-client': 1.168.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@tanstack/react-start-rsc': 0.1.26(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@tanstack/react-start-rsc': 0.1.26(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/react-start-server': 1.167.21(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/router-utils': 1.162.2 '@tanstack/start-client-core': 1.170.13 - '@tanstack/start-plugin-core': 1.171.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@tanstack/start-plugin-core': 1.171.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/start-server-core': 1.169.16 pathe: 2.0.3 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -7662,7 +7720,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@tanstack/router-plugin@1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@babel/core': 7.29.7 '@babel/template': 7.29.7 @@ -7671,11 +7729,11 @@ snapshots: '@tanstack/router-generator': 1.167.18 '@tanstack/router-utils': 1.162.2 chokidar: 5.0.0 - unplugin: 3.3.0(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + unplugin: 3.3.0(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) zod: 4.4.3 optionalDependencies: '@tanstack/react-router': 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -7708,14 +7766,14 @@ snapshots: '@tanstack/start-fn-stubs@1.162.0': {} - '@tanstack/start-plugin-core@1.171.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@tanstack/start-plugin-core@1.171.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@babel/code-frame': 7.27.1 '@babel/core': 7.29.7 '@babel/types': 7.29.7 '@tanstack/router-core': 1.171.14 '@tanstack/router-generator': 1.167.18 - '@tanstack/router-plugin': 1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@tanstack/router-plugin': 1.168.19(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@tanstack/router-utils': 1.162.2 '@tanstack/start-server-core': 1.169.16 exsolve: 1.1.0 @@ -7727,11 +7785,11 @@ snapshots: srvx: 0.11.22 tinyglobby: 0.2.17 ufo: 1.6.4 - vitefu: 1.1.3(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + vitefu: 1.1.3(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) xmlbuilder2: 4.0.3 zod: 4.4.3 optionalDependencies: - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -8055,7 +8113,7 @@ snapshots: d3-time-format: 4.1.0 internmap: 2.0.3 - '@vitejs/plugin-react@5.2.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@vitejs/plugin-react@5.2.0(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) @@ -8063,20 +8121,20 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - supports-color - '@vitest/browser@3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(vitest@3.2.7)': + '@vitest/browser@3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(vitest@3.2.7)': dependencies: '@testing-library/dom': 10.4.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@vitest/utils': 3.2.7 magic-string: 0.30.21 sirv: 3.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) ws: 8.21.0 optionalDependencies: playwright: 1.61.1 @@ -8101,9 +8159,9 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) optionalDependencies: - '@vitest/browser': 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(vitest@3.2.7) + '@vitest/browser': 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(vitest@3.2.7) transitivePeerDependencies: - supports-color @@ -8123,13 +8181,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))': + '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))': dependencies: '@vitest/spy': 3.2.7 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) '@vitest/pretty-format@3.2.4': dependencies: @@ -8195,6 +8253,8 @@ snapshots: ansis@4.3.1: {} + any-promise@1.3.0: {} + argparse@2.0.1: {} aria-hidden@1.2.6: @@ -8242,7 +8302,7 @@ snapshots: baseline-browser-mapping@2.10.43: {} - better-auth@1.6.23(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.20.0)(kysely@0.29.3)(pg@8.22.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@3.2.7): + better-auth@1.6.23(@tanstack/react-start@1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.20.0)(kysely@0.29.3)(pg@8.22.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@3.2.7): dependencies: '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0) '@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.3.7(zod@4.4.3))(jose@6.2.3)(kysely@0.29.3)(nanostores@1.4.0))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.20.0)(kysely@0.29.3)(pg@8.22.0)) @@ -8262,13 +8322,13 @@ snapshots: nanostores: 1.4.0 zod: 4.4.3 optionalDependencies: - '@tanstack/react-start': 1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@tanstack/react-start': 1.168.27(esbuild@0.28.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) drizzle-kit: 0.31.10 drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.20.0)(kysely@0.29.3)(pg@8.22.0) pg: 8.22.0 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vitest: 3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - '@cloudflare/workers-types' - '@opentelemetry/api' @@ -8373,6 +8433,10 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@2.20.3: {} + + commander@4.1.1: {} + compute-scroll-into-view@3.1.1: {} convert-source-map@2.0.0: {} @@ -8771,7 +8835,7 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-mdx@15.1.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.3(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@0.545.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(react@19.2.7)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)): + fumadocs-mdx@15.1.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.3(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@0.545.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(react@19.2.7)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 @@ -8796,7 +8860,7 @@ snapshots: '@types/mdx': 2.0.14 '@types/react': 19.2.17 react: 19.2.7 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - supports-color @@ -9058,6 +9122,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lines-and-columns@1.2.4: {} + longest-streak@3.1.0: {} loupe@3.2.1: {} @@ -9572,6 +9638,12 @@ snapshots: ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.15: {} nanostores@1.4.0: {} @@ -9587,6 +9659,8 @@ snapshots: optionalDependencies: '@tanstack/react-router': 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + object-assign@4.1.1: {} + oniguruma-parser@0.12.2: {} oniguruma-to-es@4.3.6: @@ -9724,6 +9798,8 @@ snapshots: picoquery@2.5.0: {} + pirates@4.0.7: {} + playwright-core@1.61.1: {} playwright@1.61.1: @@ -10238,6 +10314,16 @@ snapshots: dependencies: inline-style-parser: 0.2.7 + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.17 + ts-interface-checker: 0.1.13 + supports-color@10.2.2: {} supports-color@7.2.0: @@ -10252,12 +10338,27 @@ snapshots: tapable@2.3.3: {} + terser@5.49.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.17.0 + commander: 2.20.3 + source-map-support: 0.5.21 + test-exclude@7.0.2: dependencies: '@istanbuljs/schema': 0.1.6 glob: 10.5.0 minimatch: 10.2.5 + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tiny-invariant@1.3.3: {} tinybench@2.9.0: {} @@ -10295,6 +10396,8 @@ snapshots: ts-dedent@2.3.0: {} + ts-interface-checker@0.1.13: {} + tsconfig-paths@4.2.0: dependencies: json5: 2.2.3 @@ -10374,7 +10477,7 @@ snapshots: picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 - unplugin@3.3.0(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)): + unplugin@3.3.0(esbuild@0.28.1)(rollup@4.62.2)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.5 @@ -10382,7 +10485,7 @@ snapshots: optionalDependencies: esbuild: 0.28.1 rollup: 4.62.2 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) update-browserslist-db@1.2.3(browserslist@4.28.6): dependencies: @@ -10425,13 +10528,13 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-node@3.2.4(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0): + vite-node@3.2.4(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) transitivePeerDependencies: - '@types/node' - jiti @@ -10446,7 +10549,7 @@ snapshots: - tsx - yaml - vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0): + vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0): dependencies: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.5) @@ -10459,17 +10562,18 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 lightningcss: 1.32.0 + terser: 5.49.0 tsx: 4.23.0 - vitefu@1.1.3(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)): + vitefu@1.1.3(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)): optionalDependencies: - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) - vitest@3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0): + vitest@3.2.7(@types/debug@4.1.13)(@types/node@26.1.1)(@vitest/browser@3.2.7)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.7 - '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0)) + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0)) '@vitest/pretty-format': 3.2.7 '@vitest/runner': 3.2.7 '@vitest/snapshot': 3.2.7 @@ -10487,13 +10591,13 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) - vite-node: 3.2.4(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0) + vite: 7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) + vite-node: 3.2.4(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.13 '@types/node': 26.1.1 - '@vitest/browser': 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.0))(vitest@3.2.7) + '@vitest/browser': 3.2.7(playwright@1.61.1)(vite@7.3.6(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.49.0)(tsx@4.23.0))(vitest@3.2.7) transitivePeerDependencies: - jiti - less From a8d4a50d57975919461bb80c238bcba87e0c254c Mon Sep 17 00:00:00 2001 From: Justin Levine <20596508+jal-co@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:46:59 -0400 Subject: [PATCH 2/3] fix(marketplace): protect paid source when checkout is disabled Signed-off-by: Justin Levine <20596508+jal-co@users.noreply.github.com> --- apps/web/src/lib/catalog-db.ts | 77 +++++++++---------- apps/web/src/lib/preview-obfuscate.ts | 5 ++ apps/web/src/lib/registry.ts | 37 ++++----- .../routes/components.$namespace.$name.tsx | 3 +- apps/web/test/preview-obfuscate.test.ts | 12 ++- 5 files changed, 71 insertions(+), 63 deletions(-) diff --git a/apps/web/src/lib/catalog-db.ts b/apps/web/src/lib/catalog-db.ts index 4db6932..591cbaa 100644 --- a/apps/web/src/lib/catalog-db.ts +++ b/apps/web/src/lib/catalog-db.ts @@ -17,7 +17,7 @@ import { normalizeDomain } from "./domains"; import { hasCollectionEntitlement, hasEntitlement } from "./marketplace"; import { DIRECT_MARKETPLACE_ENABLED } from "./flags"; import { licenseTemplate, resolveLicenseText } from "./license"; -import { obfuscatePreviewFiles } from "./preview-obfuscate"; +import { obfuscatePreviewFiles, requiresCompiledPreview } from "./preview-obfuscate"; import { publicListsFor } from "./lists"; import { visibleProfileContent, @@ -247,29 +247,28 @@ export const fetchCatalogDetail = createServerFn({ method: "GET" }) if (!isOwner && !viewer?.isCurator) return null; } - // Marketplace pricing: an active price gates the source behind purchase. - const price = DIRECT_MARKETPLACE_ENABLED - ? (await database - .select({ - unitAmount: schema.componentPrices.unitAmount, - licenseTemplate: schema.componentPrices.licenseTemplate, - licenseText: schema.componentPrices.licenseText, - }) - .from(schema.componentPrices) - .where(and(eq(schema.componentPrices.componentId, row.component.id), eq(schema.componentPrices.active, true))) - .limit(1))[0] - : undefined; - const marketplacePrice = price?.unitAmount ?? null; - const marketplaceLicense = price + // An active price protects source regardless of whether direct checkout is + // enabled. The feature flag controls commerce UI, never access control. + const protectionPrice = (await database + .select({ + unitAmount: schema.componentPrices.unitAmount, + licenseTemplate: schema.componentPrices.licenseTemplate, + licenseText: schema.componentPrices.licenseText, + }) + .from(schema.componentPrices) + .where(and(eq(schema.componentPrices.componentId, row.component.id), eq(schema.componentPrices.active, true))) + .limit(1))[0]; + const marketplacePrice = DIRECT_MARKETPLACE_ENABLED ? (protectionPrice?.unitAmount ?? null) : null; + const marketplaceLicense = DIRECT_MARKETPLACE_ENABLED && protectionPrice ? { - name: licenseTemplate(price.licenseTemplate).name, - text: resolveLicenseText(price.licenseTemplate, price.licenseText), + name: licenseTemplate(protectionPrice.licenseTemplate).name, + text: resolveLicenseText(protectionPrice.licenseTemplate, protectionPrice.licenseText), } : null; // The viewer's own purchase (buyer side): powers the "You own this" tray. let ownedPurchase: import("./purchases").OwnedComponent | null = null; - if (marketplacePrice !== null && viewer) { + if (protectionPrice && viewer) { const [p] = await database .select({ id: schema.purchases.id, @@ -297,10 +296,9 @@ export const fetchCatalogDetail = createServerFn({ method: "GET" }) }; } } - const entitled = - marketplacePrice === null - ? true - : await hasEntitlement(row.component.id, viewer?.id ?? null, row.ownerUserId ?? null); + const entitled = !protectionPrice + ? true + : await hasEntitlement(row.component.id, viewer?.id ?? null, row.ownerUserId ?? null); const files = row.version ? await database @@ -314,7 +312,8 @@ export const fetchCatalogDetail = createServerFn({ method: "GET" }) // Never send paid source to a viewer who hasn't purchased it. Unentitled // viewers get a compiled preview artifact (or nothing if compilation fails). const readable = files.map((file) => ({ path: file.path, content: file.content ?? "" })); - const shippedFiles = entitled ? readable : (await obfuscatePreviewFiles(readable)) ?? []; + const previewOnly = requiresCompiledPreview(row.component.sourceModel, entitled); + const shippedFiles = previewOnly ? (await obfuscatePreviewFiles(readable)) ?? [] : readable; const item = toCatalogItem( row.namespace, row.component, @@ -925,14 +924,13 @@ export const fetchCollectionDetail = createServerFn({ method: "GET" }) const request = getRequest(); const viewer = request ? await getCurrentUser(request) : null; - const price = DIRECT_MARKETPLACE_ENABLED - ? (await database - .select({ unitAmount: schema.collectionPrices.unitAmount, licenseTemplate: schema.collectionPrices.licenseTemplate, licenseText: schema.collectionPrices.licenseText }) - .from(schema.collectionPrices) - .where(and(eq(schema.collectionPrices.collectionId, row.collection.id), eq(schema.collectionPrices.active, true))) - .limit(1))[0] - : undefined; - const owned = price + const protectionPrice = (await database + .select({ unitAmount: schema.collectionPrices.unitAmount, licenseTemplate: schema.collectionPrices.licenseTemplate, licenseText: schema.collectionPrices.licenseText }) + .from(schema.collectionPrices) + .where(and(eq(schema.collectionPrices.collectionId, row.collection.id), eq(schema.collectionPrices.active, true))) + .limit(1))[0]; + const price = DIRECT_MARKETPLACE_ENABLED ? protectionPrice : undefined; + const owned = protectionPrice ? await hasCollectionEntitlement(row.collection.id, viewer?.id ?? null, row.ownerUserId) : false; const externalDomain = row.collection.externalUrl ? domainOf(row.collection.externalUrl) : null; @@ -960,13 +958,11 @@ export const fetchCollectionDetail = createServerFn({ method: "GET" }) const members: (CatalogItem & { locked: boolean })[] = []; for (const member of memberRows) { if (member.component.visibility !== "public" || member.component.reviewStatus !== "approved" || !member.version) continue; - const memberPrice = DIRECT_MARKETPLACE_ENABLED - ? (await database - .select({ id: schema.componentPrices.id }) - .from(schema.componentPrices) - .where(and(eq(schema.componentPrices.componentId, member.component.id), eq(schema.componentPrices.active, true))) - .limit(1))[0] - : undefined; + const memberPrice = (await database + .select({ id: schema.componentPrices.id }) + .from(schema.componentPrices) + .where(and(eq(schema.componentPrices.componentId, member.component.id), eq(schema.componentPrices.active, true))) + .limit(1))[0]; const entitled = !memberPrice ? true : owned || (await hasEntitlement(member.component.id, viewer?.id ?? null, row.ownerUserId)); @@ -978,7 +974,10 @@ export const fetchCollectionDetail = createServerFn({ method: "GET" }) // Paid members still render a live preview: unentitled viewers get the // compiled artifact, never the readable source (nothing on failure). const readableMemberFiles = files.map((f) => ({ path: f.path, content: f.content ?? "" })); - const shippedMemberFiles = entitled ? readableMemberFiles : (await obfuscatePreviewFiles(readableMemberFiles)) ?? []; + const previewOnly = requiresCompiledPreview(member.component.sourceModel, entitled); + const shippedMemberFiles = previewOnly + ? (await obfuscatePreviewFiles(readableMemberFiles)) ?? [] + : readableMemberFiles; members.push({ ...toCatalogItem(data.namespace, member.component, member.version, shippedMemberFiles), locked: !entitled, diff --git a/apps/web/src/lib/preview-obfuscate.ts b/apps/web/src/lib/preview-obfuscate.ts index 72cc34a..0062a13 100644 --- a/apps/web/src/lib/preview-obfuscate.ts +++ b/apps/web/src/lib/preview-obfuscate.ts @@ -15,6 +15,11 @@ export interface PreviewFile { content: string; } +/** Paid external source and unentitled hosted source are preview-only. */ +export function requiresCompiledPreview(sourceModel: string, entitled: boolean): boolean { + return sourceModel !== "open-source" || !entitled; +} + const BANNER = "/* Modulora preview build — purchase unlocks the readable source. */\n"; const SCRIPT_EXTENSIONS = /\.(tsx|ts|jsx|js|mjs)$/i; diff --git a/apps/web/src/lib/registry.ts b/apps/web/src/lib/registry.ts index 8b97651..6bd5b82 100644 --- a/apps/web/src/lib/registry.ts +++ b/apps/web/src/lib/registry.ts @@ -13,7 +13,6 @@ import { and, eq } from "drizzle-orm"; import { schema } from "@modulora/db"; import { getCurrentUser } from "./session"; import { hasCollectionEntitlement, hasEntitlement } from "./marketplace"; -import { DIRECT_MARKETPLACE_ENABLED } from "./flags"; export interface ParsedRegistryPath { namespace: string; @@ -94,13 +93,11 @@ async function resolveCollection( // A priced collection is a product: the whole bundle requires the bundle // entitlement (buying it also snapshots per-member entitlements). - const bundlePrice = DIRECT_MARKETPLACE_ENABLED - ? (await db - .select({ unitAmount: schema.collectionPrices.unitAmount, currency: schema.collectionPrices.currency }) - .from(schema.collectionPrices) - .where(and(eq(schema.collectionPrices.collectionId, collection.collection.id), eq(schema.collectionPrices.active, true))) - .limit(1))[0] - : undefined; + const bundlePrice = (await db + .select({ unitAmount: schema.collectionPrices.unitAmount, currency: schema.collectionPrices.currency }) + .from(schema.collectionPrices) + .where(and(eq(schema.collectionPrices.collectionId, collection.collection.id), eq(schema.collectionPrices.active, true))) + .limit(1))[0]; if (bundlePrice) { const bundleViewer = request ? await getCurrentUser(request) : null; const [bundleOwner] = await db @@ -147,13 +144,11 @@ async function resolveCollection( for (const member of servable) { const channels = member.component.distributionChannels ?? []; - const price = DIRECT_MARKETPLACE_ENABLED - ? (await db - .select({ id: schema.componentPrices.id }) - .from(schema.componentPrices) - .where(and(eq(schema.componentPrices.componentId, member.component.id), eq(schema.componentPrices.active, true))) - .limit(1))[0] - : undefined; + const price = (await db + .select({ id: schema.componentPrices.id }) + .from(schema.componentPrices) + .where(and(eq(schema.componentPrices.componentId, member.component.id), eq(schema.componentPrices.active, true))) + .limit(1))[0]; const paid = Boolean(price); const entitled = !paid || (await hasEntitlement(member.component.id, viewer?.id ?? null, owner?.ownerUserId ?? null)); if (!entitled) { @@ -253,13 +248,11 @@ export async function resolveRegistryItem( // Marketplace-priced components require an entitlement: the buyer (or the // owner), authenticated via session cookie or a CLI bearer token. - const price = DIRECT_MARKETPLACE_ENABLED - ? (await db - .select({ unitAmount: schema.componentPrices.unitAmount, currency: schema.componentPrices.currency }) - .from(schema.componentPrices) - .where(and(eq(schema.componentPrices.componentId, c.id), eq(schema.componentPrices.active, true))) - .limit(1))[0] - : undefined; + const price = (await db + .select({ unitAmount: schema.componentPrices.unitAmount, currency: schema.componentPrices.currency }) + .from(schema.componentPrices) + .where(and(eq(schema.componentPrices.componentId, c.id), eq(schema.componentPrices.active, true))) + .limit(1))[0]; if (price) { const viewer = request ? await getCurrentUser(request) : null; const entitled = await hasEntitlement(c.id, viewer?.id ?? null, row.ownerUserId ?? null); diff --git a/apps/web/src/routes/components.$namespace.$name.tsx b/apps/web/src/routes/components.$namespace.$name.tsx index 138bbb1..e097935 100644 --- a/apps/web/src/routes/components.$namespace.$name.tsx +++ b/apps/web/src/routes/components.$namespace.$name.tsx @@ -136,7 +136,8 @@ function ComponentDetailInner({ item, files, colorVisionMode, viewerPlus }: { it const isCommercialSource = item.sourceModel !== "open-source"; // Marketplace-priced: an open component sold on Modulora, source gated behind // purchase until the viewer owns it. - const locked = item.marketplacePrice != null && item.entitled === false; + // Entitlement protects source even while direct checkout UI is disabled. + const locked = item.entitled === false; const router = useRouter(); // Confirm a returning purchase Checkout, then reload with the entitlement. diff --git a/apps/web/test/preview-obfuscate.test.ts b/apps/web/test/preview-obfuscate.test.ts index ad9ba3b..ddde1fb 100644 --- a/apps/web/test/preview-obfuscate.test.ts +++ b/apps/web/test/preview-obfuscate.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { obfuscatePreviewFiles } from "../src/lib/preview-obfuscate"; +import { obfuscatePreviewFiles, requiresCompiledPreview } from "../src/lib/preview-obfuscate"; const component = `// secret implementation notes import { useState } from "react"; @@ -16,6 +16,16 @@ export function Counter({ initialCount }: CounterProps) { `; describe("preview obfuscation", () => { + it("compiles external paid and unentitled hosted components", () => { + const paidExternalComponent = { sourceModel: "external-commercial", entitled: true }; + const unpaidHostedComponent = { sourceModel: "open-source", entitled: false }; + const freeComponent = { sourceModel: "open-source", entitled: true }; + + expect(requiresCompiledPreview(paidExternalComponent.sourceModel, paidExternalComponent.entitled)).toBe(true); + expect(requiresCompiledPreview(unpaidHostedComponent.sourceModel, unpaidHostedComponent.entitled)).toBe(true); + expect(requiresCompiledPreview(freeComponent.sourceModel, freeComponent.entitled)).toBe(false); + }); + it("destroys comments, types, and local names while preserving the module contract", async () => { const result = await obfuscatePreviewFiles([ { path: "components/ui/counter.tsx", content: component }, From fccd136da8ef3b841948a31d9adfbc154fccb542 Mon Sep 17 00:00:00 2001 From: Justin Levine <20596508+jal-co@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:54:31 -0400 Subject: [PATCH 3/3] fix(publishing): persist only compiled paid previews Signed-off-by: Justin Levine <20596508+jal-co@users.noreply.github.com> --- apps/web/src/lib/preview-obfuscate.ts | 1 + apps/web/src/lib/publish.ts | 29 ++++++++++++++----------- apps/web/test/preview-obfuscate.test.ts | 6 +++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/web/src/lib/preview-obfuscate.ts b/apps/web/src/lib/preview-obfuscate.ts index 0062a13..3d924b9 100644 --- a/apps/web/src/lib/preview-obfuscate.ts +++ b/apps/web/src/lib/preview-obfuscate.ts @@ -25,6 +25,7 @@ const SCRIPT_EXTENSIONS = /\.(tsx|ts|jsx|js|mjs)$/i; async function compileOne(file: PreviewFile): Promise { if (!SCRIPT_EXTENSIONS.test(file.path)) return file; + if (file.content.startsWith(BANNER)) return file; const stripped = transform(file.content, { transforms: ["typescript", "jsx"], jsxRuntime: "automatic", diff --git a/apps/web/src/lib/publish.ts b/apps/web/src/lib/publish.ts index cdc5bab..6911a05 100644 --- a/apps/web/src/lib/publish.ts +++ b/apps/web/src/lib/publish.ts @@ -22,6 +22,7 @@ import { POLICY_VERSION } from "./publishing-policy"; import { roleFor } from "./scaffold"; import { stripSrc } from "./registry"; import { contentDigest } from "./digest"; +import { obfuscatePreviewFiles } from "./preview-obfuscate"; const NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/; const ALLOWED_EXTENSIONS = new Set(["tsx", "ts", "jsx", "js", "css", "json"]); @@ -176,6 +177,10 @@ export async function publishCore(data: PublishInput, request: Request): Promise } const isPaid = data.pricing === "paid"; + // Paid external listings keep only a lossy compiled preview artifact. + // Readable paid source must never be persisted by Modulora. + const previewFiles = isPaid ? await obfuscatePreviewFiles(files) : files; + if (!previewFiles) return { ok: false, error: "Could not build the paid preview. Check the component and demo files." }; const purchaseUrl = String(data.purchaseUrl ?? "").trim(); let purchaseDomain: string | null = null; let purchaseDomainVerified = false; @@ -346,19 +351,17 @@ export async function publishCore(data: PublishInput, request: Request): Promise }) .returning({ id: schema.componentVersions.id }); - if (!isPaid) { - await db.insert(schema.componentFiles).values( - files.map((file, index) => ({ - componentVersionId: createdVersion!.id, - path: file.path.trim(), - fileType: "registry:component", - role: roleFor(file.path.trim()), - content: file.content, - sizeBytes: new TextEncoder().encode(file.content).length, - orderIndex: index, - })), - ); - } + await db.insert(schema.componentFiles).values( + previewFiles.map((file, index) => ({ + componentVersionId: createdVersion!.id, + path: file.path.trim(), + fileType: "registry:component", + role: roleFor(file.path.trim()), + content: file.content, + sizeBytes: new TextEncoder().encode(file.content).length, + orderIndex: index, + })), + ); // Record honest, scoped evidence for this exact release. Every record is // something we can actually prove — no fabricated "signed"/"verified" badges. diff --git a/apps/web/test/preview-obfuscate.test.ts b/apps/web/test/preview-obfuscate.test.ts index ddde1fb..a2eb233 100644 --- a/apps/web/test/preview-obfuscate.test.ts +++ b/apps/web/test/preview-obfuscate.test.ts @@ -48,4 +48,10 @@ describe("preview obfuscation", () => { ]); expect(result).toBeNull(); }); + + it("does not transform an already compiled paid preview again", async () => { + const first = await obfuscatePreviewFiles([{ path: "component.tsx", content: component }]); + const second = await obfuscatePreviewFiles(first!); + expect(second).toEqual(first); + }); });