diff --git a/package.json b/package.json index 94b5f0ba9..97debdf7d 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build:registry": "pnpm --filter=www,v4 build:registry && pnpm --filter=www,v4 lint:fix && pnpm format:write -- --loglevel silent", "registry:build": "pnpm --filter=v4 registry:build && pnpm lint:fix && pnpm format:write -- --loglevel silent", "registry:capture": "pnpm --filter=www registry:capture", - "dev": "turbo run dev --parallel", + "dev": "turbo run dev --filter=!www --parallel", "shadcn-ui:dev": "turbo --filter=shadcn-ui dev", "shadcn-ui": "pnpm --filter=shadcn-ui start:dev", "shadcn-ui:test": "pnpm --filter=shadcn-ui test", diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index 413e75343..a9d0a7a79 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -63,6 +63,7 @@ "@babel/core": "^7.22.1", "@babel/parser": "^7.22.6", "@babel/plugin-transform-typescript": "^7.22.5", + "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.10.2", "commander": "^10.0.0", "cosmiconfig": "^8.1.3", diff --git a/packages/shadcn/src/commands/add.ts b/packages/shadcn/src/commands/add.ts index c2a795da7..811e94200 100644 --- a/packages/shadcn/src/commands/add.ts +++ b/packages/shadcn/src/commands/add.ts @@ -1,16 +1,12 @@ -import fs from "fs" import path from "path" import { runInit } from "@/src/commands/init" import { preFlightAdd } from "@/src/preflights/preflight-add" import { getRegistryIndex, getRegistryItem } from "@/src/registry/api" -import { registryItemTypeSchema } from "@/src/registry/schema" -import { - isLocalFile, - isUniversalRegistryItem, - isUrl, -} from "@/src/registry/utils" +import { clearRegistryContext } from "@/src/registry/context" +import { isUniversalRegistryItem } from "@/src/registry/utils" import { addComponents } from "@/src/utils/add-components" import { createProject } from "@/src/utils/create-project" +import { loadEnvFiles } from "@/src/utils/env-loader" import * as ERRORS from "@/src/utils/errors" import { createConfig, getConfig } from "@/src/utils/get-config" import { getProjectInfo } from "@/src/utils/get-project-info" @@ -82,37 +78,47 @@ export const add = new Command() ...opts, }) - let itemType: z.infer | undefined - let registryItem: any = null + await loadEnvFiles(options.cwd) - if ( - components.length > 0 && - (isUrl(components[0]) || isLocalFile(components[0])) - ) { - registryItem = await getRegistryItem(components[0], "") - itemType = registryItem?.type + let initialConfig = await getConfig(options.cwd) + if (!initialConfig) { + initialConfig = createConfig({ + resolvedPaths: { + cwd: options.cwd, + }, + }) } - if ( - !options.yes && - (itemType === "registry:style" || itemType === "registry:theme") - ) { - logger.break() - const { confirm } = await prompts({ - type: "confirm", - name: "confirm", - message: highlighter.warn( - `You are about to install a new ${itemType.replace( - "registry:", - "" - )}. \nExisting CSS variables and components will be overwritten. Continue?` - ), - }) - if (!confirm) { + if (components.length > 0) { + const registryItem = await getRegistryItem(components[0], initialConfig) + const itemType = registryItem?.type + + if (isUniversalRegistryItem(registryItem)) { + await addComponents(components, initialConfig, options) + return + } + + if ( + !options.yes && + (itemType === "registry:style" || itemType === "registry:theme") + ) { logger.break() - logger.log(`Installation cancelled.`) - logger.break() - process.exit(1) + const { confirm } = await prompts({ + type: "confirm", + name: "confirm", + message: highlighter.warn( + `You are about to install a new ${itemType.replace( + "registry:", + "" + )}. \nExisting CSS variables and components will be overwritten. Continue?` + ), + }) + if (!confirm) { + logger.break() + logger.log(`Installation cancelled.`) + logger.break() + process.exit(1) + } } } @@ -136,22 +142,6 @@ export const add = new Command() } } - if (isUniversalRegistryItem(registryItem)) { - // Universal items only cares about the cwd. - if (!fs.existsSync(options.cwd)) { - throw new Error(`Directory ${options.cwd} does not exist`) - } - - const minimalConfig = createConfig({ - resolvedPaths: { - cwd: options.cwd, - }, - }) - - await addComponents(options.components, minimalConfig, options) - return - } - let { errors, config } = await preFlightAdd(options) // No components.json file. Prompt the user to run init. @@ -237,6 +227,8 @@ export const add = new Command() } catch (error) { logger.break() handleError(error) + } finally { + clearRegistryContext() } }) diff --git a/packages/shadcn/src/commands/info.ts b/packages/shadcn/src/commands/info.ts index ce79cb21c..2ff0f08b9 100644 --- a/packages/shadcn/src/commands/info.ts +++ b/packages/shadcn/src/commands/info.ts @@ -1,5 +1,6 @@ import { getConfig } from "@/src/utils/get-config" import { getProjectInfo } from "@/src/utils/get-project-info" +import { handleError } from "@/src/utils/handle-error" import { logger } from "@/src/utils/logger" import { Command } from "commander" @@ -12,9 +13,13 @@ export const info = new Command() process.cwd() ) .action(async (opts) => { - logger.info("> project info") - console.log(await getProjectInfo(opts.cwd)) - logger.break() - logger.info("> components.json") - console.log(await getConfig(opts.cwd)) + try { + logger.info("> project info") + console.log(await getProjectInfo(opts.cwd)) + logger.break() + logger.info("> components.json") + console.log(await getConfig(opts.cwd)) + } catch (error) { + handleError(error) + } }) diff --git a/packages/shadcn/src/commands/init.ts b/packages/shadcn/src/commands/init.ts index 76259f8de..81a4f52ee 100644 --- a/packages/shadcn/src/commands/init.ts +++ b/packages/shadcn/src/commands/init.ts @@ -7,9 +7,12 @@ import { getRegistryItem, getRegistryStyles, } from "@/src/registry/api" +import { clearRegistryContext } from "@/src/registry/context" +import { rawConfigSchema } from "@/src/registry/schema" import { isLocalFile, isUrl } from "@/src/registry/utils" import { addComponents } from "@/src/utils/add-components" import { TEMPLATES, createProject } from "@/src/utils/create-project" +import { loadEnvFiles } from "@/src/utils/env-loader" import * as ERRORS from "@/src/utils/errors" import { DEFAULT_COMPONENTS, @@ -17,7 +20,6 @@ import { DEFAULT_TAILWIND_CSS, DEFAULT_UTILS, getConfig, - rawConfigSchema, resolveConfigPaths, type Config, } from "@/src/utils/get-config" @@ -122,14 +124,15 @@ export const init = new Command() ...opts, }) + await loadEnvFiles(options.cwd) + + const config = await getConfig(options.cwd) + // We need to check if we're initializing with a new style. // We fetch the payload of the first item. // This is okay since the request is cached and deduped. - if ( - components.length > 0 && - (isUrl(components[0]) || isLocalFile(components[0])) - ) { - const item = await getRegistryItem(components[0], "") + if (components.length > 0) { + const item = await getRegistryItem(components[0], config || undefined) // Skip base color if style. // We set a default and let the style override it. @@ -150,6 +153,8 @@ export const init = new Command() } catch (error) { logger.break() handleError(error) + } finally { + clearRegistryContext() } }) @@ -408,7 +413,7 @@ async function promptForMinimalConfig( }, rsc: defaultConfig?.rsc, tsx: defaultConfig?.tsx, - aliases: defaultConfig?.aliases, iconLibrary: defaultConfig?.iconLibrary, + aliases: defaultConfig?.aliases, }) } diff --git a/packages/shadcn/src/commands/registry/build.ts b/packages/shadcn/src/commands/registry/build.ts index fb15b9b19..85c6a647f 100644 --- a/packages/shadcn/src/commands/registry/build.ts +++ b/packages/shadcn/src/commands/registry/build.ts @@ -1,10 +1,13 @@ import * as fs from "fs/promises" import * as path from "path" import { preFlightRegistryBuild } from "@/src/preflights/preflight-registry" -import { registryItemSchema, registrySchema } from "@/src/registry" +import { + configSchema, + registryItemSchema, + registrySchema, +} from "@/src/registry" import { recursivelyResolveFileImports } from "@/src/registry/utils" import * as ERRORS from "@/src/utils/errors" -import { configSchema } from "@/src/utils/get-config" import { ProjectInfo, getProjectInfo } from "@/src/utils/get-project-info" import { handleError } from "@/src/utils/handle-error" import { highlighter } from "@/src/utils/highlighter" diff --git a/packages/shadcn/src/mcp/index.ts b/packages/shadcn/src/mcp/index.ts index 0f9916d16..ef8201b9f 100644 --- a/packages/shadcn/src/mcp/index.ts +++ b/packages/shadcn/src/mcp/index.ts @@ -198,7 +198,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } const itemUrl = getRegistryItemUrl(name, REGISTRY_URL) - const item = await getRegistryItem(itemUrl, "") + const item = await getRegistryItem(itemUrl) return { content: [{ type: "text", text: JSON.stringify(item, null, 2) }], @@ -213,7 +213,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } const itemUrl = getRegistryItemUrl(name, REGISTRY_URL) - const item = await getRegistryItem(itemUrl, "") + const item = await getRegistryItem(itemUrl) if (!item) { return { diff --git a/packages/shadcn/src/registry/api.test.ts b/packages/shadcn/src/registry/api.test.ts index 9f9db2ef1..f8288815b 100644 --- a/packages/shadcn/src/registry/api.test.ts +++ b/packages/shadcn/src/registry/api.test.ts @@ -7,6 +7,7 @@ import { afterAll, afterEach, beforeAll, + beforeEach, describe, expect, it, @@ -16,6 +17,7 @@ import { import { clearRegistryCache, fetchRegistry, + getRegistry, getRegistryItem, registryResolveItemsTree, } from "./api" @@ -34,7 +36,7 @@ vi.mock("@/src/utils/logger", () => ({ }, })) -const REGISTRY_URL = "https://ui.shadcn.com/r" +const REGISTRY_URL = process.env.REGISTRY_URL ?? "https://ui.shadcn.com/r" const server = setupServer( http.get(`${REGISTRY_URL}/index.json`, () => { @@ -177,7 +179,7 @@ describe("getRegistryItem with local files", () => { await fs.writeFile(tempFile, JSON.stringify(componentData, null, 2)) try { - const result = await getRegistryItem(tempFile, "unused-style") + const result = await getRegistryItem(tempFile) expect(result).toMatchObject({ name: "test-component", @@ -215,10 +217,7 @@ describe("getRegistryItem with local files", () => { const originalCwd = process.cwd() process.chdir(tempDir) - const result = await getRegistryItem( - "./relative-component.json", - "unused-style" - ) + const result = await getRegistryItem("./relative-component.json") expect(result).toMatchObject({ name: "relative-component", @@ -249,7 +248,7 @@ describe("getRegistryItem with local files", () => { try { // Test with tilde path const tildeePath = "~/shadcn-test-tilde.json" - const result = await getRegistryItem(tildeePath, "unused-style") + const result = await getRegistryItem(tildeePath) expect(result).toMatchObject({ name: "tilde-component", @@ -262,10 +261,7 @@ describe("getRegistryItem with local files", () => { }) it("should return null for non-existent files", async () => { - const result = await getRegistryItem( - "/non/existent/file.json", - "unused-style" - ) + const result = await getRegistryItem("/non/existent/file.json") expect(result).toBe(null) }) @@ -276,7 +272,7 @@ describe("getRegistryItem with local files", () => { await fs.writeFile(tempFile, "{ invalid json }") try { - const result = await getRegistryItem(tempFile, "unused-style") + const result = await getRegistryItem(tempFile) expect(result).toBe(null) } finally { // Clean up @@ -297,7 +293,7 @@ describe("getRegistryItem with local files", () => { await fs.writeFile(tempFile, JSON.stringify(invalidData)) try { - const result = await getRegistryItem(tempFile, "unused-style") + const result = await getRegistryItem(tempFile) expect(result).toBe(null) } finally { // Clean up @@ -308,7 +304,7 @@ describe("getRegistryItem with local files", () => { it("should still handle URLs and component names", async () => { // Test that existing functionality still works - const result = await getRegistryItem("button", "new-york") + const result = await getRegistryItem("button") expect(result).toMatchObject({ name: "button", type: "registry:ui", @@ -353,7 +349,7 @@ describe("getRegistryItem with local files", () => { await fs.writeFile(tempFile, JSON.stringify(componentData, null, 2)) try { - const result = await getRegistryItem(tempFile, "unused-style") + const result = await getRegistryItem(tempFile) expect(result).toMatchObject({ name: "component-with-url-deps", @@ -427,4 +423,181 @@ describe("registryResolveItemsTree with URL dependencies", () => { await fs.rmdir(tempDir) } }) + + it("should resolve namespace syntax in registryDependencies", async () => { + // Mock a namespace registry endpoint + const namespaceUrl = "https://custom-registry.com/custom-component.json" + server.use( + http.get(namespaceUrl, () => { + return HttpResponse.json({ + name: "custom-component", + type: "registry:ui", + files: [ + { + path: "ui/custom-component.tsx", + content: "// custom component content", + type: "registry:ui", + }, + ], + }) + }) + ) + + const tempDir = await fs.mkdtemp(path.join(tmpdir(), "shadcn-test-")) + const tempFile = path.join(tempDir, "component-with-namespace-deps.json") + + const componentData = { + name: "component-with-namespace-deps", + type: "registry:ui", + registryDependencies: ["@custom/custom-component"], // Namespace dependency + files: [ + { + path: "ui/component-with-namespace-deps.tsx", + content: "// component with namespace deps content", + type: "registry:ui", + }, + ], + } + + await fs.writeFile(tempFile, JSON.stringify(componentData, null, 2)) + + try { + const mockConfig = { + style: "new-york", + tailwind: { baseColor: "neutral", cssVariables: true }, + resolvedPaths: { cwd: process.cwd() }, + registries: { + "@custom": { + url: "https://custom-registry.com/{name}.json", + }, + }, + } as any + + const result = await registryResolveItemsTree([tempFile], mockConfig) + + expect(result).toBeDefined() + expect(result?.files).toBeDefined() + + expect(result?.files?.length).toBe(2) + expect( + result?.files?.some((f) => f.path === "ui/custom-component.tsx") + ).toBe(true) + expect( + result?.files?.some( + (f) => f.path === "ui/component-with-namespace-deps.tsx" + ) + ).toBe(true) + } finally { + // Clean up + await fs.unlink(tempFile) + await fs.rmdir(tempDir) + } + }) +}) + +describe("getRegistry", () => { + beforeEach(() => { + clearRegistryCache() + }) + + it("should fetch registry catalog", async () => { + const registryData = { + name: "@acme/registry", + homepage: "https://acme.com", + items: [ + { name: "button", type: "registry:ui" }, + { name: "card", type: "registry:ui" }, + ], + } + + server.use( + http.get("https://acme.com/registry.json", () => { + return HttpResponse.json(registryData) + }) + ) + + const mockConfig = { + style: "new-york", + tailwind: { baseColor: "neutral", cssVariables: true }, + registries: { + "@acme": { + url: "https://acme.com/{name}.json", + }, + }, + } as any + + const result = await getRegistry("@acme/registry", mockConfig) + + expect(result).toMatchObject({ + name: "@acme/registry", + homepage: "https://acme.com", + items: [ + { name: "button", type: "registry:ui" }, + { name: "card", type: "registry:ui" }, + ], + }) + }) + + it("should handle registry with auth headers", async () => { + const registryData = { + name: "@private/registry", + homepage: "https://private.com", + items: [{ name: "secure-component", type: "registry:ui" }], + } + + let receivedHeaders: Record = {} + server.use( + http.get("https://private.com/registry.json", ({ request }) => { + // Convert headers to a plain object + request.headers.forEach((value, key) => { + receivedHeaders[key] = value + }) + return HttpResponse.json(registryData) + }) + ) + + const mockConfig = { + style: "new-york", + tailwind: { baseColor: "neutral", cssVariables: true }, + registries: { + "@private": { + url: "https://private.com/{name}.json", + headers: { + Authorization: "Bearer test-token", + }, + }, + }, + } as any + + const result = await getRegistry("@private/registry", mockConfig) + + expect(result).toMatchObject({ + name: "@private/registry", + homepage: "https://private.com", + items: [{ name: "secure-component", type: "registry:ui" }], + }) + + expect(receivedHeaders.authorization).toBe("Bearer test-token") + }) + + it("should return null on error", async () => { + server.use( + http.get("https://example.com/registry.json", () => { + return HttpResponse.json({ error: "Not found" }, { status: 404 }) + }) + ) + + const mockConfig = { + style: "new-york", + tailwind: { baseColor: "neutral", cssVariables: true }, + registries: { + "@example": { + url: "https://example.com/{name}.json", + }, + }, + } as any + + const result = await getRegistry("@example/registry", mockConfig) + expect(result).toBe(null) + }) }) diff --git a/packages/shadcn/src/registry/api.ts b/packages/shadcn/src/registry/api.ts index af2291c43..eca5c19ce 100644 --- a/packages/shadcn/src/registry/api.ts +++ b/packages/shadcn/src/registry/api.ts @@ -1,8 +1,19 @@ import { promises as fs } from "fs" import { homedir } from "os" import path from "path" +import { buildUrlAndHeadersForRegistryItem } from "@/src/registry/builder" +import { + clearRegistryContext, + getRegistryHeadersFromContext, +} from "@/src/registry/context" +import { parseRegistryAndItemFromString } from "@/src/registry/parser" +import { resolveRegistryItemsFromRegistries } from "@/src/registry/resolver" import { isLocalFile } from "@/src/registry/utils" -import { Config, getTargetStyleFromConfig } from "@/src/utils/get-config" +import { + Config, + createConfig, + getTargetStyleFromConfig, +} from "@/src/utils/get-config" import { getProjectTailwindVersionFromConfig } from "@/src/utils/get-project-info" import { handleError } from "@/src/utils/handle-error" import { highlighter } from "@/src/utils/highlighter" @@ -13,17 +24,18 @@ import { HttpsProxyAgent } from "https-proxy-agent" import fetch from "node-fetch" import { z } from "zod" +import { REGISTRY_URL } from "./constants" import { iconsSchema, registryBaseColorSchema, registryIndexSchema, registryItemSchema, registryResolvedItemsTreeSchema, + registrySchema, stylesSchema, + type RegistryItem, } from "./schema" -const REGISTRY_URL = process.env.REGISTRY_URL ?? "https://ui.shadcn.com/r" - const agent = process.env.https_proxy ? new HttpsProxyAgent(process.env.https_proxy) : undefined @@ -86,19 +98,29 @@ export async function getRegistryIcons() { } } -export async function getRegistryItem(name: string, style: string) { +export async function getRegistryItem( + name: string, + config?: Config +): Promise { try { - // Handle local file paths if (isLocalFile(name)) { return await getLocalRegistryItem(name) } - // Handle URLs and component names - const [result] = await fetchRegistry([ - isUrl(name) ? name : `styles/${style}/${name}.json`, - ]) + if (isUrl(name)) { + const [result] = await fetchFromRegistry([name], config) + return result + } - return registryItemSchema.parse(result) + if (name.startsWith("@") && config?.registries) { + const [result] = await fetchFromRegistry([name], config) + return result + } + + // Handle regular component names + const path = `styles/${config?.style ?? "new-york-v4"}/${name}.json` + const [result] = await fetchFromRegistry([path], config) + return result } catch (error) { logger.break() handleError(error) @@ -126,6 +148,22 @@ async function getLocalRegistryItem(filePath: string) { } } +export async function getRegistry(name: `${string}/registry`, config?: Config) { + try { + const results = await fetchFromRegistry([name], config, { useCache: false }) + + if (!results?.length) { + return null + } + + return registrySchema.parse(results[0]) + } catch (error) { + logger.break() + handleError(error) + return null + } +} + export async function getRegistryBaseColors() { return BASE_COLORS } @@ -225,7 +263,15 @@ export async function fetchRegistry( // Store the promise in the cache before awaiting if caching is enabled const fetchPromise = (async () => { - const response = await fetch(url, { agent }) + // Get headers from context for this URL + const headers = getRegistryHeadersFromContext(url) + + const response = await fetch(url, { + agent, + headers: { + ...headers, + }, + }) if (!response.ok) { const errorMessages: { [key: number]: string } = { @@ -236,11 +282,30 @@ export async function fetchRegistry( 500: "Internal server error", } + let errorDetails = "" + try { + const result = await response.json() + if (result && typeof result === "object") { + const messages = [] + if ("error" in result && result.error) { + messages.push(`[${result.error}]: `) + } + if ("message" in result && result.message) { + messages.push(result.message) + } + if (messages.length > 0) { + errorDetails = `\n\nServer response: \n${messages.join("")}` + } + } + } catch { + // If we can't parse JSON, that's okay + } + if (response.status === 401) { throw new Error( `You are not authorized to access the component at ${highlighter.info( url - )}.\nIf this is a remote registry, you may need to authenticate.` + )}.\nIf this is a remote registry, you may need to authenticate.${errorDetails}` ) } @@ -248,7 +313,7 @@ export async function fetchRegistry( throw new Error( `The component at ${highlighter.info( url - )} was not found.\nIt may not exist at the registry. Please make sure it is a valid component.` + )} was not found.\nIt may not exist at the registry. Please make sure it is a valid component.${errorDetails}` ) } @@ -256,17 +321,16 @@ export async function fetchRegistry( throw new Error( `You do not have access to the component at ${highlighter.info( url - )}.\nIf this is a remote registry, you may need to authenticate or a token.` + )}.\nIf this is a remote registry, you may need to authenticate or a token.${errorDetails}` ) } - const result = await response.json() - const message = - result && typeof result === "object" && "error" in result - ? result.error - : response.statusText || errorMessages[response.status] throw new Error( - `Failed to fetch from ${highlighter.info(url)}.\n${message}` + `Failed to fetch from ${highlighter.info(url)}.\n${ + errorDetails || + response.statusText || + errorMessages[response.status] + }` ) } @@ -292,26 +356,79 @@ export function clearRegistryCache() { registryCache.clear() } +async function getResolvedStyle(config?: Config) { + if (!config) { + return undefined + } + + const tailwindVersion = await getProjectTailwindVersionFromConfig(config) + return tailwindVersion === "v4" && config.style === "new-york" + ? "new-york-v4" + : config.style +} + +export async function fetchFromRegistry( + items: `${string}/registry`[], + config?: Config, + options?: { useCache?: boolean } +): Promise[]> + +export async function fetchFromRegistry( + items: string[], + config?: Config, + options?: { useCache?: boolean } +): Promise[]> + +export async function fetchFromRegistry( + items: string[], + config?: Config, + options: { useCache?: boolean } = {} +): Promise< + (z.infer | z.infer)[] +> { + clearRegistryContext() + + const resolvedStyle = await getResolvedStyle(config) + const configWithStyle = + config && resolvedStyle ? { ...config, style: resolvedStyle } : config + const paths = configWithStyle + ? resolveRegistryItemsFromRegistries(items, configWithStyle) + : items + + const results = await fetchRegistry(paths, options) + + return results.map((result, index) => { + const originalItem = items[index] + const resolvedItem = paths[index] + + if ( + originalItem.endsWith("/registry") || + resolvedItem.endsWith("/registry.json") + ) { + return registrySchema.parse(result) + } + + return registryItemSchema.parse(result) + }) +} + async function resolveDependenciesRecursively( dependencies: string[], config?: Config, visited: Set = new Set() -): Promise<{ - items: z.infer[] - registryNames: string[] -}> { +) { const items: z.infer[] = [] const registryNames: string[] = [] for (const dep of dependencies) { - // Avoid infinite recursion. if (visited.has(dep)) { continue } visited.add(dep) + // Handle URLs and local files directly if (isUrl(dep) || isLocalFile(dep)) { - const item = await getRegistryItem(dep, "") + const item = await getRegistryItem(dep, config) if (item) { items.push(item) if (item.registryDependencies) { @@ -324,21 +441,41 @@ async function resolveDependenciesRecursively( registryNames.push(...nested.registryNames) } } - } else { - // Registry name - add it to the list + } + // Handle namespaced items (e.g., @one/foo, @two/bar) + else if (dep.startsWith("@") && config?.registries) { + // Check if the registry exists + const { registry } = parseRegistryAndItemFromString(dep) + if (registry && !(registry in config.registries)) { + throw new Error( + `The items you're adding depend on unknown registry ${registry}. \nMake sure it is defined in components.json as follows:\n` + + `{\n "registries": {\n "${registry}": "https://example.com/{name}.json"\n }\n}` + ) + } + + // Let getRegistryItem handle the namespaced item with config + // This ensures proper authentication headers are used + const item = await getRegistryItem(dep, config) + if (item) { + items.push(item) + if (item.registryDependencies) { + const nested = await resolveDependenciesRecursively( + item.registryDependencies, + config, + visited + ) + items.push(...nested.items) + registryNames.push(...nested.registryNames) + } + } + } + // Handle regular component names + else { registryNames.push(dep) - // If we have config, we can also fetch the item to get its dependencies if (config) { - const style = config.resolvedPaths?.cwd - ? await getTargetStyleFromConfig( - config.resolvedPaths.cwd, - config.style - ) - : config.style - try { - const item = await getRegistryItem(dep, style) + const item = await getRegistryItem(dep, config) if (item && item.registryDependencies) { const nested = await resolveDependenciesRecursively( item.registryDependencies, @@ -349,7 +486,7 @@ async function resolveDependenciesRecursively( registryNames.push(...nested.registryNames) } } catch (error) { - // If we can't fetch the registry item, that's okay - we'll still include the name + // If we can't fetch the registry item, that's okay - we'll still include the name. } } } @@ -363,6 +500,19 @@ export async function registryResolveItemsTree( config: Config ) { try { + // Check for namespaced items when no registries are configured + const namespacedItems = names.filter( + (name) => !isLocalFile(name) && !isUrl(name) && name.startsWith("@") + ) + + if (namespacedItems.length > 0 && !config?.registries) { + const { registry } = parseRegistryAndItemFromString(namespacedItems[0]) + throw new Error( + `Unknown registry "${registry}". Make sure it is defined in components.json as follows:\n` + + `{\n "registries": {\n "${registry}": "https://example.com/{name}.json"\n }\n}` + ) + } + // Separate local files, URLs, and registry names. const localFiles = names.filter((name) => isLocalFile(name)) const urls = names.filter((name) => isUrl(name)) @@ -372,60 +522,161 @@ export async function registryResolveItemsTree( const payload: z.infer[] = [] - // Handle local files and URLs directly, collecting their dependencies. - const allDependencies: string[] = [] + // Handle local files and URLs directly, resolving their dependencies individually. + let allDependencyItems: z.infer[] = [] + let allDependencyRegistryNames: string[] = [] + + const resolvedStyle = await getResolvedStyle(config) + const configWithStyle = + config && resolvedStyle ? { ...config, style: resolvedStyle } : config for (const localFile of localFiles) { - const item = await getRegistryItem(localFile, "") + const item = await getRegistryItem(localFile) if (item) { payload.push(item) if (item.registryDependencies) { - allDependencies.push(...item.registryDependencies) + // Resolve namespace syntax and set headers for dependencies + let resolvedDependencies = item.registryDependencies + + // Check for namespaced dependencies when no registries are configured + if (!config?.registries) { + const namespacedDeps = item.registryDependencies.filter((dep) => + dep.startsWith("@") + ) + if (namespacedDeps.length > 0) { + const { registry } = parseRegistryAndItemFromString( + namespacedDeps[0] + ) + throw new Error( + `The items you're adding depend on unknown registry ${registry}. \nMake sure it is defined in components.json as follows:\n` + + `{\n "registries": {\n "${registry}": "https://example.com/{name}.json"\n }\n}` + ) + } + } else { + resolvedDependencies = resolveRegistryItemsFromRegistries( + item.registryDependencies, + configWithStyle + ) + } + + const { items, registryNames } = await resolveDependenciesRecursively( + resolvedDependencies, + config, + new Set() + ) + allDependencyItems.push(...items) + allDependencyRegistryNames.push(...registryNames) } } } for (const url of urls) { - const item = await getRegistryItem(url, "") + const item = await getRegistryItem(url, config) if (item) { payload.push(item) if (item.registryDependencies) { - allDependencies.push(...item.registryDependencies) + // Resolve namespace syntax and set headers for dependencies + let resolvedDependencies = item.registryDependencies + + // Check for namespaced dependencies when no registries are configured + if (!config?.registries) { + const namespacedDeps = item.registryDependencies.filter((dep) => + dep.startsWith("@") + ) + if (namespacedDeps.length > 0) { + const { registry } = parseRegistryAndItemFromString( + namespacedDeps[0] + ) + throw new Error( + `The items you're adding depend on unknown registry ${registry}. \nMake sure it is defined in components.json as follows:\n` + + `{\n "registries": {\n "${registry}": "https://example.com/{name}.json"\n }\n}` + ) + } + } else { + resolvedDependencies = resolveRegistryItemsFromRegistries( + item.registryDependencies, + configWithStyle + ) + } + + const { items, registryNames } = await resolveDependenciesRecursively( + resolvedDependencies, + config, + new Set() + ) + + allDependencyItems.push(...items) + allDependencyRegistryNames.push(...registryNames) } } } - // Recursively resolve all dependencies. - const { items: dependencyItems, registryNames: dependencyRegistryNames } = - await resolveDependenciesRecursively(allDependencies, config) + payload.push(...allDependencyItems) - payload.push(...dependencyItems) - - // Handle registry names using existing resolveRegistryItems logic. - const allRegistryNames = [...registryNames, ...dependencyRegistryNames] + // Handle registry names using the new fetchFromRegistry logic. + const allRegistryNames = [...registryNames, ...allDependencyRegistryNames] if (allRegistryNames.length > 0) { - const index = await getRegistryIndex() - if (!index) { - // If we only have local files or URLs, that's fine. - if (payload.length === 0) { + // Separate namespaced and non-namespaced items + const nonNamespacedItems = allRegistryNames.filter( + (name) => !name.startsWith("@") + ) + const namespacedItems = allRegistryNames.filter((name) => + name.startsWith("@") + ) + + // Handle namespaced items directly with fetchFromRegistry + if (namespacedItems.length > 0) { + const results = await fetchFromRegistry(namespacedItems, config) + const namespacedPayload = results as z.infer< + typeof registryItemSchema + >[] + payload.push(...namespacedPayload) + + // Process dependencies of namespaced items + for (const item of namespacedPayload) { + if (item.registryDependencies) { + const { items: depItems, registryNames: depNames } = + await resolveDependenciesRecursively( + item.registryDependencies, + config, + new Set([...namespacedItems]) + ) + payload.push(...depItems) + + // Add any non-namespaced dependencies to be processed + const nonNamespacedDeps = depNames.filter( + (name) => !name.startsWith("@") + ) + nonNamespacedItems.push(...nonNamespacedDeps) + } + } + } + + // For non-namespaced items, we need the index and style resolution + if (nonNamespacedItems.length > 0) { + const index = await getRegistryIndex() + if (!index && payload.length === 0) { return null } - } else { - // Remove duplicates. - const uniqueRegistryNames = Array.from(new Set(allRegistryNames)) - // If we're resolving the index, we want it to go first. - if (uniqueRegistryNames.includes("index")) { - uniqueRegistryNames.unshift("index") + if (index) { + // Remove duplicates from non-namespaced items + const uniqueNonNamespaced = Array.from(new Set(nonNamespacedItems)) + + // If we're resolving the index, we want it to go first + if (uniqueNonNamespaced.includes("index")) { + uniqueNonNamespaced.unshift("index") + } + + // Resolve non-namespaced items through the existing flow + let registryItems = await resolveRegistryItems( + uniqueNonNamespaced, + config + ) + let result = await fetchRegistry(registryItems) + const registryPayload = z.array(registryItemSchema).parse(result) + payload.push(...registryPayload) } - - let registryItems = await resolveRegistryItems( - uniqueRegistryNames, - config - ) - let result = await fetchRegistry(registryItems) - const registryPayload = z.array(registryItemSchema).parse(result) - payload.push(...registryPayload) } } @@ -446,12 +697,16 @@ export async function registryResolveItemsTree( } } - // Sort the payload so that registry:theme is always first. + // Sort the payload so that registry:theme items come first, + // while maintaining the relative order of all items. payload.sort((a, b) => { - if (a.type === "registry:theme") { + if (a.type === "registry:theme" && b.type !== "registry:theme") { return -1 } - return 1 + if (a.type !== "registry:theme" && b.type === "registry:theme") { + return 1 + } + return 0 }) let tailwind = {} @@ -506,11 +761,16 @@ export async function registryResolveItemsTree( } } -async function resolveRegistryDependencies( - url: string, - config: Config -): Promise { - const { registryNames } = await resolveDependenciesRecursively([url], config) +async function resolveRegistryDependencies(url: string, config: Config) { + if (isUrl(url)) { + return [url] + } + + const { registryNames } = await resolveDependenciesRecursively( + [url], + config, + new Set() + ) const style = config.resolvedPaths?.cwd ? await getTargetStyleFromConfig(config.resolvedPaths.cwd, config.style) @@ -627,14 +887,30 @@ export function isUrl(path: string) { export async function resolveRegistryItems(names: string[], config: Config) { let registryDependencies: string[] = [] - // Filter out local files and URLs - these should be handled directly by getRegistryItem const registryNames = names.filter( (name) => !isLocalFile(name) && !isUrl(name) ) + const resolvedStyle = await getResolvedStyle(config) for (const name of registryNames) { + let resolvedName = name + if (config) { + try { + const configWithStyle = + config && resolvedStyle ? { ...config, style: resolvedStyle } : config + + const resolved = buildUrlAndHeadersForRegistryItem( + name, + configWithStyle + ) + if (resolved) { + resolvedName = resolved.url + } + } catch (error) {} + } + const itemRegistryDependencies = await resolveRegistryDependencies( - name, + resolvedName, config ) registryDependencies.push(...itemRegistryDependencies) diff --git a/packages/shadcn/src/registry/builder.test.ts b/packages/shadcn/src/registry/builder.test.ts new file mode 100644 index 000000000..099fdb273 --- /dev/null +++ b/packages/shadcn/src/registry/builder.test.ts @@ -0,0 +1,449 @@ +/* eslint-disable turbo/no-undeclared-env-vars */ +import { afterEach, beforeEach, describe, expect, it } from "vitest" + +import { + buildHeadersFromRegistryConfig, + buildUrlAndHeadersForRegistryItem, + buildUrlFromRegistryConfig, +} from "./builder" + +describe("buildUrlFromRegistryConfig", () => { + beforeEach(() => { + process.env.TEST_TOKEN = "abc123" + process.env.API_VERSION = "v2" + process.env.API_KEY = "key456" + }) + + afterEach(() => { + delete process.env.TEST_TOKEN + delete process.env.API_VERSION + delete process.env.API_KEY + }) + + it("should build URL from string config", () => { + const url = buildUrlFromRegistryConfig( + "chat-component", + "https://v0.dev/chat/b/{name}/json" + ) + expect(url).toBe("https://v0.dev/chat/b/chat-component/json") + }) + + it("should replace style placeholder in URL", () => { + const url = buildUrlFromRegistryConfig( + "button", + "https://ui.shadcn.com/r/styles/{style}/{name}.json", + { style: "new-york" } as any + ) + expect(url).toBe("https://ui.shadcn.com/r/styles/new-york/button.json") + }) + + it("should handle both name and style placeholders", () => { + const url = buildUrlFromRegistryConfig( + "accordion", + "https://example.com/{style}/components/{name}", + { style: "default" } as any + ) + expect(url).toBe("https://example.com/default/components/accordion") + }) + + it("should build URL with env vars", () => { + const url = buildUrlFromRegistryConfig( + "button", + "https://api.com/{name}?token=${TEST_TOKEN}" + ) + expect(url).toBe("https://api.com/button?token=abc123") + }) + + it("should build URL with params", () => { + const config = { + url: "https://api.com/{name}", + params: { + version: "${API_VERSION}", + format: "json", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table?version=v2&format=json") + }) + + it("should skip empty param values", () => { + const config = { + url: "https://api.com/{name}", + params: { + token: "${MISSING_VAR}", + format: "json", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table?format=json") + }) + + it("should handle existing query params", () => { + const config = { + url: "https://api.com/{name}?existing=true", + params: { + new: "param", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table?existing=true&new=param") + }) + + it("should handle URL with no params", () => { + const config = { + url: "https://api.com/{name}", + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table") + }) + + it("should handle multiple env vars in params", () => { + const config = { + url: "https://api.com/{name}", + params: { + token: "${TEST_TOKEN}", + version: "${API_VERSION}", + key: "${API_KEY}", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table?token=abc123&version=v2&key=key456") + }) + + it("should handle all empty env vars in params", () => { + const config = { + url: "https://api.com/{name}", + params: { + token: "${MISSING_VAR1}", + key: "${MISSING_VAR2}", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table") + }) + + it("should handle mixed static and env var params", () => { + const config = { + url: "https://api.com/{name}", + params: { + static: "value", + env: "${TEST_TOKEN}", + empty: "${MISSING_VAR}", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe("https://api.com/table?static=value&env=abc123") + }) + + it("should handle special characters in params", () => { + const config = { + url: "https://api.com/{name}", + params: { + "user-id": "123", + "api-key": "${TEST_TOKEN}", + "content-type": "application/json", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe( + "https://api.com/table?user-id=123&api-key=abc123&content-type=application%2Fjson" + ) + }) + + it("should handle URL with multiple existing query params", () => { + const config = { + url: "https://api.com/{name}?param1=value1¶m2=value2", + params: { + newParam: "newValue", + envParam: "${TEST_TOKEN}", + }, + } + + const url = buildUrlFromRegistryConfig("table", config) + expect(url).toBe( + "https://api.com/table?param1=value1¶m2=value2&newParam=newValue&envParam=abc123" + ) + }) +}) + +describe("buildHeadersFromRegistryConfig", () => { + beforeEach(() => { + process.env.AUTH_TOKEN = "secret123" + process.env.CLIENT_ID = "client456" + process.env.API_KEY = "key789" + }) + + afterEach(() => { + delete process.env.AUTH_TOKEN + delete process.env.CLIENT_ID + delete process.env.API_KEY + }) + + it("should return empty object for string config", () => { + expect(buildHeadersFromRegistryConfig("https://api.com/{name}")).toEqual({}) + }) + + it("should return empty object for config without headers", () => { + expect( + buildHeadersFromRegistryConfig({ url: "https://api.com/{name}" }) + ).toEqual({}) + }) + + it("should expand headers with env vars", () => { + const config = { + url: "https://api.com/{name}", + headers: { + Authorization: "Bearer ${AUTH_TOKEN}", + "X-Client-Id": "${CLIENT_ID}", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + Authorization: "Bearer secret123", + "X-Client-Id": "client456", + }) + }) + + it("should skip headers with empty values", () => { + const config = { + url: "https://api.com/{name}", + headers: { + Authorization: "Bearer ${MISSING_VAR}", + "X-Client-Id": "${CLIENT_ID}", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "X-Client-Id": "client456", + }) + }) + + it("should handle headers with mixed static and env var content", () => { + const config = { + url: "https://api.com/{name}", + headers: { + Authorization: "Bearer ${AUTH_TOKEN}", + "Content-Type": "application/json", + "X-Custom": "prefix-${CLIENT_ID}-suffix", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + Authorization: "Bearer secret123", + "Content-Type": "application/json", + "X-Custom": "prefix-client456-suffix", + }) + }) + + it("should skip headers with only env vars that are empty", () => { + const config = { + url: "https://api.com/{name}", + headers: { + "X-Missing": "${MISSING_VAR1}", + "X-Also-Missing": "${MISSING_VAR2}", + "X-Present": "${CLIENT_ID}", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "X-Present": "client456", + }) + }) + + it("should handle headers with whitespace-only values", () => { + const config = { + url: "https://api.com/{name}", + headers: { + "X-Empty": " ", + "X-Whitespace": " ${MISSING_VAR} ", + "X-Valid": " ${CLIENT_ID} ", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "X-Valid": " client456 ", + }) + }) + + it("should handle complex env var patterns", () => { + const config = { + url: "https://api.com/{name}", + headers: { + "X-Complex": "Bearer ${AUTH_TOKEN} with ${CLIENT_ID} and ${API_KEY}", + "X-Simple": "${CLIENT_ID}", + "X-Mixed": "static-${AUTH_TOKEN}-${MISSING_VAR}-${API_KEY}", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "X-Complex": "Bearer secret123 with client456 and key789", + "X-Simple": "client456", + "X-Mixed": "static-secret123--key789", + }) + }) + + it("should handle headers with only static content", () => { + const config = { + url: "https://api.com/{name}", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "User-Agent": "shadcn-ui/1.0.0", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "Content-Type": "application/json", + Accept: "application/json", + "User-Agent": "shadcn-ui/1.0.0", + }) + }) + + it("should handle headers with template-like content but no env vars", () => { + const config = { + url: "https://api.com/{name}", + headers: { + "X-Template": "This is a template ${but not an env var}", + "X-Regular": "Regular header value", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "X-Template": "This is a template ${but not an env var}", + "X-Regular": "Regular header value", + }) + }) + + it("should handle case where env var expansion doesn't change the value", () => { + const config = { + url: "https://api.com/{name}", + headers: { + "X-No-Change": "static value", + "X-With-Env": "prefix-${CLIENT_ID}-suffix", + }, + } + + expect(buildHeadersFromRegistryConfig(config)).toEqual({ + "X-No-Change": "static value", + "X-With-Env": "prefix-client456-suffix", + }) + }) +}) + +describe("buildUrlAndHeadersForRegistryItem", () => { + it("should return null for non-registry items", () => { + const input = "button" + const config = {} as any + expect(buildUrlAndHeadersForRegistryItem(input, config)).toBeNull() + }) + + it("should throw error for unknown registry", () => { + expect(() => { + buildUrlAndHeadersForRegistryItem("@unknown/button", {} as any) + }).toThrow('Unknown registry "@unknown"') + }) + + it("should resolve registry items with string config", () => { + const config = { + registries: { + "@v0": "https://v0.dev/chat/b/{name}/json", + }, + } as any + + const result1 = buildUrlAndHeadersForRegistryItem("@v0/button", config) + expect(result1).toEqual({ + url: "https://v0.dev/chat/b/button/json", + headers: {}, + }) + + const result2 = buildUrlAndHeadersForRegistryItem("@v0/data-table", config) + expect(result2).toEqual({ + url: "https://v0.dev/chat/b/data-table/json", + headers: {}, + }) + }) + + it("should resolve registry items with object config", () => { + const config = { + registries: { + "@test": { + url: "https://api.com/{name}.json", + headers: { + Authorization: "Bearer token123", + }, + }, + }, + } as any + + const result = buildUrlAndHeadersForRegistryItem("@test/button", config) + expect(result).toEqual({ + url: "https://api.com/button.json", + headers: { + Authorization: "Bearer token123", + }, + }) + }) + + it("should handle environment variables in config", () => { + process.env.TEST_TOKEN = "abc123" + process.env.API_URL = "https://api.com" + + const config = { + registries: { + "@env": { + url: "${API_URL}/{name}.json", + headers: { + Authorization: "Bearer ${TEST_TOKEN}", + }, + }, + }, + } as any + + const result = buildUrlAndHeadersForRegistryItem("@env/button", config) + expect(result).toEqual({ + url: "https://api.com/button.json", + headers: { + Authorization: "Bearer abc123", + }, + }) + + delete process.env.TEST_TOKEN + delete process.env.API_URL + }) + + it("should handle complex item paths", () => { + const config = { + registries: { + "@acme": "https://api.com/{name}.json", + }, + } as any + + const result = buildUrlAndHeadersForRegistryItem("@acme/ui/button", config) + expect(result).toEqual({ + url: "https://api.com/ui/button.json", + headers: {}, + }) + }) + + it("should handle URLs and local files", () => { + const config = { registries: {} } as any + + // URLs should return null (not registry items) + expect( + buildUrlAndHeadersForRegistryItem("https://example.com/button", config) + ).toBeNull() + + // Local files should return null (not registry items) + expect( + buildUrlAndHeadersForRegistryItem("./local/button", config) + ).toBeNull() + }) +}) diff --git a/packages/shadcn/src/registry/builder.ts b/packages/shadcn/src/registry/builder.ts new file mode 100644 index 000000000..089da051f --- /dev/null +++ b/packages/shadcn/src/registry/builder.ts @@ -0,0 +1,131 @@ +import { parseRegistryAndItemFromString } from "@/src/registry/parser" +import { configSchema, registryConfigItemSchema } from "@/src/registry/schema" +import { validateRegistryConfig } from "@/src/registry/validator" +import { z } from "zod" + +import { expandEnvVars } from "./env" + +const NAME_PLACEHOLDER = "{name}" +const STYLE_PLACEHOLDER = "{style}" +const ENV_VAR_PATTERN = /\${(\w+)}/g +const QUERY_PARAM_SEPARATOR = "?" +const QUERY_PARAM_DELIMITER = "&" + +export function buildUrlAndHeadersForRegistryItem( + name: string, + config?: z.infer +) { + const { registry, item } = parseRegistryAndItemFromString(name) + + if (!registry) { + return null + } + + const registries = config?.registries || {} + const registryConfig = registries[registry] + if (!registryConfig) { + throw new Error( + `Unknown registry "${registry}". Make sure it is defined in components.json as follows:\n` + + `{\n "registries": {\n "${registry}": "https://example.com/{name}.json"\n }\n}` + ) + } + + // TODO: I don't like this here. + // But this will do for now. + validateRegistryConfig(registry, registryConfig) + + return { + url: buildUrlFromRegistryConfig(item, registryConfig, config), + headers: buildHeadersFromRegistryConfig(registryConfig), + } +} + +export function buildUrlFromRegistryConfig( + item: string, + registryConfig: z.infer, + config?: z.infer +) { + if (typeof registryConfig === "string") { + let url = registryConfig.replace(NAME_PLACEHOLDER, item) + if (config?.style && url.includes(STYLE_PLACEHOLDER)) { + url = url.replace(STYLE_PLACEHOLDER, config.style) + } + return expandEnvVars(url) + } + + let baseUrl = registryConfig.url.replace(NAME_PLACEHOLDER, item) + if (config?.style && baseUrl.includes(STYLE_PLACEHOLDER)) { + baseUrl = baseUrl.replace(STYLE_PLACEHOLDER, config.style) + } + baseUrl = expandEnvVars(baseUrl) + + if (!registryConfig.params) { + return baseUrl + } + + return appendQueryParams(baseUrl, registryConfig.params) +} + +export function buildHeadersFromRegistryConfig( + config: z.infer +) { + if (typeof config === "string" || !config.headers) { + return {} + } + + const headers: Record = {} + + for (const [key, value] of Object.entries(config.headers)) { + const expandedValue = expandEnvVars(value) + + if (shouldIncludeHeader(value, expandedValue)) { + headers[key] = expandedValue + } + } + + return headers +} + +function appendQueryParams(baseUrl: string, params: Record) { + const urlParams = new URLSearchParams() + + for (const [key, value] of Object.entries(params)) { + const expandedValue = expandEnvVars(value) + if (expandedValue) { + urlParams.append(key, expandedValue) + } + } + + const queryString = urlParams.toString() + if (!queryString) { + return baseUrl + } + + const separator = baseUrl.includes(QUERY_PARAM_SEPARATOR) + ? QUERY_PARAM_DELIMITER + : QUERY_PARAM_SEPARATOR + + return `${baseUrl}${separator}${queryString}` +} + +function shouldIncludeHeader(originalValue: string, expandedValue: string) { + const trimmedExpanded = expandedValue.trim() + + if (!trimmedExpanded) { + return false + } + + // If the original value contains valid env vars, only include if expansion changed the value. + if (originalValue.includes("${")) { + // Check if there are actual env vars in the string + const envVars = originalValue.match(ENV_VAR_PATTERN) + if (envVars) { + const templateWithoutVars = originalValue + .replace(ENV_VAR_PATTERN, "") + .trim() + return trimmedExpanded !== templateWithoutVars + } + } + + return true +} diff --git a/packages/shadcn/src/registry/constants.ts b/packages/shadcn/src/registry/constants.ts index a996659cb..ab26eb8b9 100644 --- a/packages/shadcn/src/registry/constants.ts +++ b/packages/shadcn/src/registry/constants.ts @@ -1,3 +1,15 @@ +import { z } from "zod" + +import { registryConfigSchema } from "./schema" + +export const REGISTRY_URL = + process.env.REGISTRY_URL ?? "https://ui.shadcn.com/r" + +// Built-in registries that are always available and cannot be overridden +export const BUILTIN_REGISTRIES: z.infer = { + "@shadcn": `${REGISTRY_URL}/styles/{style}/{name}.json`, +} + export const BUILTIN_MODULES = new Set([ [ // Node.js built-in modules diff --git a/packages/shadcn/src/registry/context.ts b/packages/shadcn/src/registry/context.ts new file mode 100644 index 000000000..cd6db4272 --- /dev/null +++ b/packages/shadcn/src/registry/context.ts @@ -0,0 +1,23 @@ +interface RegistryContext { + headers: Record> +} + +let context: RegistryContext = { + headers: {}, +} + +export function setRegistryHeaders( + headers: Record> +) { + context.headers = headers +} + +export function getRegistryHeadersFromContext( + url: string +): Record { + return context.headers[url] || {} +} + +export function clearRegistryContext() { + context.headers = {} +} diff --git a/packages/shadcn/src/registry/env.test.ts b/packages/shadcn/src/registry/env.test.ts new file mode 100644 index 000000000..8712b89ad --- /dev/null +++ b/packages/shadcn/src/registry/env.test.ts @@ -0,0 +1,46 @@ +/* eslint-disable turbo/no-undeclared-env-vars */ +import { afterEach, beforeEach, describe, expect, it } from "vitest" + +import { expandEnvVars, extractEnvVars } from "./env" + +describe("expandEnvVars", () => { + beforeEach(() => { + process.env.TEST_TOKEN = "abc123" + process.env.API_KEY = "secret" + }) + + afterEach(() => { + delete process.env.TEST_TOKEN + delete process.env.API_KEY + }) + + it("should expand environment variables", () => { + expect(expandEnvVars("Bearer ${TEST_TOKEN}")).toBe("Bearer abc123") + expect(expandEnvVars("key=${API_KEY}&token=${TEST_TOKEN}")).toBe( + "key=secret&token=abc123" + ) + }) + + it("should replace missing env vars with empty string", () => { + expect(expandEnvVars("Bearer ${MISSING_VAR}")).toBe("Bearer ") + expect(expandEnvVars("${VAR1}:${VAR2}")).toBe(":") + }) + + it("should handle strings without env vars", () => { + expect(expandEnvVars("no variables here")).toBe("no variables here") + expect(expandEnvVars("https://example.com")).toBe("https://example.com") + }) +}) + +describe("extractEnvVars", () => { + it("should extract environment variable names", () => { + expect(extractEnvVars("Bearer ${TOKEN}")).toEqual(["TOKEN"]) + expect(extractEnvVars("${VAR1} and ${VAR2}")).toEqual(["VAR1", "VAR2"]) + expect(extractEnvVars("${SAME} and ${SAME}")).toEqual(["SAME", "SAME"]) + }) + + it("should return empty array for no variables", () => { + expect(extractEnvVars("no variables")).toEqual([]) + expect(extractEnvVars("")).toEqual([]) + }) +}) diff --git a/packages/shadcn/src/registry/env.ts b/packages/shadcn/src/registry/env.ts new file mode 100644 index 000000000..463ade8a5 --- /dev/null +++ b/packages/shadcn/src/registry/env.ts @@ -0,0 +1,15 @@ +export function expandEnvVars(value: string) { + return value.replace(/\${(\w+)}/g, (_match, key) => process.env[key] || "") +} + +export function extractEnvVars(value: string) { + const vars: string[] = [] + const regex = /\${(\w+)}/g + let match: RegExpExecArray | null + + while ((match = regex.exec(value)) !== null) { + vars.push(match[1]) + } + + return vars +} diff --git a/packages/shadcn/src/registry/index.ts b/packages/shadcn/src/registry/index.ts index d4aad7070..31911a6a5 100644 --- a/packages/shadcn/src/registry/index.ts +++ b/packages/shadcn/src/registry/index.ts @@ -3,3 +3,5 @@ export { registryResolveItemsTree as internal_registryResolveItemsTree, fetchRegistry, } from "./api" +export { BUILTIN_REGISTRIES, REGISTRY_URL } from "./constants" +export { buildUrlAndHeadersForRegistryItem } from "./builder" diff --git a/packages/shadcn/src/registry/parser.test.ts b/packages/shadcn/src/registry/parser.test.ts new file mode 100644 index 000000000..c40e80a47 --- /dev/null +++ b/packages/shadcn/src/registry/parser.test.ts @@ -0,0 +1,252 @@ +import { describe, expect, it } from "vitest" + +import { parseRegistryAndItemFromString } from "./parser" + +describe("parseRegistryAndItemFromString", () => { + describe("valid registry items", () => { + it.each([ + ["@v0/button", { registry: "@v0", item: "button" }], + ["@acme/data-table", { registry: "@acme", item: "data-table" }], + [ + "@company/nested/component", + { registry: "@company", item: "nested/component" }, + ], + ["@test/simple", { registry: "@test", item: "simple" }], + ["@my-registry/item", { registry: "@my-registry", item: "item" }], + ["@my_registry/item", { registry: "@my_registry", item: "item" }], + ["@123registry/item", { registry: "@123registry", item: "item" }], + ["@registry123/item", { registry: "@registry123", item: "item" }], + ["@r/item", { registry: "@r", item: "item" }], + [ + "@very-long-registry-name/item", + { registry: "@very-long-registry-name", item: "item" }, + ], + ])("should parse registry item: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("non-registry items", () => { + it.each([ + ["button", { registry: null, item: "button" }], + ["components/button", { registry: null, item: "components/button" }], + ["v0/button", { registry: null, item: "v0/button" }], + ["@button", { registry: null, item: "@button" }], + ["button@", { registry: null, item: "button@" }], + ["@", { registry: null, item: "@" }], + ["@/button", { registry: null, item: "@/button" }], + ["@-registry/item", { registry: null, item: "@-registry/item" }], + ["@registry-/item", { registry: null, item: "@registry-/item" }], + ["@-registry-/item", { registry: null, item: "@-registry-/item" }], + ])( + "should return null registry for non-registry item: %s", + (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + } + ) + }) + + describe("URLs and external paths", () => { + it.each([ + [ + "https://example.com/button", + { registry: null, item: "https://example.com/button" }, + ], + [ + "http://localhost:3000/component", + { registry: null, item: "http://localhost:3000/component" }, + ], + [ + "file:///path/to/component", + { registry: null, item: "file:///path/to/component" }, + ], + [ + "ftp://example.com/file", + { registry: null, item: "ftp://example.com/file" }, + ], + [ + "//cdn.example.com/component", + { registry: null, item: "//cdn.example.com/component" }, + ], + ])("should handle URLs: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("complex item paths", () => { + it.each([ + ["@acme/ui/button", { registry: "@acme", item: "ui/button" }], + [ + "@company/components/forms/input", + { registry: "@company", item: "components/forms/input" }, + ], + [ + "@test/nested/deep/path/component", + { registry: "@test", item: "nested/deep/path/component" }, + ], + [ + "@registry/path/with/multiple/slashes", + { registry: "@registry", item: "path/with/multiple/slashes" }, + ], + ])("should handle complex item paths: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("edge cases and special characters", () => { + it.each([ + ["", { registry: null, item: "" }], + ["@", { registry: null, item: "@" }], + ["@@", { registry: null, item: "@@" }], + ["@@@", { registry: null, item: "@@@" }], + ["@/", { registry: null, item: "@/" }], + ["@//", { registry: null, item: "@//" }], + ["@/item", { registry: null, item: "@/item" }], + ["@registry/", { registry: null, item: "@registry/" }], + ["@registry//", { registry: "@registry", item: "/" }], + ["@registry///", { registry: "@registry", item: "//" }], + ])("should handle edge cases: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("registry names with special characters", () => { + it.each([ + ["@my-registry/item", { registry: "@my-registry", item: "item" }], + ["@my_registry/item", { registry: "@my_registry", item: "item" }], + [ + "@my-registry-name/item", + { registry: "@my-registry-name", item: "item" }, + ], + [ + "@my_registry_name/item", + { registry: "@my_registry_name", item: "item" }, + ], + [ + "@my-registry_name/item", + { registry: "@my-registry_name", item: "item" }, + ], + [ + "@my_registry-name/item", + { registry: "@my_registry-name", item: "item" }, + ], + ["@123-registry/item", { registry: "@123-registry", item: "item" }], + ["@registry-123/item", { registry: "@registry-123", item: "item" }], + ["@123_registry/item", { registry: "@123_registry", item: "item" }], + ["@registry_123/item", { registry: "@registry_123", item: "item" }], + ])( + "should handle registry names with special characters: %s", + (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + } + ) + }) + + describe("invalid registry patterns", () => { + it.each([ + ["@-registry/item", { registry: null, item: "@-registry/item" }], + ["@registry-/item", { registry: null, item: "@registry-/item" }], + ["@-registry-/item", { registry: null, item: "@-registry-/item" }], + ["@-item", { registry: null, item: "@-item" }], + ["@item-", { registry: null, item: "@item-" }], + ["@-item-", { registry: null, item: "@-item-" }], + ["@_registry/item", { registry: null, item: "@_registry/item" }], + ["@registry_/item", { registry: null, item: "@registry_/item" }], + ["@_registry_/item", { registry: null, item: "@_registry_/item" }], + ["@_item", { registry: null, item: "@_item" }], + ["@item_", { registry: null, item: "@item_" }], + ["@_item_", { registry: null, item: "@_item_" }], + ])("should reject invalid registry patterns: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("whitespace and formatting", () => { + it.each([ + [" @v0/button", { registry: null, item: " @v0/button" }], + ["@v0/button ", { registry: "@v0", item: "button " }], + [" @v0/button ", { registry: null, item: " @v0/button " }], + ["\t@v0/button", { registry: null, item: "\t@v0/button" }], + ["@v0/button\t", { registry: "@v0", item: "button\t" }], + ["\n@v0/button", { registry: null, item: "\n@v0/button" }], + ["@v0/button\n", { registry: null, item: "@v0/button\n" }], + ])("should handle whitespace: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("case sensitivity", () => { + it.each([ + ["@V0/button", { registry: "@V0", item: "button" }], + ["@v0/BUTTON", { registry: "@v0", item: "BUTTON" }], + ["@V0/BUTTON", { registry: "@V0", item: "BUTTON" }], + ["@MyRegistry/item", { registry: "@MyRegistry", item: "item" }], + ["@MYREGISTRY/item", { registry: "@MYREGISTRY", item: "item" }], + ["@myregistry/ITEM", { registry: "@myregistry", item: "ITEM" }], + ])("should be case sensitive: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("numbers and mixed content", () => { + it.each([ + ["@123/item", { registry: "@123", item: "item" }], + ["@registry123/item", { registry: "@registry123", item: "item" }], + ["@123registry/item", { registry: "@123registry", item: "item" }], + ["@r123/item", { registry: "@r123", item: "item" }], + ["@123r/item", { registry: "@123r", item: "item" }], + ["@item123/item", { registry: "@item123", item: "item" }], + ["@123-item/item", { registry: "@123-item", item: "item" }], + ["@item-123/item", { registry: "@item-123", item: "item" }], + ["@123_item/item", { registry: "@123_item", item: "item" }], + ["@item_123/item", { registry: "@item_123", item: "item" }], + ])("should handle numbers and mixed content: %s", (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + }) + }) + + describe("single character cases", () => { + it.each([ + ["@a/b", { registry: "@a", item: "b" }], + ["@a/", { registry: null, item: "@a/" }], + ["@a//", { registry: "@a", item: "/" }], + ["@1/b", { registry: "@1", item: "b" }], + ["@1/", { registry: null, item: "@1/" }], + ["@1//", { registry: "@1", item: "/" }], + ])( + "should handle single character registry names: %s", + (input, expected) => { + expect(parseRegistryAndItemFromString(input)).toEqual(expected) + } + ) + }) + + describe("very long inputs", () => { + it("should handle very long registry names", () => { + const longRegistry = "@" + "a".repeat(100) + const result = parseRegistryAndItemFromString(longRegistry + "/item") + expect(result).toEqual({ + registry: longRegistry, + item: "item", + }) + }) + + it("should handle very long item paths", () => { + const longItem = "a".repeat(100) + const result = parseRegistryAndItemFromString("@registry/" + longItem) + expect(result).toEqual({ + registry: "@registry", + item: longItem, + }) + }) + + it("should handle very long non-registry paths", () => { + const longPath = "a".repeat(100) + const result = parseRegistryAndItemFromString(longPath) + expect(result).toEqual({ + registry: null, + item: longPath, + }) + }) + }) +}) diff --git a/packages/shadcn/src/registry/parser.ts b/packages/shadcn/src/registry/parser.ts new file mode 100644 index 000000000..2f0042bda --- /dev/null +++ b/packages/shadcn/src/registry/parser.ts @@ -0,0 +1,24 @@ +// Valid registry name pattern: @namespace where namespace is alphanumeric with hyphens/underscores +const REGISTRY_PATTERN = /^(@[a-zA-Z0-9](?:[a-zA-Z0-9-_]*[a-zA-Z0-9])?)\/(.+)$/ + +export function parseRegistryAndItemFromString(name: string) { + if (!name.startsWith("@")) { + return { + registry: null, + item: name, + } + } + + const match = name.match(REGISTRY_PATTERN) + if (match) { + return { + registry: match[1], + item: match[2], + } + } + + return { + registry: null, + item: name, + } +} diff --git a/packages/shadcn/src/registry/resolver.test.ts b/packages/shadcn/src/registry/resolver.test.ts new file mode 100644 index 000000000..27a56d5b5 --- /dev/null +++ b/packages/shadcn/src/registry/resolver.test.ts @@ -0,0 +1,345 @@ +/* eslint-disable turbo/no-undeclared-env-vars */ +import { beforeEach, describe, expect, it, vi } from "vitest" + +import { setRegistryHeaders } from "./context" +import { resolveRegistryItemsFromRegistries } from "./resolver" + +// Mock the context module +vi.mock("./context", () => ({ + setRegistryHeaders: vi.fn(), +})) + +describe("resolveRegistryItemsFromRegistries", () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it("should return empty array for empty input", () => { + const result = resolveRegistryItemsFromRegistries([], { + registries: {}, + } as any) + expect(result).toEqual([]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should return empty array for empty input with no registries", () => { + const result = resolveRegistryItemsFromRegistries([], undefined) + expect(result).toEqual([]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should return non-registry items unchanged", () => { + const items = ["button", "card", "dialog"] + const config = { registries: {} } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual(items) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should resolve registry items with string config", () => { + const items = ["@v0/button", "@v0/card"] + const config = { + registries: { + "@v0": "https://v0.dev/chat/b/{name}/json", + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://v0.dev/chat/b/button/json", + "https://v0.dev/chat/b/card/json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should resolve registry items with object config and headers", () => { + const items = ["@private/button", "@private/card"] + const config = { + registries: { + "@private": { + url: "https://api.com/{name}.json", + headers: { + Authorization: "Bearer token123", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://api.com/button.json", + "https://api.com/card.json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({ + "https://api.com/button.json": { + Authorization: "Bearer token123", + }, + "https://api.com/card.json": { + Authorization: "Bearer token123", + }, + }) + }) + + it("should handle mixed registry and non-registry items", () => { + const items = ["button", "@v0/card", "dialog", "@private/table"] + const config = { + registries: { + "@v0": "https://v0.dev/chat/b/{name}/json", + "@private": { + url: "https://api.com/{name}.json", + headers: { + "X-API-Key": "secret123", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "button", + "https://v0.dev/chat/b/card/json", + "dialog", + "https://api.com/table.json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({ + "https://api.com/table.json": { + "X-API-Key": "secret123", + }, + }) + }) + + it("should handle environment variables in config", () => { + process.env.API_TOKEN = "abc123" + process.env.API_URL = "https://api.com" + + const items = ["@env/button"] + const config = { + registries: { + "@env": { + url: "${API_URL}/{name}.json", + headers: { + Authorization: "Bearer ${API_TOKEN}", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual(["https://api.com/button.json"]) + expect(setRegistryHeaders).toHaveBeenCalledWith({ + "https://api.com/button.json": { + Authorization: "Bearer abc123", + }, + }) + + delete process.env.API_TOKEN + delete process.env.API_URL + }) + + it("should handle complex item paths", () => { + const items = ["@acme/ui/button", "@acme/components/card"] + const config = { + registries: { + "@acme": "https://api.com/{name}.json", + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://api.com/ui/button.json", + "https://api.com/components/card.json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should handle URLs and local files unchanged", () => { + const items = [ + "https://example.com/button.json", + "./local/component.json", + "@v0/card", + ] + const config = { + registries: { + "@v0": "https://v0.dev/chat/b/{name}/json", + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://example.com/button.json", + "./local/component.json", + "https://v0.dev/chat/b/card/json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should throw error for unknown registry", () => { + const items = ["@unknown/button"] + const config = { registries: {} } as any + + expect(() => { + resolveRegistryItemsFromRegistries(items, config) + }).toThrow('Unknown registry "@unknown"') + }) + + it("should handle multiple unknown registries", () => { + const items = ["@unknown1/button", "@unknown2/card"] + const config = { registries: {} } as any + + expect(() => { + resolveRegistryItemsFromRegistries(items, config) + }).toThrow('Unknown registry "@unknown1"') + }) + + it("should handle empty headers correctly", () => { + const items = ["@empty/button"] + const config = { + registries: { + "@empty": { + url: "https://api.com/{name}.json", + headers: {}, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual(["https://api.com/button.json"]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should handle headers with environment variables that expand to empty", () => { + process.env.EMPTY_TOKEN = "some-value" + + const items = ["@empty/button"] + const config = { + registries: { + "@empty": { + url: "https://api.com/{name}.json", + headers: { + Authorization: "Bearer ${EMPTY_TOKEN}", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual(["https://api.com/button.json"]) + expect(setRegistryHeaders).toHaveBeenCalledWith({ + "https://api.com/button.json": { + Authorization: "Bearer some-value", + }, + }) + + delete process.env.EMPTY_TOKEN + }) + + it("should handle headers with mixed static and environment variables", () => { + process.env.API_TOKEN = "secret123" + + const items = ["@mixed/button"] + const config = { + registries: { + "@mixed": { + url: "https://api.com/{name}.json", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer ${API_TOKEN}", + "X-Custom": "static-value", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual(["https://api.com/button.json"]) + expect(setRegistryHeaders).toHaveBeenCalledWith({ + "https://api.com/button.json": { + "Content-Type": "application/json", + Authorization: "Bearer secret123", + "X-Custom": "static-value", + }, + }) + + delete process.env.API_TOKEN + }) + + it("should handle query parameters in URL config", () => { + const items = ["@params/button"] + const config = { + registries: { + "@params": { + url: "https://api.com/{name}.json", + params: { + version: "1.0", + format: "json", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://api.com/button.json?version=1.0&format=json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) + + it("should handle query parameters with environment variables", () => { + process.env.API_VERSION = "2.0" + + const items = ["@params/button"] + const config = { + registries: { + "@params": { + url: "https://api.com/{name}.json", + params: { + version: "${API_VERSION}", + format: "json", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://api.com/button.json?version=2.0&format=json", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + + delete process.env.API_VERSION + }) + + it("should handle existing query parameters in URL", () => { + const items = ["@existing/button"] + const config = { + registries: { + "@existing": { + url: "https://api.com/{name}.json?existing=true", + params: { + version: "1.0", + }, + }, + }, + } as any + + const result = resolveRegistryItemsFromRegistries(items, config) + + expect(result).toEqual([ + "https://api.com/button.json?existing=true&version=1.0", + ]) + expect(setRegistryHeaders).toHaveBeenCalledWith({}) + }) +}) diff --git a/packages/shadcn/src/registry/resolver.ts b/packages/shadcn/src/registry/resolver.ts new file mode 100644 index 000000000..33d418314 --- /dev/null +++ b/packages/shadcn/src/registry/resolver.ts @@ -0,0 +1,34 @@ +import { configSchema } from "@/src/registry/schema" +import { z } from "zod" + +import { buildUrlAndHeadersForRegistryItem } from "./builder" +import { setRegistryHeaders } from "./context" + +export function resolveRegistryItemsFromRegistries( + items: string[], + config?: z.infer +) { + const registryHeaders: Record> = {} + const resolvedItems = [...items] + + if (!config?.registries) { + setRegistryHeaders({}) + return resolvedItems + } + + for (let i = 0; i < resolvedItems.length; i++) { + const resolved = buildUrlAndHeadersForRegistryItem(resolvedItems[i], config) + + if (resolved) { + resolvedItems[i] = resolved.url + + if (Object.keys(resolved.headers).length > 0) { + registryHeaders[resolved.url] = resolved.headers + } + } + } + + setRegistryHeaders(registryHeaders) + + return resolvedItems +} diff --git a/packages/shadcn/src/registry/schema.test.ts b/packages/shadcn/src/registry/schema.test.ts new file mode 100644 index 000000000..e7fa2c9b4 --- /dev/null +++ b/packages/shadcn/src/registry/schema.test.ts @@ -0,0 +1,49 @@ +import { describe, expect, it } from "vitest" + +import { registryConfigSchema } from "./schema" + +describe("registryConfigSchema", () => { + it("should accept valid registry names starting with @", () => { + const validConfig = { + "@v0": "https://v0.dev/{name}.json", + "@acme": { + url: "https://acme.com/{name}.json", + headers: { + Authorization: "Bearer token", + }, + }, + } + + const result = registryConfigSchema.safeParse(validConfig) + expect(result.success).toBe(true) + }) + + it("should reject registry names not starting with @", () => { + const invalidConfig = { + v0: "https://v0.dev/{name}.json", + acme: "https://acme.com/{name}.json", + } + + const result = registryConfigSchema.safeParse(invalidConfig) + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error.errors[0].message).toContain( + "Registry names must start with @" + ) + } + }) + + it("should reject URLs without {name} placeholder", () => { + const invalidConfig = { + "@v0": "https://v0.dev/component.json", + } + + const result = registryConfigSchema.safeParse(invalidConfig) + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error.errors[0].message).toContain( + "Registry URL must include {name} placeholder" + ) + } + }) +}) diff --git a/packages/shadcn/src/registry/schema.ts b/packages/shadcn/src/registry/schema.ts index 272663e45..10ece0f1f 100644 --- a/packages/shadcn/src/registry/schema.ts +++ b/packages/shadcn/src/registry/schema.ts @@ -133,3 +133,67 @@ export const registryResolvedItemsTreeSchema = registryItemSchema.pick({ envVars: true, docs: true, }) + +export const registryConfigItemSchema = z.union([ + // Simple string format: "https://example.com/{name}.json" + z.string().refine((s) => s.includes("{name}"), { + message: "Registry URL must include {name} placeholder", + }), + // Advanced object format with auth options + z.object({ + url: z.string().refine((s) => s.includes("{name}"), { + message: "Registry URL must include {name} placeholder", + }), + params: z.record(z.string(), z.string()).optional(), + headers: z.record(z.string(), z.string()).optional(), + }), +]) + +export const registryConfigSchema = z.record( + z.string().refine((key) => key.startsWith("@"), { + message: "Registry names must start with @ (e.g., @v0, @acme)", + }), + registryConfigItemSchema +) + +export const rawConfigSchema = z + .object({ + $schema: z.string().optional(), + style: z.string(), + rsc: z.coerce.boolean().default(false), + tsx: z.coerce.boolean().default(true), + tailwind: z.object({ + config: z.string().optional(), + css: z.string(), + baseColor: z.string(), + cssVariables: z.boolean().default(true), + prefix: z.string().default("").optional(), + }), + iconLibrary: z.string().optional(), + aliases: z.object({ + components: z.string(), + utils: z.string(), + ui: z.string().optional(), + lib: z.string().optional(), + hooks: z.string().optional(), + }), + registries: registryConfigSchema.optional(), + }) + .strict() + +export const configSchema = rawConfigSchema.extend({ + resolvedPaths: z.object({ + cwd: z.string(), + tailwindConfig: z.string(), + tailwindCss: z.string(), + utils: z.string(), + components: z.string(), + lib: z.string(), + hooks: z.string(), + ui: z.string(), + }), +}) + +// TODO: type the key. +// Okay for now since I don't want a breaking change. +export const workspaceConfigSchema = z.record(configSchema) diff --git a/packages/shadcn/src/registry/utils.ts b/packages/shadcn/src/registry/utils.ts index 886bcbd9c..c50bc4b4b 100644 --- a/packages/shadcn/src/registry/utils.ts +++ b/packages/shadcn/src/registry/utils.ts @@ -1,8 +1,7 @@ import * as fs from "fs/promises" import { tmpdir } from "os" import * as path from "path" -import { registryItemSchema } from "@/src/registry" -import { configSchema } from "@/src/utils/get-config" +import { configSchema, registryItemSchema } from "@/src/registry" import { ProjectInfo } from "@/src/utils/get-project-info" import { resolveImport } from "@/src/utils/resolve-import" import { Project, ScriptKind } from "ts-morph" @@ -273,7 +272,9 @@ export function isUniversalRegistryItem( return ( !!registryItem?.files?.length && registryItem.files.every( - (file) => !!file.target && file.type === "registry:file" + (file) => + !!file.target && + (file.type === "registry:file" || file.type === "registry:item") ) ) } diff --git a/packages/shadcn/src/registry/validator.test.ts b/packages/shadcn/src/registry/validator.test.ts new file mode 100644 index 000000000..c9021fc92 --- /dev/null +++ b/packages/shadcn/src/registry/validator.test.ts @@ -0,0 +1,111 @@ +/* eslint-disable turbo/no-undeclared-env-vars */ +import { afterEach, beforeEach, describe, expect, it } from "vitest" + +import { + extractEnvVarsFromRegistryConfig, + validateRegistryConfig, +} from "./validator" + +describe("extractEnvVarsFromRegistryConfig", () => { + it("should extract vars from string config", () => { + expect( + extractEnvVarsFromRegistryConfig("https://api.com?token=${TOKEN}") + ).toEqual(["TOKEN"]) + }) + + it("should extract vars from object config", () => { + const config = { + url: "https://api.com/{name}?key=${API_KEY}", + params: { + version: "1.0", + token: "${TOKEN}", + }, + headers: { + Authorization: "Bearer ${AUTH_TOKEN}", + "X-Api-Key": "${API_KEY}", + }, + } + + expect(extractEnvVarsFromRegistryConfig(config).sort()).toEqual([ + "API_KEY", + "AUTH_TOKEN", + "TOKEN", + ]) + }) + + it("should handle config without params or headers", () => { + const config = { + url: "https://api.com/{name}", + } + + expect(extractEnvVarsFromRegistryConfig(config)).toEqual([]) + }) +}) + +describe("validateRegistryConfig", () => { + beforeEach(() => { + process.env.TOKEN = "value" + }) + + afterEach(() => { + delete process.env.TOKEN + }) + + describe("built-in registries", () => { + it("should not throw for @shadcn since it's now a built-in registry", () => { + expect(() => { + validateRegistryConfig("@shadcn", { + url: "https://example.com/{name}", + }) + }).not.toThrow() + }) + + it("should not throw for non-built-in registry names", () => { + expect(() => { + validateRegistryConfig("@mycompany", { + url: "https://example.com/{name}", + }) + }).not.toThrow() + }) + + it("should not throw for similar but different registry names", () => { + expect(() => { + validateRegistryConfig("@shadcn-ui", { + url: "https://example.com/{name}", + }) + }).not.toThrow() + + expect(() => { + validateRegistryConfig("@myshadcn", { + url: "https://example.com/{name}", + }) + }).not.toThrow() + }) + }) + + it("should pass when all env vars are set", () => { + expect(() => { + validateRegistryConfig("@test", "https://api.com?token=${TOKEN}") + }).not.toThrow() + }) + + it("should throw when env vars are missing", () => { + expect(() => { + validateRegistryConfig("@test", "https://api.com?token=${MISSING}") + }).toThrow(/Registry "@test" requires environment variables/) + }) + + it("should list all missing variables", () => { + const config = { + url: "https://api.com/{name}", + headers: { + Auth: "${TOKEN1}", + Key: "${TOKEN2}", + }, + } + + expect(() => { + validateRegistryConfig("@test", config) + }).toThrow(/TOKEN1[\s\S]*TOKEN2/) + }) +}) diff --git a/packages/shadcn/src/registry/validator.ts b/packages/shadcn/src/registry/validator.ts new file mode 100644 index 000000000..a09e14c56 --- /dev/null +++ b/packages/shadcn/src/registry/validator.ts @@ -0,0 +1,56 @@ +import { z } from "zod" + +import { extractEnvVars } from "./env" +import { registryConfigItemSchema } from "./schema" + +export function extractEnvVarsFromRegistryConfig( + config: z.infer +): string[] { + const vars = new Set() + + if (typeof config === "string") { + extractEnvVars(config).forEach((v) => vars.add(v)) + } else { + extractEnvVars(config.url).forEach((v) => vars.add(v)) + + if (config.params) { + Object.values(config.params).forEach((value) => { + extractEnvVars(value).forEach((v) => vars.add(v)) + }) + } + + if (config.headers) { + Object.values(config.headers).forEach((value) => { + extractEnvVars(value).forEach((v) => vars.add(v)) + }) + } + } + + return Array.from(vars) +} + +export function validateRegistryConfig( + registryName: string, + config: z.infer +): void { + const requiredVars = extractEnvVarsFromRegistryConfig(config) + const missing = requiredVars.filter((v) => !process.env[v]) + + if (missing.length > 0) { + const suggestions = missing.map((v) => { + // Common patterns for environment variable names + if (v.includes("TOKEN")) return `export ${v}="your-token-here"` + if (v.includes("KEY")) return `export ${v}="your-api-key-here"` + if (v.includes("SECRET")) return `export ${v}="your-secret-here"` + return `export ${v}="your-value-here"` + }) + + throw new Error( + `Registry "${registryName}" requires environment variables:\n\n` + + missing.map((v) => ` • ${v}`).join("\n") + + "\n\nSet them in your environment:\n\n" + + suggestions.map((s) => ` ${s}`).join("\n") + + "\n\nOr add them to a .env file in your project root." + ) + } +} diff --git a/packages/shadcn/src/utils/add-components.ts b/packages/shadcn/src/utils/add-components.ts index dca9280ff..d18914e6b 100644 --- a/packages/shadcn/src/utils/add-components.ts +++ b/packages/shadcn/src/utils/add-components.ts @@ -8,15 +8,15 @@ import { resolveRegistryItems, } from "@/src/registry/api" import { + configSchema, registryItemFileSchema, registryItemSchema, + workspaceConfigSchema, } from "@/src/registry/schema" import { - configSchema, findCommonRoot, findPackageRoot, getWorkspaceConfig, - workspaceConfigSchema, type Config, } from "@/src/utils/get-config" import { getProjectTailwindVersionFromConfig } from "@/src/utils/get-project-info" @@ -40,6 +40,7 @@ export async function addComponents( silent?: boolean isNewProject?: boolean style?: string + registryHeaders?: Record> } ) { options = { @@ -341,7 +342,7 @@ async function shouldOverwriteCssVars( config: z.infer ) { let result = await Promise.all( - components.map((component) => getRegistryItem(component, config.style)) + components.map((component) => getRegistryItem(component, config)) ) const payload = z.array(registryItemSchema).parse(result) diff --git a/packages/shadcn/src/utils/env-loader.ts b/packages/shadcn/src/utils/env-loader.ts new file mode 100644 index 000000000..daa61d544 --- /dev/null +++ b/packages/shadcn/src/utils/env-loader.ts @@ -0,0 +1,28 @@ +import { existsSync } from "fs" +import { join } from "path" +import { logger } from "@/src/utils/logger" + +export async function loadEnvFiles(cwd: string = process.cwd()): Promise { + try { + const { config } = await import("@dotenvx/dotenvx") + const envFiles = [ + ".env.local", + ".env.development.local", + ".env.development", + ".env", + ] + + for (const envFile of envFiles) { + const envPath = join(cwd, envFile) + if (existsSync(envPath)) { + config({ + path: envPath, + overload: false, + quiet: true, + }) + } + } + } catch (error) { + logger.warn("Failed to load env files:", error) + } +} diff --git a/packages/shadcn/src/utils/get-config.ts b/packages/shadcn/src/utils/get-config.ts index 4e368bcc7..579043329 100644 --- a/packages/shadcn/src/utils/get-config.ts +++ b/packages/shadcn/src/utils/get-config.ts @@ -1,4 +1,10 @@ import path from "path" +import { + configSchema, + rawConfigSchema, + workspaceConfigSchema, +} from "@/src/registry" +import { BUILTIN_REGISTRIES } from "@/src/registry/constants" import { getProjectInfo } from "@/src/utils/get-project-info" import { highlighter } from "@/src/utils/highlighter" import { resolveImport } from "@/src/utils/resolve-import" @@ -20,51 +26,8 @@ const explorer = cosmiconfig("components", { searchPlaces: ["components.json"], }) -export const rawConfigSchema = z - .object({ - $schema: z.string().optional(), - style: z.string(), - rsc: z.coerce.boolean().default(false), - tsx: z.coerce.boolean().default(true), - tailwind: z.object({ - config: z.string().optional(), - css: z.string(), - baseColor: z.string(), - cssVariables: z.boolean().default(true), - prefix: z.string().default("").optional(), - }), - aliases: z.object({ - components: z.string(), - utils: z.string(), - ui: z.string().optional(), - lib: z.string().optional(), - hooks: z.string().optional(), - }), - iconLibrary: z.string().optional(), - }) - .strict() - -export type RawConfig = z.infer - -export const configSchema = rawConfigSchema.extend({ - resolvedPaths: z.object({ - cwd: z.string(), - tailwindConfig: z.string(), - tailwindCss: z.string(), - utils: z.string(), - components: z.string(), - lib: z.string(), - hooks: z.string(), - ui: z.string(), - }), -}) - export type Config = z.infer -// TODO: type the key. -// Okay for now since I don't want a breaking change. -export const workspaceConfigSchema = z.record(configSchema) - export async function getConfig(cwd: string) { const config = await getRawConfig(cwd) @@ -80,7 +43,16 @@ export async function getConfig(cwd: string) { return await resolveConfigPaths(cwd, config) } -export async function resolveConfigPaths(cwd: string, config: RawConfig) { +export async function resolveConfigPaths( + cwd: string, + config: z.infer +) { + // Merge built-in registries with user registries + config.registries = { + ...BUILTIN_REGISTRIES, + ...(config.registries || {}), + } + // Read tsconfig.json. const tsConfig = await loadConfig(cwd) @@ -129,7 +101,9 @@ export async function resolveConfigPaths(cwd: string, config: RawConfig) { }) } -export async function getRawConfig(cwd: string): Promise { +export async function getRawConfig( + cwd: string +): Promise | null> { try { const configResult = await explorer.search(cwd) @@ -137,9 +111,25 @@ export async function getRawConfig(cwd: string): Promise { return null } - return rawConfigSchema.parse(configResult.config) + const config = rawConfigSchema.parse(configResult.config) + + // Check if user is trying to override built-in registries + if (config.registries) { + for (const registryName of Object.keys(config.registries)) { + if (registryName in BUILTIN_REGISTRIES) { + throw new Error( + `"${registryName}" is a built-in registry and cannot be overridden.` + ) + } + } + } + + return config } catch (error) { const componentPath = `${cwd}/components.json` + if (error instanceof Error && error.message.includes("reserved registry")) { + throw error + } throw new Error( `Invalid configuration found in ${highlighter.info(componentPath)}.` ) @@ -262,6 +252,9 @@ export function createConfig(partial?: DeepPartial): Config { components: "", utils: "", }, + registries: { + ...BUILTIN_REGISTRIES, + }, } // Deep merge the partial config with defaults diff --git a/packages/shadcn/src/utils/get-project-info.ts b/packages/shadcn/src/utils/get-project-info.ts index 29495d8db..2c15fb43c 100644 --- a/packages/shadcn/src/utils/get-project-info.ts +++ b/packages/shadcn/src/utils/get-project-info.ts @@ -1,11 +1,7 @@ import path from "path" +import { rawConfigSchema } from "@/src/registry" import { FRAMEWORKS, Framework } from "@/src/utils/frameworks" -import { - Config, - RawConfig, - getConfig, - resolveConfigPaths, -} from "@/src/utils/get-config" +import { Config, getConfig, resolveConfigPaths } from "@/src/utils/get-config" import { getPackageInfo } from "@/src/utils/get-package-info" import fg from "fast-glob" import fs from "fs-extra" @@ -332,7 +328,7 @@ export async function getProjectConfig( return null } - const config: RawConfig = { + const config: z.infer = { $schema: "https://ui.shadcn.com/schema.json", rsc: projectInfo.isRSC, tsx: projectInfo.isTsx, diff --git a/packages/shadcn/src/utils/handle-error.ts b/packages/shadcn/src/utils/handle-error.ts index 30244ec07..281a4c2eb 100644 --- a/packages/shadcn/src/utils/handle-error.ts +++ b/packages/shadcn/src/utils/handle-error.ts @@ -3,6 +3,7 @@ import { logger } from "@/src/utils/logger" import { z } from "zod" export function handleError(error: unknown) { + logger.break() logger.error( `Something went wrong. Please check the error below for more details.` ) diff --git a/packages/shadcn/src/utils/update-app-index.ts b/packages/shadcn/src/utils/update-app-index.ts index d6d1872c0..cd1cb74bf 100644 --- a/packages/shadcn/src/utils/update-app-index.ts +++ b/packages/shadcn/src/utils/update-app-index.ts @@ -10,7 +10,7 @@ export async function updateAppIndex(component: string, config: Config) { return } - const registryItem = await getRegistryItem(component, config.style) + const registryItem = await getRegistryItem(component, config) if ( !registryItem?.meta?.importSpecifier || !registryItem?.meta?.moduleSpecifier diff --git a/packages/shadcn/test/utils/get-config.test.ts b/packages/shadcn/test/utils/get-config.test.ts index f8f6affba..65d3eaa4e 100644 --- a/packages/shadcn/test/utils/get-config.test.ts +++ b/packages/shadcn/test/utils/get-config.test.ts @@ -91,6 +91,9 @@ test("get config", async () => { lib: path.resolve(__dirname, "../fixtures/config-partial", "./lib"), }, iconLibrary: "lucide", + registries: { + "@shadcn": "https://ui.shadcn.com/r/styles/{style}/{name}.json", + }, }) expect( @@ -144,6 +147,9 @@ test("get config", async () => { "./src/lib/utils" ), }, + registries: { + "@shadcn": "https://ui.shadcn.com/r/styles/{style}/{name}.json", + }, }) expect( @@ -185,6 +191,9 @@ test("get config", async () => { hooks: path.resolve(__dirname, "../fixtures/config-jsx", "./hooks"), lib: path.resolve(__dirname, "../fixtures/config-jsx", "./lib"), }, + registries: { + "@shadcn": "https://ui.shadcn.com/r/styles/{style}/{name}.json", + }, }) }) diff --git a/packages/shadcn/test/utils/registry.test.ts b/packages/shadcn/test/utils/registry.test.ts index 11d7b4f7a..422151636 100644 --- a/packages/shadcn/test/utils/registry.test.ts +++ b/packages/shadcn/test/utils/registry.test.ts @@ -1,7 +1,8 @@ import { expect, test } from "vitest" +import { z } from "zod" import { resolveTree } from "../../src/registry/api" -import { Registry } from "../../src/registry/schema" +import { registryItemSchema } from "../../src/registry/schema" test("resolve tree", async () => { const index = [ @@ -37,7 +38,7 @@ test("resolve tree", async () => { files: [{ type: "registry:component", path: "example-card.tsx" }], registryDependencies: ["button", "dialog", "input"], }, - ] satisfies Registry + ] satisfies z.infer[] expect( (await resolveTree(index, ["button"])).map((entry) => entry.name).sort() diff --git a/packages/tests/fixtures/next-app-init/app/favicon.ico b/packages/tests/fixtures/next-app-init/app/favicon.ico new file mode 100644 index 000000000..718d6fea4 Binary files /dev/null and b/packages/tests/fixtures/next-app-init/app/favicon.ico differ diff --git a/packages/tests/fixtures/next-app-init/app/globals.css b/packages/tests/fixtures/next-app-init/app/globals.css new file mode 100644 index 000000000..f4c1e9b51 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/app/globals.css @@ -0,0 +1,120 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/packages/tests/fixtures/next-app-init/app/layout.tsx b/packages/tests/fixtures/next-app-init/app/layout.tsx new file mode 100644 index 000000000..ef077d2d9 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/app/layout.tsx @@ -0,0 +1,22 @@ +import "./globals.css" +import type { Metadata } from "next" +import { Inter } from "next/font/google" + +const inter = Inter({ subsets: ["latin"] }) + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/packages/tests/fixtures/next-app-init/app/other.css b/packages/tests/fixtures/next-app-init/app/other.css new file mode 100644 index 000000000..aa1634c25 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/app/other.css @@ -0,0 +1,3 @@ +body { + background-color: red; +} diff --git a/packages/tests/fixtures/next-app-init/app/page.tsx b/packages/tests/fixtures/next-app-init/app/page.tsx new file mode 100644 index 000000000..08930a9d3 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/app/page.tsx @@ -0,0 +1,113 @@ +import Image from "next/image" + +export default function Home() { + return ( +
+
+

+ Get started by editing  + app/page.tsx +

+ +
+ +
+ Next.js Logo +
+ + +
+ ) +} diff --git a/packages/tests/fixtures/next-app-init/components.json b/packages/tests/fixtures/next-app-init/components.json new file mode 100644 index 000000000..335484f94 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/packages/tests/fixtures/next-app-init/lib/utils.ts b/packages/tests/fixtures/next-app-init/lib/utils.ts new file mode 100644 index 000000000..bd0c391dd --- /dev/null +++ b/packages/tests/fixtures/next-app-init/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/packages/tests/fixtures/next-app-init/next.config.ts b/packages/tests/fixtures/next-app-init/next.config.ts new file mode 100644 index 000000000..767719fc4 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/next.config.ts @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} + +module.exports = nextConfig diff --git a/packages/tests/fixtures/next-app-init/package-lock.json b/packages/tests/fixtures/next-app-init/package-lock.json new file mode 100644 index 000000000..532dcfde5 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/package-lock.json @@ -0,0 +1,6204 @@ +{ + "name": "my-app", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "my-app", + "version": "0.1.0", + "dependencies": { + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.527.0", + "next": "15.4.4", + "react": "19.1.0", + "react-dom": "19.1.0", + "tailwind-merge": "^3.3.1" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "15.4.4", + "tailwindcss": "^4", + "tw-animate-css": "^1.3.6", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", + "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", + "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", + "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", + "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", + "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", + "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", + "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", + "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", + "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", + "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", + "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", + "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", + "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", + "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", + "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", + "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", + "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", + "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.4" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", + "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", + "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", + "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@next/env": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.4.tgz", + "integrity": "sha512-SJKOOkULKENyHSYXE5+KiFU6itcIb6wSBjgM92meK0HVKpo94dNOLZVdLLuS7/BxImROkGoPsjR4EnuDucqiiA==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.4.4.tgz", + "integrity": "sha512-1FDsyN//ai3Jd97SEd7scw5h1yLdzDACGOPRofr2GD3sEFsBylEEoL0MHSerd4n2dq9Zm/mFMqi4+NRMOreOKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.4.tgz", + "integrity": "sha512-eVG55dnGwfUuG+TtnUCt+mEJ+8TGgul6nHEvdb8HEH7dmJIFYOCApAaFrIrxwtEq2Cdf+0m5sG1Np8cNpw9EAw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.4.tgz", + "integrity": "sha512-zqG+/8apsu49CltEj4NAmCGZvHcZbOOOsNoTVeIXphYWIbE4l6A/vuQHyqll0flU2o3dmYCXsBW5FmbrGDgljQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.4.tgz", + "integrity": "sha512-LRD4l2lq4R+2QCHBQVC0wjxxkLlALGJCwigaJ5FSRSqnje+MRKHljQNZgDCaKUZQzO/TXxlmUdkZP/X3KNGZaw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.4.tgz", + "integrity": "sha512-LsGUCTvuZ0690fFWerA4lnQvjkYg9gHo12A3wiPUR4kCxbx/d+SlwmonuTH2SWZI+RVGA9VL3N0S03WTYv6bYg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.4.tgz", + "integrity": "sha512-aOy5yNRpLL3wNiJVkFYl6w22hdREERNjvegE6vvtix8LHRdsTHhWTpgvcYdCK7AIDCQW5ATmzr9XkPHvSoAnvg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.4.tgz", + "integrity": "sha512-FL7OAn4UkR8hKQRGBmlHiHinzOb07tsfARdGh7v0Z0jEJ3sz8/7L5bR23ble9E6DZMabSStqlATHlSxv1fuzAg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.4.tgz", + "integrity": "sha512-eEdNW/TXwjYhOulQh0pffTMMItWVwKCQpbziSBmgBNFZIIRn2GTXrhrewevs8wP8KXWYMx8Z+mNU0X+AfvtrRg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.4.tgz", + "integrity": "sha512-SE5pYNbn/xZKMy1RE3pAs+4xD32OI4rY6mzJa4XUkp/ItZY+OMjIgilskmErt8ls/fVJ+Ihopi2QIeW6O3TrMw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.12.0.tgz", + "integrity": "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz", + "integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz", + "integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-x64": "4.1.11", + "@tailwindcss/oxide-freebsd-x64": "4.1.11", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-x64-musl": "4.1.11", + "@tailwindcss/oxide-wasm32-wasi": "4.1.11", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz", + "integrity": "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz", + "integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz", + "integrity": "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz", + "integrity": "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz", + "integrity": "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz", + "integrity": "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz", + "integrity": "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz", + "integrity": "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz", + "integrity": "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz", + "integrity": "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.11", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz", + "integrity": "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz", + "integrity": "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.11.tgz", + "integrity": "sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.11", + "@tailwindcss/oxide": "4.1.11", + "postcss": "^8.4.41", + "tailwindcss": "4.1.11" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz", + "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", + "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", + "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.38.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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/axe-core": { + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", + "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", + "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.4.4.tgz", + "integrity": "sha512-sK/lWLUVF5om18O5w76Jt3F8uzu/LP5mVa6TprCMWkjWHUmByq80iHGHcdH7k1dLiJlj+DRIWf98d5piwRsSuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "15.4.4", + "@rushstack/eslint-patch": "^1.10.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^5.0.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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/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/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "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/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "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/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "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-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "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-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "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", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lucide-react": { + "version": "0.527.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.527.0.tgz", + "integrity": "sha512-tyqW8gfeeDfpBjZpQ2vv1S6n9OzvkrDcs6pyLJLvB3eyHoz8BNkkR7WbYePlq6ZbNmFA911YJlbTtWkEdvXGgA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.2.tgz", + "integrity": "sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/next/-/next-15.4.4.tgz", + "integrity": "sha512-kNcubvJjOL9yUOfwtZF3HfDhuhp+kVD+FM2A6Tyua1eI/xfmY4r/8ZS913MMz+oWKDlbps/dQOWdDricuIkXLw==", + "license": "MIT", + "dependencies": { + "@next/env": "15.4.4", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.4.4", + "@next/swc-darwin-x64": "15.4.4", + "@next/swc-linux-arm64-gnu": "15.4.4", + "@next/swc-linux-arm64-musl": "15.4.4", + "@next/swc-linux-x64-gnu": "15.4.4", + "@next/swc-linux-x64-musl": "15.4.4", + "@next/swc-win32-arm64-msvc": "15.4.4", + "@next/swc-win32-x64-msvc": "15.4.4", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "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", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", + "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.4", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.3", + "@img/sharp-darwin-x64": "0.34.3", + "@img/sharp-libvips-darwin-arm64": "1.2.0", + "@img/sharp-libvips-darwin-x64": "1.2.0", + "@img/sharp-libvips-linux-arm": "1.2.0", + "@img/sharp-libvips-linux-arm64": "1.2.0", + "@img/sharp-libvips-linux-ppc64": "1.2.0", + "@img/sharp-libvips-linux-s390x": "1.2.0", + "@img/sharp-libvips-linux-x64": "1.2.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0", + "@img/sharp-linux-arm": "0.34.3", + "@img/sharp-linux-arm64": "0.34.3", + "@img/sharp-linux-ppc64": "0.34.3", + "@img/sharp-linux-s390x": "0.34.3", + "@img/sharp-linux-x64": "0.34.3", + "@img/sharp-linuxmusl-arm64": "0.34.3", + "@img/sharp-linuxmusl-x64": "0.34.3", + "@img/sharp-wasm32": "0.34.3", + "@img/sharp-win32-arm64": "0.34.3", + "@img/sharp-win32-ia32": "0.34.3", + "@img/sharp-win32-x64": "0.34.3" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", + "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tw-animate-css": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.6.tgz", + "integrity": "sha512-9dy0R9UsYEGmgf26L8UcHiLmSFTHa9+D7+dAt/G/sF5dCnPePZbfgDYinc7/UzAM7g/baVrmS6m9yEpU46d+LA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "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/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/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/packages/tests/fixtures/next-app-init/package.json b/packages/tests/fixtures/next-app-init/package.json new file mode 100644 index 000000000..6da9f4c8c --- /dev/null +++ b/packages/tests/fixtures/next-app-init/package.json @@ -0,0 +1,32 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.527.0", + "next": "15.4.4", + "react": "19.1.0", + "react-dom": "19.1.0", + "tailwind-merge": "^3.3.1" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "15.4.4", + "tailwindcss": "^4", + "tw-animate-css": "^1.3.6", + "typescript": "^5" + } +} diff --git a/packages/tests/fixtures/next-app-init/postcss.config.mjs b/packages/tests/fixtures/next-app-init/postcss.config.mjs new file mode 100644 index 000000000..c7bcb4b1e --- /dev/null +++ b/packages/tests/fixtures/next-app-init/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/packages/tests/fixtures/next-app-init/tsconfig.json b/packages/tests/fixtures/next-app-init/tsconfig.json new file mode 100644 index 000000000..c71469637 --- /dev/null +++ b/packages/tests/fixtures/next-app-init/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/tests/fixtures/no-framework/.gitkeep b/packages/tests/fixtures/no-framework/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/tests/src/tests/add.test.ts b/packages/tests/src/tests/add.test.ts index 7f28746b8..7c835eb57 100644 --- a/packages/tests/src/tests/add.test.ts +++ b/packages/tests/src/tests/add.test.ts @@ -278,4 +278,19 @@ describe("shadcn add", () => { " `) }) + + it("should add registry:item with no framework", async () => { + const fixturePath = await createFixtureTestDirectory("no-framework") + await npxShadcn(fixturePath, [ + "add", + "../../fixtures/registry/example-item.json", + ]) + + expect(await fs.pathExists(path.join(fixturePath, "path/to/foo.txt"))).toBe( + true + ) + expect( + await fs.readFile(path.join(fixturePath, "path/to/foo.txt"), "utf-8") + ).toBe("Foo Bar") + }) }) diff --git a/packages/tests/src/tests/init.test.ts b/packages/tests/src/tests/init.test.ts index 77585f0b7..ea45d10e9 100644 --- a/packages/tests/src/tests/init.test.ts +++ b/packages/tests/src/tests/init.test.ts @@ -6,6 +6,9 @@ import { createFixtureTestDirectory, npxShadcn } from "../utils/helpers" describe("shadcn init - next-app", () => { it("should init with default configuration", async () => { + // Sleep for 1 second to avoid race condition with the registry server. + await new Promise((resolve) => setTimeout(resolve, 2000)) + const fixturePath = await createFixtureTestDirectory("next-app") await npxShadcn(fixturePath, ["init", "--base-color=neutral"]) diff --git a/packages/tests/src/tests/registries.test.ts b/packages/tests/src/tests/registries.test.ts new file mode 100644 index 000000000..126ad8222 --- /dev/null +++ b/packages/tests/src/tests/registries.test.ts @@ -0,0 +1,1148 @@ +/* eslint-disable turbo/no-undeclared-env-vars */ +import path from "path" +import fs from "fs-extra" +import { afterAll, beforeAll, describe, expect, it } from "vitest" + +import { + createFixtureTestDirectory, + cssHasProperties, + npxShadcn, +} from "../utils/helpers" +import { configureRegistries, createRegistryServer } from "../utils/registry" + +const registryShadcn = await createRegistryServer( + [ + { + name: "utils", + type: "registry:component", + files: [ + { + path: "registry/new-york-v4/lib/utils.ts", + content: + 'import { clsx, type ClassValue } from "clsx"\nimport { twMerge } from "tailwind-merge"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n', + type: "registry:lib", + }, + ], + }, + { + name: "alert-dialog", + type: "registry:ui", + files: [ + { + path: "components/ui/alert-dialog.tsx", + content: + "export function AlertDialog() {\n return
AlertDialog Component from Registry Shadcn
\n}", + type: "registry:ui", + }, + { + path: "components/ui/button.tsx", + content: + "export function Button() {\n return
Button Component from Registry Shadcn
\n}", + type: "registry:ui", + }, + ], + }, + { + name: "button", + type: "registry:ui", + files: [ + { + path: "components/ui/button.tsx", + content: + "export function Button() {\n return
Button Component from Registry Shadcn
\n}", + type: "registry:ui", + }, + ], + }, + { + name: "example-button", + type: "registry:component", + registryDependencies: ["@shadcn/button"], + files: [ + { + path: "components/example-button.tsx", + content: + "export function ExampleButton() {\n return
Example Button Component from Registry Shadcn
\n}", + type: "registry:component", + }, + ], + }, + { + name: "no-framework-item", + type: "registry:item", + files: [ + { + path: "path/to/foo.txt", + content: "Foo Bar", + type: "registry:item", + target: "path/to/foo.txt", + }, + ], + }, + ], + { + port: 4040, + path: "/r", + } +) + +const registryOne = await createRegistryServer( + [ + { + name: "foo", + type: "registry:component", + files: [ + { + path: "components/foo.tsx", + content: + "export function Foo() {\n return
Foo Component from Registry 1
\n}", + type: "registry:component", + }, + ], + }, + { + name: "bar", + type: "registry:component", + files: [ + { + path: "components/bar.tsx", + content: + "export function Bar() {\n return
Bar Component from Registry 1
\n}", + type: "registry:component", + }, + ], + }, + { + name: "baz", + type: "registry:component", + registryDependencies: ["@one/bar"], + files: [ + { + path: "components/baz.tsx", + content: + "export function Baz() {\n return
Baz Component from Registry 2
\n}", + type: "registry:component", + }, + ], + }, + { + name: "qux", + type: "registry:component", + registryDependencies: ["@one/baz"], + files: [ + { + path: "components/qux.tsx", + content: + "export function Qux() {\n return
Qux Component from Registry 2
\n}", + type: "registry:component", + }, + ], + }, + { + name: "quux", + type: "registry:page", + registryDependencies: ["@two/two"], + files: [ + { + path: "path/to/app/quux/page.tsx", + content: + "export function Quux() {\n return
Quux Component from Registry 2
\n}", + type: "registry:page", + target: "app/quux/page.tsx", + }, + ], + }, + { + name: "foo-theme", + type: "registry:theme", + cssVars: { + light: { + background: "white", + foreground: "black", + }, + dark: { + background: "black", + foreground: "white", + }, + }, + }, + ], + { + port: 4444, + path: "/r", + } +) + +const registryTwo = await createRegistryServer( + [ + { + name: "one", + type: "registry:file", + files: [ + { + path: "path/to/one.txt", + content: "one", + type: "registry:file", + target: "example/one.txt", + }, + ], + }, + { + name: "two", + type: "registry:ui", + registryDependencies: ["button", "@one/qux"], + files: [ + { + path: "components/ui/two.tsx", + content: + "export function Two() {\n return
Two Component from Registry 2
\n}", + type: "registry:ui", + }, + { + path: "components/example.tsx", + content: + "export function Example() {\n return
Example Component from Registry 2
\n}", + type: "registry:component", + }, + ], + }, + { + name: "theme", + type: "registry:theme", + cssVars: { + light: { + background: "red", + foreground: "blue", + primary: "green", + }, + dark: { + foreground: "red", + }, + }, + }, + ], + { + port: 5555, + path: "/registry", + } +) + +beforeAll(async () => { + // This sets the shadcn registry to our mock registry. + process.env.REGISTRY_URL = "http://localhost:4040/r" + await registryShadcn.start() + await registryOne.start() + await registryTwo.start() +}) + +afterAll(async () => { + await registryShadcn.stop() + await registryOne.stop() + await registryTwo.stop() +}) + +describe("registries", () => { + it("should add from registry using url", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await npxShadcn(fixturePath, ["add", "http://localhost:4444/r/foo"]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + }) + + it("should add multiple items from registry using urls", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await npxShadcn(fixturePath, [ + "add", + "http://localhost:4444/r/foo", + "http://localhost:4444/r/bar", + ]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + }) + + it("should add multiple items from multiple registries using urls", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await npxShadcn(fixturePath, [ + "add", + "http://localhost:4444/r/foo", + "http://localhost:5555/registry/one", + ]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + expect(await fs.pathExists(path.join(fixturePath, "example/one.txt"))).toBe( + true + ) + }) + + it("should add item using name and from registry url", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await npxShadcn(fixturePath, [ + "add", + "alert-dialog", + "http://localhost:4444/r/foo", + ]) + + expect( + await fs.pathExists( + path.join(fixturePath, "components/ui/alert-dialog.tsx") + ) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + }) + + it("should add item from name, local path and registry url", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await npxShadcn(fixturePath, [ + "add", + "alert-dialog", + "../../fixtures/registry/example-item.json", + "http://localhost:4444/r/foo", + ]) + + expect(await fs.pathExists(path.join(fixturePath, "path/to/foo.txt"))).toBe( + true + ) + expect( + await fs.pathExists( + path.join(fixturePath, "components/ui/alert-dialog.tsx") + ) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + }) + + it("should show only built-in registries when not configured", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + const output = await npxShadcn(fixturePath, ["info"]) + // Should show registries since @shadcn is built-in + expect(output.stdout).toContain("registries:") + expect(output.stdout).toContain("@shadcn") + // Should not show user-defined registries + expect(output.stdout).not.toContain("@one") + expect(output.stdout).not.toContain("@two") + }) + + it("should show an error when adding from a non-existent registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + const output = await npxShadcn(fixturePath, [ + "add", + "@non-existent/component", + ]) + expect(output.stdout).toContain('Unknown registry "@non-existent"') + expect(output.stdout).toContain( + '"registries": {\n' + + ' "@non-existent": "https://example.com/{name}.json"\n' + + " }\n" + ) + }) + + it("should show registries when configured", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + const output = await npxShadcn(fixturePath, ["info"]) + // Should contain both built-in and user registries + expect(output.stdout).toContain("registries:") + expect(output.stdout).toContain("@shadcn") + expect(output.stdout).toContain("@one") + expect(output.stdout).toContain("http://localhost:4444/r/{name}") + }) + + it("should show multiple registries when configured", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + "@two": { + url: "http://localhost:5555/registry/{name}", + headers: { + Authorization: "Bearer ${BEARER_TOKEN}", + }, + }, + }) + + const output = await npxShadcn(fixturePath, ["info"]) + // Should contain built-in and both user registries + expect(output.stdout).toContain("registries:") + expect(output.stdout).toContain("@shadcn") + expect(output.stdout).toContain("@one") + expect(output.stdout).toContain("@two") + expect(output.stdout).toContain("http://localhost:4444/r/{name}") + expect(output.stdout).toContain("http://localhost:5555/registry/{name}") + }) + + it("should show an error when adding from a non-existent registry with configured registries", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + const output = await npxShadcn(fixturePath, ["add", "@acme/component"]) + expect(output.stdout).toContain('Unknown registry "@acme"') + expect(output.stdout).toContain( + '"registries": {\n' + + ' "@acme": "https://example.com/{name}.json"\n' + + " }\n" + ) + }) + + it("should add item using namespaced registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + const output = await npxShadcn(fixturePath, ["add", "@one/foo"]) + + if (!(await fs.pathExists(path.join(fixturePath, "components/foo.tsx")))) { + console.log("Test failed. Command output:", output.stdout) + console.log("Command stderr:", output.stderr) + } + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + }) + + it("should add multiple items using namespaced registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + await npxShadcn(fixturePath, ["add", "@one/foo", "@one/bar"]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + }) + + it("should add registry dependencies when adding from namespaced registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + await npxShadcn(fixturePath, ["add", "@one/baz"]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/baz.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + }) + + it("should add nested registry dependencies when adding from namespaced registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + await npxShadcn(fixturePath, ["add", "@one/qux"]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/qux.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/baz.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + }) + + it("should show an error when adding url with namespaced dependency", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + const output = await npxShadcn(fixturePath, [ + "add", + "http://localhost:4444/r/baz", + ]) + + expect(output.stdout).toContain('Unknown registry "@one"') + }) + + it("should show an error when adding url with unconfigured registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + const output = await npxShadcn(fixturePath, [ + "add", + "http://localhost:5555/registry/two", + ]) + + expect(output.stdout).toContain('Unknown registry "@one"') + }) + + it("should show an error when adding namespaced with unconfigured registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@two": "http://localhost:5555/registry/{name}", + }) + + const output = await npxShadcn(fixturePath, ["add", "@two/two"]) + expect(output.stdout).toContain("unknown registry @one") + }) + + it("should show an error when adding multiple namespaced items with unconfigured registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@two": "http://localhost:5555/registry/{name}", + }) + + const output = await npxShadcn(fixturePath, ["add", "@two/one", "@one/foo"]) + + expect(output.stdout).toContain('Unknown registry "@one"') + }) + + it("should show an error when authentication is not configured", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@two": "http://localhost:5555/registry/bearer/{name}", + }) + const output = await npxShadcn(fixturePath, ["add", "@two/one"]) + expect(output.stdout).toContain("Unauthorized") + }) + + it("should add item when authentication is configured", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@two": { + url: "http://localhost:5555/registry/bearer/{name}", + headers: { + Authorization: "Bearer EXAMPLE_BEARER_TOKEN", + }, + }, + }) + + await npxShadcn(fixturePath, ["add", "@two/one"]) + + expect(await fs.pathExists(path.join(fixturePath, "example/one.txt"))).toBe( + true + ) + }) + + it("should show an error for nested unauthorized dependencies", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + "@two": "http://localhost:5555/registry/bearer/{name}", + }) + const output = await npxShadcn(fixturePath, ["add", "@one/quux"]) + expect(output.stdout).toContain("Unauthorized") + }) + + it("should add item when authentication is configured and nested dependencies are authorized", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + "@two": { + url: "http://localhost:5555/registry/bearer/{name}", + headers: { + Authorization: "Bearer EXAMPLE_BEARER_TOKEN", + }, + }, + }) + await npxShadcn(fixturePath, ["add", "@one/quux"]) + + expect( + await fs.pathExists(path.join(fixturePath, "app/quux/page.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/two.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/example.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/qux.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/baz.tsx")) + ).toBe(true) + }) + + it("should error when adding item with api key authentication and no api key is provided", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@two": "http://localhost:5555/registry/api-key/{name}", + }) + const output = await npxShadcn(fixturePath, ["add", "@two/one"]) + expect(output.stdout).toContain("Unauthorized") + }) + + it("should add item with api key authentication", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@two": { + url: "http://localhost:5555/registry/api-key/{name}", + headers: { + "x-api-key": "EXAMPLE_API_KEY", + }, + }, + }) + await npxShadcn(fixturePath, ["add", "@two/one"]) + expect(await fs.pathExists(path.join(fixturePath, "example/one.txt"))).toBe( + true + ) + }) + + it("should error when adding item with client secret authentication and no client secret is provided", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@two": { + url: "http://localhost:5555/registry/client-secret/{name}", + }, + }) + const output = await npxShadcn(fixturePath, ["add", "@two/one"]) + expect(output.stdout).toContain("Unauthorized") + }) + + it("should add item with client secret authentication", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@two": { + url: "http://localhost:5555/registry/client-secret/{name}", + headers: { + "x-client-secret": "EXAMPLE_CLIENT_SECRET", + "x-client-id": "EXAMPLE_CLIENT_ID", + }, + }, + }) + await npxShadcn(fixturePath, ["add", "@two/one"]) + expect(await fs.pathExists(path.join(fixturePath, "example/one.txt"))).toBe( + true + ) + }) + + it("should expand env vars in registries config", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "${NEXT_PUBLIC_REGISTRY_URL}/r/{name}", + }) + + process.env.NEXT_PUBLIC_REGISTRY_URL = "http://localhost:4444/r" + await npxShadcn(fixturePath, ["add", "@one/foo"]) + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + }) + + it("should expand env vars in registries config with multiple registries", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await configureRegistries(fixturePath, { + "@one": "${NEXT_PUBLIC_REGISTRY_URL}/r/{name}", + "@two": { + url: "http://localhost:5555/registry/params/{name}?token=${REGISTRY_TOKEN}", + headers: { + "x-client-secret": "EXAMPLE_CLIENT_SECRET", + "x-client-id": "EXAMPLE_CLIENT_ID", + }, + }, + "@three": { + url: "http://localhost:4444/r/api-key/{name}", + headers: { + "x-api-key": "${REGISTRY_API_KEY}", + }, + }, + }) + + process.env.NEXT_PUBLIC_REGISTRY_URL = "http://localhost:4444/r" + process.env.REGISTRY_TOKEN = "EXAMPLE_REGISTRY_TOKEN" + process.env.REGISTRY_API_KEY = "EXAMPLE_API_KEY" + const output = await npxShadcn(fixturePath, [ + "add", + "@one/foo", + "@three/baz", + "@two/two", + ]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/baz.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/two.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/example.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/qux.tsx")) + ).toBe(true) + }) + + describe("fetchFromRegistry improvements", () => { + it("should handle registry resolution transparently", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + "@two": { + url: "http://localhost:5555/registry/{name}", + headers: { + Authorization: "Bearer EXAMPLE_BEARER_TOKEN", + }, + }, + }) + + // Test that components can be added without pre-resolution + await npxShadcn(fixturePath, ["add", "@one/foo", "@two/two"]) + + // Verify all files were created including dependencies + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/two.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/example.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/qux.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/baz.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/bar.tsx")) + ).toBe(true) + }) + + it("should maintain type safety with mixed registries", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + // Mix of namespaced and non-namespaced components + await npxShadcn(fixturePath, ["add", "@one/foo", "button"]) + + expect( + await fs.pathExists(path.join(fixturePath, "components/foo.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + }) + + it("should handle circular dependencies gracefully", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + // Create a mock server with circular dependencies + const circularServer = await createRegistryServer( + [ + { + name: "comp-a", + type: "registry:component", + registryDependencies: ["@circular/comp-b"], + files: [ + { + path: "components/comp-a.tsx", + content: + "export function CompA() { return
Component A
}", + type: "registry:component", + }, + ], + }, + { + name: "comp-b", + type: "registry:component", + registryDependencies: ["@circular/comp-a"], + files: [ + { + path: "components/comp-b.tsx", + content: + "export function CompB() { return
Component B
}", + type: "registry:component", + }, + ], + }, + ], + { + port: 9999, + path: "/circular", + } + ) + + await circularServer.start() + + await configureRegistries(fixturePath, { + "@circular": "http://localhost:9999/circular/{name}", + }) + + // Should handle circular dependency without infinite loop + await npxShadcn(fixturePath, ["add", "@circular/comp-a"]) + + // Both components should be added once + expect( + await fs.pathExists(path.join(fixturePath, "components/comp-a.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/comp-b.tsx")) + ).toBe(true) + + await circularServer.stop() + }) + + it("should preserve header context across dependency resolution", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + // Create a server that validates headers for all requests + const authServer = await createRegistryServer( + [ + { + name: "parent", + type: "registry:component", + registryDependencies: ["@auth/child1", "@auth/child2"], + files: [ + { + path: "components/parent.tsx", + content: + "export function Parent() { return
Parent
}", + type: "registry:component", + }, + ], + }, + { + name: "child1", + type: "registry:component", + files: [ + { + path: "components/child1.tsx", + content: + "export function Child1() { return
Child 1
}", + type: "registry:component", + }, + ], + }, + { + name: "child2", + type: "registry:component", + files: [ + { + path: "components/child2.tsx", + content: + "export function Child2() { return
Child 2
}", + type: "registry:component", + }, + ], + }, + ], + { + port: 10000, + path: "/auth-test", + } + ) + + await authServer.start() + + await configureRegistries(fixturePath, { + "@auth": { + url: "http://localhost:10000/auth-test/bearer/{name}", + headers: { + Authorization: "Bearer EXAMPLE_BEARER_TOKEN", + }, + }, + }) + + // Add parent which should trigger requests for dependencies + await npxShadcn(fixturePath, ["add", "@auth/parent"]) + + // All components should be added + expect( + await fs.pathExists(path.join(fixturePath, "components/parent.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/child1.tsx")) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/child2.tsx")) + ).toBe(true) + + await authServer.stop() + }) + }) + + describe("built-in registries", () => { + it("should error when trying to override @shadcn in config", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + // Read the existing components.json + const configPath = path.join(fixturePath, "components.json") + const config = await fs.readJson(configPath) + + // Add @shadcn as a registry + config.registries = { + "@shadcn": "https://my-custom-registry.com/{name}", + } + + // Write the updated config + await fs.writeJson(configPath, config, { spaces: 2 }) + + // Try to run a command that loads the config + const output = await npxShadcn(fixturePath, ["info"]) + + // Check either stdout or stderr for the error message + const combinedOutput = output.stdout + output.stderr + + // The error should be about built-in registry or invalid configuration + expect(combinedOutput.toLowerCase()).toMatch( + /built-in registry|invalid configuration/ + ) + }) + + it("should work with @shadcn namespace without configuration", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + // Don't configure any registries - @shadcn should be built-in + const output = await npxShadcn(fixturePath, ["add", "@shadcn/button"]) + + if ( + !(await fs.pathExists( + path.join(fixturePath, "components/ui/button.tsx") + )) + ) { + console.log("Test failed. Command output:", output.stdout) + console.log("Command stderr:", output.stderr) + } + + // Should add button component just like regular "button" command + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + }) + + it("should allow similar but different registry names", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@shadcn-ui": "http://localhost:4444/r/{name}", + "@myshadcn": "http://localhost:4444/r/{name}", + "@shadcntest": "http://localhost:4444/r/{name}", + }) + + // Try to run a command that loads the config + const output = await npxShadcn(fixturePath, ["info"]) + + // Should not error - check that registries are shown + expect(output.stdout).toContain("@shadcn-ui") + expect(output.stdout).toContain("@myshadcn") + expect(output.stdout).toContain("@shadcntest") + expect(output.stdout).not.toContain("built-in registry") + }) + }) + + it("should add registry:item with no framework", async () => { + const fixturePath = await createFixtureTestDirectory("no-framework") + await npxShadcn(fixturePath, ["add", "no-framework-item"]) + + expect(await fs.pathExists(path.join(fixturePath, "path/to/foo.txt"))).toBe( + true + ) + expect( + await fs.readFile(path.join(fixturePath, "path/to/foo.txt"), "utf-8") + ).toBe("Foo Bar") + }) + + it("should add registry:theme", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + }) + + const output = await npxShadcn(fixturePath, [ + "add", + "@one/foo-theme", + "--yes", + ]) + + expect(output.stderr).toContain("Updating CSS variables in app/globals.css") + + const globalCssContent = await fs.readFile( + path.join(fixturePath, "app/globals.css"), + "utf-8" + ) + + expect( + cssHasProperties(globalCssContent, [ + { + selector: ":root", + properties: { + "--background": "white", + "--foreground": "black", + }, + }, + { + selector: ".dark", + properties: { + "--background": "black", + "--foreground": "white", + }, + }, + ]) + ).toBe(true) + }) + + it("should merge registry:theme with existing theme", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + + await configureRegistries(fixturePath, { + "@one": "http://localhost:4444/r/{name}", + "@two": { + url: "http://localhost:5555/registry/{name}", + headers: { + Authorization: "Bearer ${BEARER_TOKEN}", + }, + }, + }) + + process.env.BEARER_TOKEN = "1234567890" + + await npxShadcn(fixturePath, [ + "add", + "@one/foo-theme", + "@two/theme", + "--yes", + ]) + expect( + cssHasProperties( + await fs.readFile(path.join(fixturePath, "app/globals.css"), "utf-8"), + [ + { + selector: ":root", + properties: { + "--background": "red", + "--foreground": "blue", + "--primary": "green", + }, + }, + { + selector: ".dark", + properties: { + "--background": "black", + "--foreground": "red", + }, + }, + ] + ) + ).toBe(true) + + await npxShadcn(fixturePath, [ + "add", + "@two/theme", + "@one/foo-theme", + "--yes", + ]) + expect( + cssHasProperties( + await fs.readFile(path.join(fixturePath, "app/globals.css"), "utf-8"), + [ + { + selector: ":root", + properties: { + "--background": "white", + "--foreground": "black", + "--primary": "green", + }, + }, + { + selector: ".dark", + properties: { + "--background": "black", + "--foreground": "white", + }, + }, + ] + ) + ).toBe(true) + }) + + it("should add named item from shadcn registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await npxShadcn(fixturePath, ["add", "button"]) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + }) + + it("should add namespaced items from the shadcn registry", async () => { + const fixturePath = await createFixtureTestDirectory("next-app-init") + await npxShadcn(fixturePath, [ + "add", + "@shadcn/example-button", + "@shadcn/no-framework-item", + ]) + expect( + await fs.pathExists( + path.join(fixturePath, "components/example-button.tsx") + ) + ).toBe(true) + expect( + await fs.pathExists(path.join(fixturePath, "components/ui/button.tsx")) + ).toBe(true) + expect(await fs.pathExists(path.join(fixturePath, "path/to/foo.txt"))).toBe( + true + ) + expect( + await fs.readFile(path.join(fixturePath, "path/to/foo.txt"), "utf-8") + ).toBe("Foo Bar") + }) + + it("should add namespaced items from shadcn registry with no-framework", async () => { + const fixturePath = await createFixtureTestDirectory("no-framework") + await npxShadcn(fixturePath, ["add", "@shadcn/no-framework-item"]) + expect(await fs.pathExists(path.join(fixturePath, "path/to/foo.txt"))).toBe( + true + ) + expect( + await fs.readFile(path.join(fixturePath, "path/to/foo.txt"), "utf-8") + ).toBe("Foo Bar") + }) +}) diff --git a/packages/tests/src/utils/helpers.ts b/packages/tests/src/utils/helpers.ts index b39ea5a20..a031cc94e 100644 --- a/packages/tests/src/utils/helpers.ts +++ b/packages/tests/src/utils/helpers.ts @@ -1,11 +1,13 @@ +import { randomUUID } from "crypto" import path from "path" import { fileURLToPath } from "url" import { execa } from "execa" import fs from "fs-extra" +import { TEMP_DIR } from "./setup" + const __dirname = path.dirname(fileURLToPath(import.meta.url)) const FIXTURES_DIR = path.join(__dirname, "../../fixtures") -const TEMP_DIR = path.join(__dirname, "../../temp") const SHADCN_CLI_PATH = path.join(__dirname, "../../../shadcn/dist/index.js") export function getRegistryUrl() { @@ -14,12 +16,11 @@ export function getRegistryUrl() { export async function createFixtureTestDirectory(fixtureName: string) { const fixturePath = path.join(FIXTURES_DIR, fixtureName) - const testDir = path.join( - TEMP_DIR, - `test-${Date.now()}-${Math.random().toString(36).substring(7)}` - ) - await fs.ensureDir(TEMP_DIR) + const uniqueId = `${process.pid}-${randomUUID().substring(0, 8)}` + let testDir = path.join(TEMP_DIR, `test-${uniqueId}-${fixtureName}`) + + await fs.ensureDir(testDir) await fs.copy(fixturePath, testDir) return testDir diff --git a/packages/tests/src/utils/registry.ts b/packages/tests/src/utils/registry.ts new file mode 100644 index 000000000..7c9bffd51 --- /dev/null +++ b/packages/tests/src/utils/registry.ts @@ -0,0 +1,205 @@ +import { createServer } from "http" +import path from "path" +import fs from "fs-extra" + +export async function createRegistryServer( + items: Array<{ name: string; type: string } & Record>, + { + port = 4444, + path = "/r", + }: { + port?: number + path?: string + } +) { + const server = createServer((request, response) => { + const urlWithoutQuery = request.url?.split("?")[0]?.replace(/\.json$/, "") + + if (urlWithoutQuery?.includes("icons/index")) { + response.writeHead(200, { "Content-Type": "application/json" }) + response.end( + JSON.stringify({ + AlertCircle: { + lucide: "AlertCircle", + radix: "ExclamationTriangleIcon", + }, + ArrowLeft: { + lucide: "ArrowLeft", + radix: "ArrowLeftIcon", + }, + }) + ) + return + } + + if (urlWithoutQuery?.includes("colors/neutral")) { + response.writeHead(200, { "Content-Type": "application/json" }) + response.end( + JSON.stringify({ + inlineColors: { + light: { + background: "white", + foreground: "neutral-950", + }, + dark: { + background: "neutral-950", + foreground: "neutral-50", + }, + }, + cssVars: { + light: { + background: "0 0% 100%", + foreground: "0 0% 3.9%", + }, + dark: { + background: "0 0% 3.9%", + foreground: "0 0% 98%", + }, + }, + cssVarsV4: { + light: { + background: "oklch(1 0 0)", + foreground: "oklch(0.145 0 0)", + }, + dark: { + background: "oklch(0.145 0 0)", + foreground: "oklch(0.985 0 0)", + }, + }, + inlineColorsTemplate: + "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ", + cssVarsTemplate: + "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer ", + }) + ) + return + } + + if (urlWithoutQuery?.includes("index")) { + response.writeHead(200, { "Content-Type": "application/json" }) + response.end( + JSON.stringify([ + { + name: "alert-dialog", + type: "registry:ui", + files: [ + { + path: "components/ui/alert-dialog.tsx", + type: "registry:ui", + content: + "export function AlertDialog() { return
AlertDialog Component from Registry Shadcn
}", + }, + ], + }, + { + name: "button", + type: "registry:ui", + files: [ + { + path: "components/ui/button.tsx", + type: "registry:ui", + content: + "export function Button() { return
Button Component from Registry Shadcn
}", + }, + ], + }, + ]) + ) + return + } + + const match = urlWithoutQuery?.match( + new RegExp(`^${path}/(?:.*/)?([^/]+)$`) + ) + const itemName = match?.[1] + const item = itemName + ? items.find((item) => item.name === itemName) + : undefined + + if (!item) { + response.writeHead(404, { "Content-Type": "application/json" }) + response.end(JSON.stringify({ error: "Item not found" })) + return + } + + if (request.url?.includes("/bearer/")) { + // Validate bearer token + const token = request.headers.authorization?.split(" ")[1] + if (token !== "EXAMPLE_BEARER_TOKEN") { + response.writeHead(401, { "Content-Type": "application/json" }) + response.end(JSON.stringify({ error: "Unauthorized" })) + return + } + } + + if (request.url?.includes("/api-key/")) { + // Validate api key + const apiKey = request.headers["x-api-key"] + if (apiKey !== "EXAMPLE_API_KEY") { + response.writeHead(401, { "Content-Type": "application/json" }) + response.end(JSON.stringify({ error: "Unauthorized" })) + return + } + } + + if (request.url?.includes("/client-secret/")) { + // Validate client secret + const clientSecret = request.headers["x-client-secret"] + const clientId = request.headers["x-client-id"] + if ( + clientSecret !== "EXAMPLE_CLIENT_SECRET" || + clientId !== "EXAMPLE_CLIENT_ID" + ) { + response.writeHead(401, { "Content-Type": "application/json" }) + response.end(JSON.stringify({ error: "Unauthorized" })) + return + } + } + + if (request.url?.includes("/params/")) { + const token = request.url.split("?")[1]?.split("=")[1] + if (token !== "EXAMPLE_REGISTRY_TOKEN") { + response.writeHead(401, { "Content-Type": "application/json" }) + response.end(JSON.stringify({ error: "Unauthorized" })) + return + } + } + + response.writeHead(200, { "Content-Type": "application/json" }) + response.end(JSON.stringify(item)) + }) + + return { + start: async () => { + await new Promise((resolve) => { + server.listen(port, () => { + resolve() + }) + }) + }, + stop: async () => { + await new Promise((resolve) => { + server.close(() => { + resolve() + }) + }) + }, + } +} + +export async function configureRegistries( + fixturePath: string, + payload: Record +) { + if (!fs.pathExistsSync(path.join(fixturePath, "components.json"))) { + await fs.writeJSON(path.join(fixturePath, "components.json"), { + payload, + }) + } + + const componentsJson = await fs.readJSON( + path.join(fixturePath, "components.json") + ) + componentsJson.registries = payload + await fs.writeJSON(path.join(fixturePath, "components.json"), componentsJson) +} diff --git a/packages/tests/src/utils/setup.ts b/packages/tests/src/utils/setup.ts index cf5b75d25..98b3acf24 100644 --- a/packages/tests/src/utils/setup.ts +++ b/packages/tests/src/utils/setup.ts @@ -1,18 +1,17 @@ -/* eslint-disable turbo/no-undeclared-env-vars */ -import { tmpdir } from "os" import path from "path" import fs from "fs-extra" import { rimraf } from "rimraf" -const TEMP_DIR = fs.mkdtempSync(path.join(tmpdir(), "shadcn-tests")) +export const TEMP_DIR = path.join(__dirname, "../../temp") -console.log("TEMP_DIR", TEMP_DIR) - -export async function setup() { - await rimraf(TEMP_DIR) +export default async function setup() { await fs.ensureDir(TEMP_DIR) -} -export async function teardown() { - await rimraf(TEMP_DIR) + return async () => { + try { + await rimraf(TEMP_DIR) + } catch (error) { + console.error("Failed to clean up temp directory:", error) + } + } } diff --git a/packages/tests/vitest.config.ts b/packages/tests/vitest.config.ts index 235d3ce39..3959b4b40 100644 --- a/packages/tests/vitest.config.ts +++ b/packages/tests/vitest.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ hookTimeout: 120000, globals: true, environment: "node", - globalSetup: "./src/utils/setup.ts", + globalSetup: ["./src/utils/setup.ts"], maxConcurrency: 4, isolate: false, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db0ac04e1..3f1f41b18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -713,6 +713,9 @@ importers: '@babel/plugin-transform-typescript': specifier: ^7.22.5 version: 7.26.7(@babel/core@7.26.7) + '@dotenvx/dotenvx': + specifier: ^1.48.4 + version: 1.48.4 '@modelcontextprotocol/sdk': specifier: ^1.10.2 version: 1.10.2 @@ -1190,6 +1193,16 @@ packages: peerDependencies: react: '>=16.8.0' + '@dotenvx/dotenvx@1.48.4': + resolution: {integrity: sha512-GpJWpGVI5JGhNzFlWOjCD3KMiN3xU1US4oLKQ7SiiGru4LvR7sUf3pDMpfjtlgzHStL5ydq4ekfZcRxWpHaJkA==} + hasBin: true + + '@ecies/ciphers@0.2.4': + resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + '@effect-ts/core@0.60.5': resolution: {integrity: sha512-qi1WrtJA90XLMnj2hnUszW9Sx4dXP03ZJtCc5DiUBIOhF4Vw7plfb65/bdBySPoC9s7zy995TdUX1XBSxUkl5w==} @@ -2543,6 +2556,18 @@ packages: cpu: [x64] os: [win32] + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.6': + resolution: {integrity: sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -4983,6 +5008,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -5366,6 +5395,10 @@ packages: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} + dotenv@17.2.1: + resolution: {integrity: sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==} + engines: {node: '>=12'} + dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} @@ -5383,6 +5416,10 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + eciesjs@0.4.15: + resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -6627,6 +6664,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} @@ -7568,6 +7609,10 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} @@ -8625,6 +8670,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -9497,6 +9543,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -10258,6 +10309,22 @@ snapshots: react: 19.1.0 tslib: 2.8.1 + '@dotenvx/dotenvx@1.48.4': + dependencies: + commander: 11.1.0 + dotenv: 17.2.1 + eciesjs: 0.4.15 + execa: 5.1.1 + fdir: 6.4.6(picomatch@4.0.3) + ignore: 5.3.1 + object-treeify: 1.1.33 + picomatch: 4.0.3 + which: 4.0.0 + + '@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + '@effect-ts/core@0.60.5': dependencies: '@effect-ts/system': 0.57.5 @@ -10299,7 +10366,7 @@ snapshots: '@esbuild-plugins/node-resolve@0.2.2(esbuild@0.25.0)': dependencies: '@types/resolve': 1.20.6 - debug: 4.4.0 + debug: 4.4.1 esbuild: 0.25.0 escape-string-regexp: 4.0.0 resolve: 1.22.10 @@ -11287,6 +11354,14 @@ snapshots: '@next/swc-win32-x64-msvc@15.3.1': optional: true + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.6': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -14471,6 +14546,8 @@ snapshots: commander@10.0.1: {} + commander@11.1.0: {} + commander@4.1.1: {} comment-json@4.2.5: @@ -14825,6 +14902,8 @@ snapshots: dotenv@16.0.3: {} + dotenv@17.2.1: {} + dotenv@8.6.0: {} dunder-proto@1.0.1: @@ -14839,6 +14918,13 @@ snapshots: eastasianwidth@0.2.0: {} + eciesjs@0.4.15: + dependencies: + '@ecies/ciphers': 0.2.4(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.6 + '@noble/hashes': 1.8.0 + ee-first@1.1.1: {} electron-to-chromium@1.5.90: {} @@ -15719,7 +15805,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.0 + debug: 4.4.1 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -16059,7 +16145,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.4.0 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -16471,7 +16557,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -16485,7 +16571,7 @@ snapshots: https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -16730,6 +16816,8 @@ snapshots: isexe@2.0.0: {} + isexe@3.1.1: {} + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -17656,7 +17744,7 @@ snapshots: micromark@3.2.0: dependencies: '@types/debug': 4.1.12 - debug: 4.4.0 + debug: 4.4.1 decode-named-character-reference: 1.0.2 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 @@ -17678,7 +17766,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.0 + debug: 4.4.1 decode-named-character-reference: 1.1.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -18005,6 +18093,8 @@ snapshots: object-keys@1.1.1: {} + object-treeify@1.1.33: {} + object.assign@4.1.7: dependencies: call-bind: 1.0.8 @@ -18146,7 +18236,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.1 get-uri: 6.0.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -18418,7 +18508,7 @@ snapshots: proxy-agent@6.5.0: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.1 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -19378,7 +19468,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.1 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -20354,7 +20444,7 @@ snapshots: vite-node@2.1.9(@types/node@20.17.16)(lightningcss@1.30.1): dependencies: cac: 6.7.14 - debug: 4.4.0 + debug: 4.4.1 es-module-lexer: 1.6.0 pathe: 1.1.2 vite: 5.4.15(@types/node@20.17.16)(lightningcss@1.30.1) @@ -20371,7 +20461,7 @@ snapshots: vite-tsconfig-paths@4.3.2(typescript@5.7.3)(vite@5.4.15(@types/node@20.17.16)(lightningcss@1.30.1)): dependencies: - debug: 4.4.0 + debug: 4.4.1 globrex: 0.1.2 tsconfck: 3.1.4(typescript@5.7.3) optionalDependencies: @@ -20400,7 +20490,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.2.0 - debug: 4.4.0 + debug: 4.4.1 expect-type: 1.2.0 magic-string: 0.30.17 pathe: 1.1.2 @@ -20506,6 +20596,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.1 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 156f9ba37..3f9f260ce 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,3 +2,5 @@ packages: - "apps/*" - "packages/*" - "!**/test/**" + - "!**/fixtures/**" + - "!**/temp/**"