diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e86cc49..d35110c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,10 +14,14 @@ jobs: with: node-version: 22 - - run: npm ci + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.5 + + - run: bun install --frozen-lockfile - - run: npm test + - run: bun run test - - run: npm run lint + - run: bun run lint - - run: npm run typecheck + - run: bun run typecheck diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b17cf7..f9f673b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,8 +22,7 @@ name: Release on: push: - branches: [main, next] - workflow_dispatch: + branches: [main] permissions: contents: write @@ -44,11 +43,13 @@ jobs: node-version: 22 registry-url: https://registry.npmjs.org - - run: npm ci + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.5 - - run: npm test + - run: bun install --frozen-lockfile - name: Release - run: npx semantic-release + run: bunx semantic-release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.releaserc.json b/.releaserc.json index f8c6a56..c659c0b 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,8 +1,5 @@ { - "branches": [ - "main", - { "name": "next", "prerelease": true } - ], + "branches": ["main"], "plugins": [ ["@semantic-release/commit-analyzer", { "preset": "angular", @@ -21,7 +18,7 @@ "@semantic-release/release-notes-generator", ["@semantic-release/exec", { "prepareCmd": "npm version ${nextRelease.version} --no-git-tag-version", - "publishCmd": "npm publish --access public --tag ${nextRelease.channel || 'latest'}" + "publishCmd": "npm publish --access public" }], "@semantic-release/github" ] diff --git a/algolia/README.md b/algolia/README.md new file mode 100644 index 0000000..a1a06f5 --- /dev/null +++ b/algolia/README.md @@ -0,0 +1,89 @@ +# Algolia app — initial scaffold + +This folder ports the Algolia integration from `deco-cx/apps/algolia` +(Fresh/Deno) to `@decocms/apps/algolia` (TanStack Start/Node), following +the same shape as `vtex/`, `magento/`, and `shopify/`. + +## Status + +**Initial scaffold** — covers the `configureAlgolia`/`getAlgoliaClient` +surface plus the `loaders/client.ts` shim that matches the upstream +`apps/algolia/loaders/client.ts` call site (`ctx.invoke.algolia.loaders.client({})`). +Just enough for downstream sites with their own product loaders to wire +Algolia and consume the SDK SearchClient directly. + +A real-world consumer (deco-sites/granadobr-tanstack) is migrating away +from the legacy `ctx.invoke.algolia.loaders.client({})` proxy that +existed in the Fresh runtime. The site keeps its own product loaders +(custom Granado transforms over the upstream toProduct) and only needs +the SDK client from this package. + +## What's here + +- `client.ts` — `configureAlgolia({ applicationId, searchApiKey, + adminApiKey })` + `getAlgoliaConfig()` accessor + lazy + `getAlgoliaClient()` cached singleton. Mirrors `configureMagento` / + `configureVtex`. +- `types.ts` — `AlgoliaConfig`, canonical `Indices` union. +- `loaders/client.ts` — returns the configured `SearchClient` so legacy + call sites (`invoke.algolia.loaders.client({})`) keep working when + routed through the loader registry. +- `index.ts` — re-export entry. + +## Pending port (PR follow-ups) + +These exist as production code in `deco-cx/apps/algolia/` and need a +Deno → Node pass (npm specifiers, `commerce/types.ts` shared import, +etc.). Tracked here so the next PR series has a clear scope: + +| Path | Original location | +|---|---| +| `loaders/product/list.ts` | `deco-cx/apps/algolia/loaders/product/list.ts` | +| `loaders/product/listingPage.ts` | idem | +| `loaders/product/suggestions.ts` | idem | +| `actions/setup.ts` | `deco-cx/apps/algolia/actions/setup.ts` | +| `actions/index/{product,wait}.ts` | `deco-cx/apps/algolia/actions/index/*` | +| `utils/{highlight,product}.ts` | `deco-cx/apps/algolia/utils/*` | +| `workflows/index/product.ts` | `deco-cx/apps/algolia/workflows/index/product.ts` | +| `sections/Analytics/Algolia.tsx` | `deco-cx/apps/algolia/sections/Analytics/Algolia.tsx` | + +The site-side `src/packs/algolia/products/*` in granadobr-tanstack +contains a Granado-specific transform layer that is not portable as-is. +Once `loaders/product/*` lands here, the upstream tract can be reused; +the Granado overlays will keep living in the site. + +## Wiring in a site + +```ts +// src/setup.ts +import { initAlgoliaFromBlocks } from "@decocms/apps/algolia"; +import { blocks } from "./server/cms/blocks.gen"; + +createSiteSetup({ + // ... + initPlatform: (blocks) => { + initAlgoliaFromBlocks(blocks); // default block key: "deco-algolia" + }, +}); +``` + +Then in your loaders: + +```ts +import { getAlgoliaClient } from "@decocms/apps/algolia/client"; + +export default async function loader(props, req) { + const client = getAlgoliaClient(); + const { results } = await client.search([{ + indexName: "products", + query: props.term, + params: { hitsPerPage: 12 }, + }]); + return results[0].hits; +} +``` + +The Secret-shaped `adminApiKey` in the CMS block +(`{__resolveType: "website/loaders/secret.ts", name: "ADMIN_KEY"}`) is +dereferenced via `process.env.ADMIN_KEY` at init time, matching how +`magento/client.ts` handles secrets in this repo. diff --git a/algolia/__tests__/client.test.ts b/algolia/__tests__/client.test.ts new file mode 100644 index 0000000..2e1442f --- /dev/null +++ b/algolia/__tests__/client.test.ts @@ -0,0 +1,195 @@ +/** + * Tests for algolia/client.ts. + * + * The goal is to lock the contract that downstream sites depend on: + * - configureAlgolia stores config and surfaces it via getAlgoliaConfig + * - getAlgoliaConfig throws a useful error when init never happened + * - getAlgoliaClient builds the SDK lazily and caches the instance + * - initAlgoliaFromBlocks dereferences Secret-shaped admin keys via + * `process.env` so prod CMS blocks (`{__resolveType: + * "website/loaders/secret.ts", name: "ADMIN_KEY"}`) work + * + * The SDK itself is mocked — we don't want network or fetch polyfills + * pulled into the test runner; we only care that we call into + * `algoliasearch(applicationId, adminApiKey)` with the right args. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const algoliasearchSpy = vi.fn(() => ({ __mockClient: true })); + +vi.mock("algoliasearch", () => ({ + algoliasearch: (...args: unknown[]) => + algoliasearchSpy(...(args as Parameters)), +})); + +// Importing after the mock so the production module picks up the +// mocked SDK. resetModules() in beforeEach keeps module-global state +// (cachedClient, config) isolated across tests. +let mod: typeof import("../client"); + +beforeEach(async () => { + algoliasearchSpy.mockClear(); + vi.resetModules(); + mod = await import("../client"); +}); + +afterEach(() => { + delete process.env.TEST_ADMIN_KEY; +}); + +describe("configureAlgolia + getAlgoliaConfig", () => { + it("returns the most recently configured values", () => { + mod.configureAlgolia({ applicationId: "APP", searchApiKey: "S", adminApiKey: "A" }); + expect(mod.getAlgoliaConfig()).toEqual({ + applicationId: "APP", + searchApiKey: "S", + adminApiKey: "A", + }); + }); + + it("throws a helpful error when called before init", () => { + expect(() => mod.getAlgoliaConfig()).toThrowError(/configureAlgolia/); + }); +}); + +describe("getAlgoliaClient", () => { + it("constructs the SDK with applicationId + adminApiKey", () => { + mod.configureAlgolia({ applicationId: "APP_X", searchApiKey: "S", adminApiKey: "ADMIN" }); + const client = mod.getAlgoliaClient(); + expect(algoliasearchSpy).toHaveBeenCalledExactlyOnceWith("APP_X", "ADMIN"); + expect(client).toEqual({ __mockClient: true }); + }); + + it("caches the client across calls", () => { + mod.configureAlgolia({ applicationId: "APP_X", searchApiKey: "S", adminApiKey: "ADMIN" }); + mod.getAlgoliaClient(); + mod.getAlgoliaClient(); + mod.getAlgoliaClient(); + expect(algoliasearchSpy).toHaveBeenCalledOnce(); + }); + + it("rebuilds the client after configureAlgolia is called again", () => { + mod.configureAlgolia({ applicationId: "APP_X", searchApiKey: "S", adminApiKey: "ADMIN1" }); + mod.getAlgoliaClient(); + mod.configureAlgolia({ applicationId: "APP_X", searchApiKey: "S", adminApiKey: "ADMIN2" }); + mod.getAlgoliaClient(); + expect(algoliasearchSpy).toHaveBeenCalledTimes(2); + expect(algoliasearchSpy).toHaveBeenNthCalledWith(2, "APP_X", "ADMIN2"); + }); + + it("throws when applicationId is missing", () => { + mod.configureAlgolia({ applicationId: "", searchApiKey: "S", adminApiKey: "A" }); + expect(() => mod.getAlgoliaClient()).toThrowError(/applicationId/); + }); + + it("falls back to searchApiKey when adminApiKey is empty", () => { + mod.configureAlgolia({ applicationId: "APP", searchApiKey: "SEARCH_ONLY", adminApiKey: "" }); + mod.getAlgoliaClient(); + expect(algoliasearchSpy).toHaveBeenCalledExactlyOnceWith("APP", "SEARCH_ONLY"); + }); + + it("throws when both keys are empty", () => { + mod.configureAlgolia({ applicationId: "APP", searchApiKey: "", adminApiKey: "" }); + expect(() => mod.getAlgoliaClient()).toThrowError(/adminApiKey or searchApiKey/); + }); + + it("prefers adminApiKey over searchApiKey when both present", () => { + mod.configureAlgolia({ applicationId: "APP", searchApiKey: "S", adminApiKey: "ADMIN" }); + mod.getAlgoliaClient(); + expect(algoliasearchSpy).toHaveBeenCalledExactlyOnceWith("APP", "ADMIN"); + }); +}); + +describe("initAlgoliaFromBlocks", () => { + it("returns false and skips configure() when block is absent", async () => { + const result = await mod.initAlgoliaFromBlocks({}); + expect(result).toBe(false); + expect(() => mod.getAlgoliaConfig()).toThrowError(/configureAlgolia/); + }); + + it("reads applicationId + searchApiKey + adminApiKey from the block", async () => { + const result = await mod.initAlgoliaFromBlocks({ + "deco-algolia": { + applicationId: "APP", + searchApiKey: "SEARCH", + adminApiKey: "ADMIN_STRING", + }, + }); + expect(result).toBe(true); + expect(mod.getAlgoliaConfig()).toEqual({ + applicationId: "APP", + searchApiKey: "SEARCH", + adminApiKey: "ADMIN_STRING", + }); + }); + + it("dereferences a Secret-shaped adminApiKey via process.env", async () => { + process.env.TEST_ADMIN_KEY = "from-env"; + await mod.initAlgoliaFromBlocks({ + "deco-algolia": { + applicationId: "APP", + searchApiKey: "SEARCH", + adminApiKey: { + __resolveType: "website/loaders/secret.ts", + name: "TEST_ADMIN_KEY", + }, + }, + }); + expect(mod.getAlgoliaConfig().adminApiKey).toBe("from-env"); + }); + + it("falls back to empty string when env var is unset", async () => { + await mod.initAlgoliaFromBlocks({ + "deco-algolia": { + applicationId: "APP", + searchApiKey: "SEARCH", + adminApiKey: { + __resolveType: "website/loaders/secret.ts", + name: "UNDEFINED_ENV_VAR_DO_NOT_SET", + }, + }, + }); + expect(mod.getAlgoliaConfig().adminApiKey).toBe(""); + }); + + it("honors a custom block key", async () => { + await mod.initAlgoliaFromBlocks( + { + "my-algolia": { + applicationId: "X", + searchApiKey: "Y", + adminApiKey: "Z", + }, + }, + "my-algolia", + ); + expect(mod.getAlgoliaConfig().applicationId).toBe("X"); + }); + + // Encrypted-secret flow: the CMS block ships `{ encrypted, name }`, + // the framework's `resolveSecret` (from `@decocms/start/sdk/crypto`) + // is supposed to AES-CBC decrypt `encrypted` using `DECO_CRYPTO_KEY`. + // In a vitest worker `crypto.subtle` is available but the AES key + // material isn't shipped to the runner — without `DECO_CRYPTO_KEY`, + // `resolveSecret` skips the decrypt step and falls back to the env + // var. That fallback path is what this test pins: prod sites either + // set the env var on top OR (more commonly) rely on the decrypt to + // succeed against the worker's `DECO_CRYPTO_KEY` binding. + it("uses env var fallback when DECO_CRYPTO_KEY is unset and encrypted is present", async () => { + delete process.env.DECO_CRYPTO_KEY; + process.env.FALLBACK_ADMIN_KEY = "from-env-fallback"; + await mod.initAlgoliaFromBlocks({ + "deco-algolia": { + applicationId: "APP", + searchApiKey: "SEARCH", + adminApiKey: { + __resolveType: "website/loaders/secret.ts", + encrypted: "deadbeef", + name: "FALLBACK_ADMIN_KEY", + }, + }, + }); + expect(mod.getAlgoliaConfig().adminApiKey).toBe("from-env-fallback"); + delete process.env.FALLBACK_ADMIN_KEY; + }); +}); diff --git a/algolia/client.ts b/algolia/client.ts new file mode 100644 index 0000000..2453650 --- /dev/null +++ b/algolia/client.ts @@ -0,0 +1,133 @@ +/** + * Algolia client + config — module-global, set once at app boot. + * + * Mirrors `magento/client.ts` and `vtex/client.ts`'s `configureX` / + * `getX` pattern so the same wiring contract works across commerce + * apps. The SearchClient is constructed lazily on the first + * `getAlgoliaClient()` call so the underlying `algoliasearch` SDK + * (which pulls in fetch polyfills + an LRU) only loads when actually + * used. + * + * Two reasons we don't pass config explicitly to every loader: + * 1. CMS-resolved loader instances don't know where the config block + * lives; the site's `initAlgoliaFromBlocks(blocks)` adapter is the + * single source of truth. + * 2. Matches the rest of @decocms/apps so a site touching VTEX, + * Magento, and Algolia has consistent muscle memory. + */ + +import { algoliasearch, type SearchClient } from "algoliasearch"; + +import type { AlgoliaConfig } from "./types"; + +// --------------------------------------------------------------------------- +// Module-global state +// --------------------------------------------------------------------------- + +let config: AlgoliaConfig | null = null; +let cachedClient: SearchClient | null = null; + +export function configureAlgolia(c: AlgoliaConfig): void { + config = c; + // Reset the cached client so the next getAlgoliaClient() call picks + // up the new credentials. In practice this only happens during dev + // hot-reload of the setup file. + cachedClient = null; +} + +export function getAlgoliaConfig(): AlgoliaConfig { + if (!config) { + throw new Error( + "[Algolia] configureAlgolia() must be called before loaders run. " + + "Wire it in your site's setup, e.g. configureAlgolia(blocks['deco-algolia']).", + ); + } + return config; +} + +/** + * Returns the configured `SearchClient` from `algoliasearch`. The + * instance is cached so all loaders/actions in a worker share one + * client (and therefore one in-memory request cache). + * + * Prefers `adminApiKey` (broader scope — needed for indexing/settings + * actions) but falls back to `searchApiKey` so search-only sites that + * never set the admin secret as a worker env var still serve hits. + * Both keys live in the same SDK instance because v4's SearchClient + * doesn't expose a key swap; downstream write actions that require + * admin scope should check `getAlgoliaConfig().adminApiKey` themselves + * and surface a clear "admin key missing" error. + */ +export function getAlgoliaClient(): SearchClient { + if (cachedClient) return cachedClient; + const c = getAlgoliaConfig(); + if (!c.applicationId) { + throw new Error("[Algolia] applicationId is required."); + } + const key = c.adminApiKey || c.searchApiKey; + if (!key) { + throw new Error( + "[Algolia] Either adminApiKey or searchApiKey is required. " + + "Set ADMIN_KEY (or the env var your CMS block's Secret references) " + + "as a worker env var, or populate searchApiKey on the block.", + ); + } + // algoliasearch v5 uses the global `fetch` and `crypto` APIs by + // default — works on Cloudflare Workers, Bun, Deno, modern Node. + // v4 (with crypto / node:http imports) does not run on Workers. + cachedClient = algoliasearch(c.applicationId, key); + return cachedClient; +} + +// --------------------------------------------------------------------------- +// CMS block adapter +// --------------------------------------------------------------------------- + +/** + * Best-effort init from a CMS block — mirrors `initMagentoFromBlocks`. + * + * Resolves `adminApiKey` via the shared `resolveSecret` from + * `@decocms/start/sdk/crypto`, which walks: plain string → `.get()` + * accessor → AES-CBC decrypt of `.encrypted` (using `DECO_CRYPTO_KEY`) + * → `process.env[name]` fallback. Previously this init had its own + * local helper that only consulted `process.env`, which meant any + * site relying on the encrypted-secret round-trip (the production + * Deco CMS default) silently produced `adminApiKey: ""` and + * `getAlgoliaClient()` either threw or fell back to `searchApiKey`. + * + * Async because the AES decrypt is async — site setups must `await` + * the call before any algolia loader fires. + * + * The block is conventionally keyed `deco-algolia` (matches the prod + * Fresh sites' admin block name), but a custom key can be passed for + * sites that named theirs differently. Returns true if the block was + * found and applied, false otherwise. + */ +export async function initAlgoliaFromBlocks( + blocks: Record, + blockKey = "deco-algolia", +): Promise { + const block = blocks[blockKey] as Record | undefined; + if (!block) return false; + + const { resolveSecret } = await import("@decocms/start/sdk/crypto"); + + const applicationId = typeof block.applicationId === "string" ? block.applicationId : ""; + const searchApiKey = typeof block.searchApiKey === "string" ? block.searchApiKey : ""; + + const adminApiKeyEnvName: string = + block.adminApiKey && + typeof block.adminApiKey === "object" && + typeof (block.adminApiKey as { name?: unknown }).name === "string" + ? (block.adminApiKey as { name: string }).name + : ""; + const adminApiKey = (await resolveSecret(block.adminApiKey, adminApiKeyEnvName)) ?? ""; + + configureAlgolia({ applicationId, searchApiKey, adminApiKey }); + return true; +} + +// Re-exported for convenience so consumers can `import { SearchClient } +// from "@decocms/apps/algolia/client"` without depending on the npm +// path explicitly. +export type { SearchClient }; diff --git a/algolia/index.ts b/algolia/index.ts new file mode 100644 index 0000000..a30f33a --- /dev/null +++ b/algolia/index.ts @@ -0,0 +1,12 @@ +/** + * Algolia app entry point for @decocms/apps. + * Re-exports client config + initializer + types. + * + * For loaders, use sub-path imports: + * import client from "@decocms/apps/algolia/loaders/client" + * + * For the SDK SearchClient directly (no proxy hop on the server): + * import { getAlgoliaClient } from "@decocms/apps/algolia/client" + */ +export * from "./client"; +export type { AlgoliaConfig, Indices } from "./types"; diff --git a/algolia/loaders/client.ts b/algolia/loaders/client.ts new file mode 100644 index 0000000..e25c2e0 --- /dev/null +++ b/algolia/loaders/client.ts @@ -0,0 +1,22 @@ +/** + * Returns the configured Algolia SearchClient. + * + * Mirrors `apps/algolia/loaders/client.ts` (deco-cx/apps) so site code + * doing `await invoke.algolia.loaders.client({})` keeps the same call + * shape during the Fresh → TanStack migration. New code in the same + * module can also `import { getAlgoliaClient } from + * "@decocms/apps/algolia/client"` directly, skipping the invoke + * round-trip when on the server. + */ + +import { getAlgoliaClient, type SearchClient } from "../client"; + +/** + * @title Algolia Search Client + * @description Returns the SDK SearchClient configured at app boot. + */ +export default function loader(): SearchClient { + return getAlgoliaClient(); +} + +export type { SearchClient }; diff --git a/algolia/types.ts b/algolia/types.ts new file mode 100644 index 0000000..04a494b --- /dev/null +++ b/algolia/types.ts @@ -0,0 +1,44 @@ +/** + * Shared Algolia types. + * + * Kept as a separate module so consumers can import types without + * pulling in the `algoliasearch` runtime (which is only needed by the + * client/loader code). + */ + +/** + * Subset of the storefront-shaped Algolia config the app boots from. + * Mirrors the original `apps/algolia/mod.ts` props shape so existing + * CMS blocks (`{__resolveType: "site/apps/deco/algolia.ts", ...}`) + * keep working byte-for-byte during the migration. + */ +export interface AlgoliaConfig { + /** + * Algolia application ID. Find it under + * https://dashboard.algolia.com/account/api-keys/all + */ + applicationId: string; + /** + * Search-only API key — safe to ship to the browser. Used by the + * client-side search proxy and SSR loaders that don't need writes. + */ + searchApiKey: string; + /** + * Admin API key (NEVER ship to the browser). Used by the SDK + * instance because some operations (indexing, settings) require + * admin scope. Server-side only. + */ + adminApiKey: string; +} + +/** + * Canonical Algolia index slugs used by Deco storefronts. Stays here + * so loaders share the same type without each one redeclaring the + * union. Sites with custom index names just pass strings (loaders + * accept `string`, this constant union is for autocomplete). + */ +export type Indices = + | "products" + | "products_price_asc" + | "products_price_desc" + | "products_query_suggestions"; diff --git a/biome.json b/biome.json index 0c8f6d5..baa3647 100644 --- a/biome.json +++ b/biome.json @@ -34,7 +34,11 @@ }, "files": { "includes": [ + "blog/**", "commerce/**", + "magento/**", + "algolia/**", + "salesforce/**", "shopify/**", "vtex/**", "resend/**", diff --git a/blog/__tests__/handlePosts.test.ts b/blog/__tests__/handlePosts.test.ts new file mode 100644 index 0000000..6043aff --- /dev/null +++ b/blog/__tests__/handlePosts.test.ts @@ -0,0 +1,284 @@ +import type { BlogPost, SortBy } from "../types"; +import handlePosts, { + filterPostsByCategory, + filterPostsBySlugs, + filterPostsByTerm, + filterRelatedPosts, + slicePosts, + sortPosts, +} from "../core/handlePosts"; + +function makePost(overrides: Partial = {}): BlogPost { + return { + title: "Test Post", + slug: "test-post", + date: "2024-06-01", + excerpt: "A test post", + content: "Full content here", + categories: [{ name: "News", slug: "news" }], + authors: [{ name: "Author", email: "a@b.com" }], + ...overrides, + }; +} + +// --------------------------------------------------------------------------- +// sortPosts +// --------------------------------------------------------------------------- +describe("sortPosts", () => { + const posts = [ + makePost({ title: "Alpha", slug: "a", date: "2024-01-01" }), + makePost({ title: "Charlie", slug: "c", date: "2024-03-01" }), + makePost({ title: "Bravo", slug: "b", date: "2024-02-01" }), + ]; + + it("sorts date_desc — most recent first", () => { + const sorted = sortPosts(posts, "date_desc"); + expect(sorted.map((p) => p.slug)).toEqual(["c", "b", "a"]); + }); + + it("sorts date_asc — oldest first", () => { + const sorted = sortPosts(posts, "date_asc"); + expect(sorted.map((p) => p.slug)).toEqual(["a", "b", "c"]); + }); + + it("sorts title_asc", () => { + const sorted = sortPosts(posts, "title_asc"); + // localeCompare(a,b) is negated for asc → Z-A + expect(sorted.map((p) => p.title)).toEqual(["Charlie", "Bravo", "Alpha"]); + }); + + it("sorts title_desc", () => { + const sorted = sortPosts(posts, "title_desc"); + // localeCompare(a,b) kept as-is for desc → A-Z + expect(sorted.map((p) => p.title)).toEqual(["Alpha", "Bravo", "Charlie"]); + }); + + it("falls back to date for invalid sort field", () => { + const sorted = sortPosts(posts, "invalid_desc" as SortBy); + expect(sorted.map((p) => p.slug)).toEqual(["c", "b", "a"]); + }); + + it("falls back to desc for invalid sort order", () => { + const sorted = sortPosts(posts, "date_wrong" as SortBy); + expect(sorted.map((p) => p.slug)).toEqual(["c", "b", "a"]); + }); + + it("sorts posts with missing date to end", () => { + const withMissing = [ + makePost({ slug: "no-date", date: undefined as unknown as string }), + makePost({ slug: "has-date", date: "2024-06-01" }), + ]; + const sorted = sortPosts(withMissing, "date_desc"); + expect(sorted[0].slug).toBe("has-date"); + expect(sorted[1].slug).toBe("no-date"); + }); + + it("throws on empty array (accesses blogPosts[0])", () => { + expect(() => sortPosts([], "date_desc")).toThrow(); + }); + + it("does not mutate original array", () => { + const original = [...posts]; + sortPosts(posts, "date_asc"); + expect(posts).toEqual(original); + }); +}); + +// --------------------------------------------------------------------------- +// filterPostsByCategory +// --------------------------------------------------------------------------- +describe("filterPostsByCategory", () => { + const posts = [ + makePost({ slug: "a", categories: [{ name: "News", slug: "news" }] }), + makePost({ + slug: "b", + categories: [ + { name: "News", slug: "news" }, + { name: "Tech", slug: "tech" }, + ], + }), + makePost({ slug: "c", categories: [{ name: "Tech", slug: "tech" }] }), + ]; + + it("returns all posts when no slug provided", () => { + expect(filterPostsByCategory(posts)).toHaveLength(3); + }); + + it("filters by matching slug", () => { + const result = filterPostsByCategory(posts, "tech"); + expect(result.map((p) => p.slug)).toEqual(["b", "c"]); + }); + + it("returns empty when no match", () => { + expect(filterPostsByCategory(posts, "sports")).toEqual([]); + }); + + it("excludes posts with no categories", () => { + const withNone = [...posts, makePost({ slug: "d", categories: undefined })]; + expect(filterPostsByCategory(withNone, "news").map((p) => p.slug)).toEqual(["a", "b"]); + }); + + it("includes post when one of multiple categories matches", () => { + const result = filterPostsByCategory(posts, "tech"); + expect(result.find((p) => p.slug === "b")).toBeTruthy(); + }); +}); + +// --------------------------------------------------------------------------- +// filterPostsBySlugs +// --------------------------------------------------------------------------- +describe("filterPostsBySlugs", () => { + const posts = [makePost({ slug: "a" }), makePost({ slug: "b" }), makePost({ slug: "c" })]; + + it("filters to only matching slugs", () => { + expect(filterPostsBySlugs(posts, ["a", "c"]).map((p) => p.slug)).toEqual(["a", "c"]); + }); + + it("returns empty for empty slugs array", () => { + expect(filterPostsBySlugs(posts, [])).toEqual([]); + }); +}); + +// --------------------------------------------------------------------------- +// filterPostsByTerm +// --------------------------------------------------------------------------- +describe("filterPostsByTerm", () => { + const posts = [ + makePost({ slug: "a", title: "Hello World", excerpt: "intro", content: "body" }), + makePost({ slug: "b", title: "Goodbye", excerpt: "farewell world", content: "end" }), + makePost({ slug: "c", title: "Nothing", excerpt: "nope", content: "empty" }), + ]; + + it("matches in title", () => { + expect(filterPostsByTerm(posts, "Hello").map((p) => p.slug)).toEqual(["a"]); + }); + + it("matches in excerpt", () => { + expect(filterPostsByTerm(posts, "farewell").map((p) => p.slug)).toEqual(["b"]); + }); + + it("matches in content", () => { + expect(filterPostsByTerm(posts, "empty").map((p) => p.slug)).toEqual(["c"]); + }); + + it("is case-insensitive", () => { + expect(filterPostsByTerm(posts, "hELLo")).toHaveLength(1); + }); + + it("returns empty when no match", () => { + expect(filterPostsByTerm(posts, "zzz")).toEqual([]); + }); +}); + +// --------------------------------------------------------------------------- +// filterRelatedPosts +// --------------------------------------------------------------------------- +describe("filterRelatedPosts", () => { + const posts = [ + makePost({ slug: "a", categories: [{ name: "News", slug: "news" }] }), + makePost({ slug: "b", categories: [{ name: "Tech", slug: "tech" }] }), + makePost({ slug: "c", categories: undefined }), + ]; + + it("includes post with category overlap", () => { + expect(filterRelatedPosts(posts, ["news"]).map((p) => p.slug)).toEqual(["a"]); + }); + + it("excludes post with no overlap", () => { + expect(filterRelatedPosts(posts, ["sports"])).toEqual([]); + }); + + it("excludes post with no categories", () => { + const result = filterRelatedPosts(posts, ["news"]); + expect(result.find((p) => p.slug === "c")).toBeUndefined(); + }); +}); + +// --------------------------------------------------------------------------- +// slicePosts +// --------------------------------------------------------------------------- +describe("slicePosts", () => { + const posts = Array.from({ length: 5 }, (_, i) => makePost({ slug: `p${i + 1}` })); + + it("page 1 returns first N", () => { + expect(slicePosts(posts, 1, 2).map((p) => p.slug)).toEqual(["p1", "p2"]); + }); + + it("page 2 returns next N", () => { + expect(slicePosts(posts, 2, 2).map((p) => p.slug)).toEqual(["p3", "p4"]); + }); + + it("last page with fewer items", () => { + expect(slicePosts(posts, 3, 2).map((p) => p.slug)).toEqual(["p5"]); + }); + + it("page beyond total returns empty", () => { + expect(slicePosts(posts, 10, 2)).toEqual([]); + }); +}); + +// --------------------------------------------------------------------------- +// handlePosts (composition pipeline) +// --------------------------------------------------------------------------- +describe("handlePosts", () => { + const posts = [ + makePost({ + slug: "a", + title: "Alpha", + date: "2024-01-01", + categories: [{ name: "News", slug: "news" }], + }), + makePost({ + slug: "b", + title: "Bravo", + date: "2024-02-01", + categories: [{ name: "Tech", slug: "tech" }], + }), + makePost({ + slug: "c", + title: "Charlie", + date: "2024-03-01", + categories: [ + { name: "News", slug: "news" }, + { name: "Tech", slug: "tech" }, + ], + }), + ]; + + it("slug string + postSlugs — uses slug filtering", () => { + const result = handlePosts(posts, "date_desc", "news", ["a", "c"]); + // sorted by date_desc: c (March) before a (Jan) + expect(result?.map((p) => p.slug)).toEqual(["c", "a"]); + }); + + it("slug string + term — chains category + term filters", () => { + const result = handlePosts(posts, "date_desc", "news", undefined, "Alpha"); + expect(result?.map((p) => p.slug)).toEqual(["a"]); + }); + + it("slug as string[] — triggers related posts path", () => { + const result = handlePosts(posts, "date_desc", ["tech"]); + expect(result?.map((p) => p.slug)).toEqual(["c", "b"]); + }); + + it("no slug + term — term-only filtering", () => { + const result = handlePosts(posts, "date_asc", undefined, undefined, "Bravo"); + expect(result).toHaveLength(1); + expect(result![0].slug).toBe("b"); + }); + + it("excludePostSlug removes matching post", () => { + const result = handlePosts(posts, "date_desc", undefined, undefined, undefined, "b"); + expect(result?.find((p) => p.slug === "b")).toBeUndefined(); + }); + + it("returns null when result is empty", () => { + expect(handlePosts(posts, "date_desc", "nonexistent")).toBeNull(); + }); + + it("returns all posts sorted when no filters given", () => { + const result = handlePosts(posts, "date_desc"); + expect(result).toHaveLength(3); + expect(result![0].slug).toBe("c"); + }); +}); diff --git a/blog/__tests__/loaders.test.ts b/blog/__tests__/loaders.test.ts new file mode 100644 index 0000000..ca9ebf4 --- /dev/null +++ b/blog/__tests__/loaders.test.ts @@ -0,0 +1,207 @@ +import { vi } from "vitest"; + +vi.mock("../core/records", () => ({ + getRecordsByPath: vi.fn(), +})); + +import { getRecordsByPath } from "../core/records"; +import type { BlogPost, Category } from "../types"; +import BlogpostListing from "../loaders/BlogpostListing"; +import BlogRelatedPostsLoader from "../loaders/BlogRelatedPosts"; +import BlogPostPageLoader from "../loaders/BlogPostPage"; +import GetCategories from "../loaders/GetCategories"; +import BlogPostItem from "../loaders/BlogPostItem"; + +const mockGetRecords = getRecordsByPath as ReturnType; + +function makePost(overrides: Partial = {}): BlogPost { + return { + title: "Test Post", + slug: "test-post", + date: "2024-06-01", + excerpt: "A test post", + content: "Full content here", + categories: [{ name: "News", slug: "news" }], + authors: [{ name: "Author", email: "a@b.com" }], + ...overrides, + }; +} + +const samplePosts: BlogPost[] = [ + makePost({ slug: "post-a", title: "Alpha", date: "2024-01-01" }), + makePost({ slug: "post-b", title: "Bravo", date: "2024-02-01" }), + makePost({ slug: "post-c", title: "Charlie", date: "2024-03-01" }), +]; + +beforeEach(() => { + vi.clearAllMocks(); + mockGetRecords.mockReturnValue(samplePosts); +}); + +// --------------------------------------------------------------------------- +// BlogpostListing +// --------------------------------------------------------------------------- +describe("BlogpostListing", () => { + it("returns paginated listing with defaults (page=1, count=12, sortBy=date_desc)", () => { + const result = BlogpostListing({}); + expect(result).not.toBeNull(); + expect(result!.posts).toHaveLength(3); + expect(result!.pageInfo.currentPage).toBe(1); + expect(result!.pageInfo.recordPerPage).toBe(12); + // date_desc: most recent first + expect(result!.posts[0].slug).toBe("post-c"); + }); + + it("URL search params override props", () => { + const req = new Request("http://localhost/blog?page=2&count=1"); + const result = BlogpostListing({}, req); + expect(result).not.toBeNull(); + expect(result!.pageInfo.currentPage).toBe(2); + expect(result!.posts).toHaveLength(1); + expect(result!.posts[0].slug).toBe("post-b"); // second page of date_desc + }); + + it("computes nextPage / previousPage correctly", () => { + const result = BlogpostListing({ count: 1, page: 2 }); + expect(result).not.toBeNull(); + expect(result!.pageInfo.nextPage).toContain("page=3"); + expect(result!.pageInfo.previousPage).toContain("page=1"); + }); + + it("returns null when no posts match", () => { + mockGetRecords.mockReturnValue([]); + expect(BlogpostListing({})).toBeNull(); + }); + + it("SEO canonical strips query params", () => { + const req = new Request("http://localhost/blog?page=1&count=1"); + const result = BlogpostListing({}, req); + expect(result).not.toBeNull(); + expect(result!.seo.canonical).toBe("http://localhost/blog"); + }); +}); + +// --------------------------------------------------------------------------- +// BlogRelatedPosts +// --------------------------------------------------------------------------- +describe("BlogRelatedPostsLoader", () => { + it("excludes current post via excludePostSlug", () => { + const result = BlogRelatedPostsLoader({ excludePostSlug: "post-a" }); + expect(result).not.toBeNull(); + expect(result!.find((p) => p.slug === "post-a")).toBeUndefined(); + }); + + it("returns BlogPost[] (not BlogPostListingPage)", () => { + const result = BlogRelatedPostsLoader({}); + expect(Array.isArray(result)).toBe(true); + }); + + it("returns null when empty", () => { + mockGetRecords.mockReturnValue([]); + expect(BlogRelatedPostsLoader({})).toBeNull(); + }); +}); + +// --------------------------------------------------------------------------- +// BlogPostPage +// --------------------------------------------------------------------------- +describe("BlogPostPageLoader", () => { + it("returns BlogPostPage with correct @type", () => { + const result = BlogPostPageLoader({ slug: "post-a" }); + expect(result).not.toBeNull(); + expect(result!["@type"]).toBe("BlogPostPage"); + expect(result!.post.slug).toBe("post-a"); + }); + + it("returns null when post not found", () => { + expect(BlogPostPageLoader({ slug: "nonexistent" })).toBeNull(); + }); + + it("SEO fields fall back to post fields", () => { + mockGetRecords.mockReturnValue([ + makePost({ + slug: "no-seo", + title: "Fallback Title", + excerpt: "Fallback Desc", + image: "img.png", + seo: undefined, + }), + ]); + + const result = BlogPostPageLoader({ slug: "no-seo" }); + expect(result).not.toBeNull(); + expect(result!.seo?.title).toBe("Fallback Title"); + expect(result!.seo?.description).toBe("Fallback Desc"); + expect(result!.seo?.image).toBe("img.png"); + }); + + it("uses SEO fields when present", () => { + mockGetRecords.mockReturnValue([ + makePost({ + slug: "has-seo", + title: "Post Title", + seo: { title: "SEO Title", description: "SEO Desc" }, + }), + ]); + + const result = BlogPostPageLoader({ slug: "has-seo" }); + expect(result!.seo?.title).toBe("SEO Title"); + expect(result!.seo?.description).toBe("SEO Desc"); + }); +}); + +// --------------------------------------------------------------------------- +// GetCategories +// --------------------------------------------------------------------------- +describe("GetCategories", () => { + const categories: Category[] = [ + { name: "Beta", slug: "beta" }, + { name: "Alpha", slug: "alpha" }, + { name: "Charlie", slug: "charlie" }, + ]; + + beforeEach(() => { + mockGetRecords.mockReturnValue([...categories]); + }); + + it("sorts by name (title_desc default)", () => { + const result = GetCategories({}); + expect(result).not.toBeNull(); + expect(result!.map((c) => c.name)).toEqual(["Alpha", "Beta", "Charlie"]); + }); + + it("filters by slug when provided", () => { + const result = GetCategories({ slug: "alpha" }); + expect(result).toHaveLength(1); + expect(result![0].slug).toBe("alpha"); + }); + + it("slices by count", () => { + const result = GetCategories({ count: 2 }); + expect(result).toHaveLength(2); + }); + + it("returns null when no categories", () => { + mockGetRecords.mockReturnValue([]); + expect(GetCategories({})).toBeNull(); + }); +}); + +// --------------------------------------------------------------------------- +// BlogPostItem +// --------------------------------------------------------------------------- +describe("BlogPostItem", () => { + it("returns post by slug", () => { + const result = BlogPostItem({ slug: "post-b" }); + expect(result).not.toBeNull(); + expect(result!.slug).toBe("post-b"); + }); + + it("returns null when no slug provided", () => { + expect(BlogPostItem({ slug: "" })).toBeNull(); + }); + + it("returns null when post not found", () => { + expect(BlogPostItem({ slug: "nonexistent" })).toBeNull(); + }); +}); diff --git a/blog/__tests__/mod.test.ts b/blog/__tests__/mod.test.ts new file mode 100644 index 0000000..5eed596 --- /dev/null +++ b/blog/__tests__/mod.test.ts @@ -0,0 +1,10 @@ +import { configure } from "../mod"; + +describe("blog module", () => { + it("returns AppDefinition with name 'blog' and manifest", async () => { + const app = await configure({}, async () => undefined); + expect(app.name).toBe("blog"); + expect(app.manifest).toBeDefined(); + expect(app.state).toEqual({}); + }); +}); diff --git a/blog/__tests__/records.test.ts b/blog/__tests__/records.test.ts new file mode 100644 index 0000000..416f648 --- /dev/null +++ b/blog/__tests__/records.test.ts @@ -0,0 +1,92 @@ +import { vi } from "vitest"; + +vi.mock("@decocms/start/cms", () => ({ + loadBlocks: vi.fn(), +})); + +import { loadBlocks } from "@decocms/start/cms"; +import { getRecordsByPath } from "../core/records"; + +const mockLoadBlocks = loadBlocks as ReturnType; + +beforeEach(() => { + vi.clearAllMocks(); +}); + +describe("getRecordsByPath", () => { + it("extracts records matching path prefix", () => { + mockLoadBlocks.mockReturnValue({ + "collections/blog/posts/hello": { + name: "collections/blog/posts/hello", + post: { title: "Hello", slug: "hello" }, + }, + "collections/blog/posts/world": { + name: "collections/blog/posts/world", + post: { title: "World", slug: "world" }, + }, + }); + + const result = getRecordsByPath("collections/blog/posts", "post"); + expect(result).toHaveLength(2); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ title: "Hello", slug: "hello" }), + expect.objectContaining({ title: "World", slug: "world" }), + ]), + ); + }); + + it("skips non-object blocks", () => { + mockLoadBlocks.mockReturnValue({ + "collections/blog/posts/a": "not-an-object", + "collections/blog/posts/b": null, + "collections/blog/posts/c": { + name: "collections/blog/posts/c", + post: { title: "C" }, + }, + }); + + const result = getRecordsByPath("collections/blog/posts", "post"); + expect(result).toHaveLength(1); + expect(result[0]).toEqual(expect.objectContaining({ title: "C" })); + }); + + it("skips blocks without the accessor field", () => { + mockLoadBlocks.mockReturnValue({ + "collections/blog/posts/x": { + name: "collections/blog/posts/x", + other: { title: "X" }, + }, + }); + + const result = getRecordsByPath("collections/blog/posts", "post"); + expect(result).toEqual([]); + }); + + it("derives id from block name", () => { + mockLoadBlocks.mockReturnValue({ + "collections/blog/posts/my-post": { + name: "collections/blog/posts/my-post", + post: { title: "My Post" }, + }, + }); + + const result = getRecordsByPath<{ title: string; id?: string }>( + "collections/blog/posts", + "post", + ); + expect(result[0].id).toBe("my-post"); + }); + + it("returns empty array when no blocks match", () => { + mockLoadBlocks.mockReturnValue({ + "collections/blog/categories/cat": { + name: "collections/blog/categories/cat", + category: { name: "Cat" }, + }, + }); + + const result = getRecordsByPath("collections/blog/posts", "post"); + expect(result).toEqual([]); + }); +}); diff --git a/blog/core/handlePosts.ts b/blog/core/handlePosts.ts new file mode 100644 index 0000000..2e2faa9 --- /dev/null +++ b/blog/core/handlePosts.ts @@ -0,0 +1,88 @@ +import type { BlogPost, SortBy } from "../types"; + +const VALID_SORT_ORDERS = ["asc", "desc"]; + +/** + * Sort posts by the given criteria. + * Skips view-based sorting (no Drizzle in this port). + */ +export const sortPosts = (blogPosts: BlogPost[], sortBy: SortBy): BlogPost[] => { + const parts = sortBy.split("_"); + const sortMethod = (parts[0] in blogPosts[0] ? parts[0] : "date") as keyof BlogPost; + const sortOrder = VALID_SORT_ORDERS.includes(parts[1]) ? parts[1] : "desc"; + + return blogPosts.toSorted((a, b) => { + if (!a[sortMethod] && !b[sortMethod]) return 0; + if (!a[sortMethod]) return 1; + if (!b[sortMethod]) return -1; + + const comparison = + sortMethod === "date" + ? new Date(`${b.date}T00:00:00`).getTime() - new Date(`${a.date}T00:00:00`).getTime() + : (a[sortMethod]?.toString().localeCompare(b[sortMethod]?.toString() ?? "") ?? 0); + + return sortOrder === "desc" ? comparison : -comparison; + }); +}; + +/** Filter posts by a single category slug. */ +export const filterPostsByCategory = (posts: BlogPost[], slug?: string): BlogPost[] => + slug ? posts.filter(({ categories }) => categories?.find((c) => c.slug === slug)) : posts; + +/** Filter posts whose slug is in the given list. */ +export const filterPostsBySlugs = (posts: BlogPost[], postSlugs: string[]): BlogPost[] => + posts.filter(({ slug }) => postSlugs.includes(slug)); + +/** Filter posts matching a search term (title, excerpt, content). */ +export const filterPostsByTerm = (posts: BlogPost[], term: string): BlogPost[] => + posts.filter(({ content, excerpt, title }) => + [content, excerpt, title].some((field) => field?.toLowerCase().includes(term.toLowerCase())), + ); + +/** Filter posts whose categories overlap with the given slug array. */ +export const filterRelatedPosts = (posts: BlogPost[], slugs: string[]): BlogPost[] => + posts.filter(({ categories }) => categories?.find((c) => slugs.includes(c.slug))); + +/** Slice posts for pagination. */ +export const slicePosts = ( + posts: BlogPost[], + pageNumber: number, + postsPerPage: number, +): BlogPost[] => { + const startIndex = (pageNumber - 1) * postsPerPage; + return posts.slice(startIndex, startIndex + postsPerPage); +}; + +/** + * Combined filter & sort pipeline (no slice). + */ +export default function handlePosts( + posts: BlogPost[], + sortBy: SortBy, + slug?: string | string[], + postSlugs?: string[], + term?: string, + excludePostSlug?: string, +): BlogPost[] | null { + let filtered: BlogPost[]; + + if (typeof slug === "string") { + filtered = + postSlugs && postSlugs.length > 0 + ? filterPostsBySlugs(posts, postSlugs) + : filterPostsByCategory(posts, slug); + if (term) filtered = filterPostsByTerm(filtered, term); + } else if (Array.isArray(slug)) { + filtered = filterRelatedPosts(posts, slug); + } else { + filtered = term ? filterPostsByTerm(posts, term) : posts; + } + + if (excludePostSlug) { + filtered = filtered.filter(({ slug: s }) => s !== excludePostSlug); + } + + if (!filtered || filtered.length === 0) return null; + + return sortPosts(filtered, sortBy); +} diff --git a/blog/core/records.ts b/blog/core/records.ts new file mode 100644 index 0000000..874344f --- /dev/null +++ b/blog/core/records.ts @@ -0,0 +1,30 @@ +import { loadBlocks } from "@decocms/start/cms"; + +/** + * Retrieve records from CMS blocks by path prefix. + * + * Scans the decofile blocks whose key starts with `path` and extracts the + * nested value at `accessor` from each matching block. + * + * Equivalent to the Deno `getRecordsByPath(ctx, path, accessor)` but uses + * `loadBlocks()` from `@decocms/start/cms` instead of `ctx.get(resolvables)`. + */ +export function getRecordsByPath(path: string, accessor: string): T[] { + const blocks = loadBlocks() as Record>; + const results: T[] = []; + + for (const [key, value] of Object.entries(blocks)) { + if (!key.startsWith(path) || !value || typeof value !== "object") { + continue; + } + + const record = value[accessor] as T | undefined; + if (!record) continue; + + const id = (value.name as string | undefined)?.split(path)[1]?.replace("/", ""); + + results.push({ ...record, id } as T); + } + + return results; +} diff --git a/blog/index.ts b/blog/index.ts new file mode 100644 index 0000000..9a3e167 --- /dev/null +++ b/blog/index.ts @@ -0,0 +1,24 @@ +/** + * Public API for the blog app. + */ + +export { getRecordsByPath } from "./core/records"; +/** @deprecated Use `createBlogLoaders` instead. */ +export { + createBlogLoaders, + createBlogLoaders as createBlogCommerceLoaders, +} from "./loaderMap"; +export { configure } from "./mod"; + +// Types +export type { + Author, + BlogPost, + BlogPostListingPage, + BlogPostPage, + Category, + ExtraProps, + PageInfo, + Seo, + SortBy, +} from "./types"; diff --git a/blog/loaderMap.ts b/blog/loaderMap.ts new file mode 100644 index 0000000..bf24604 --- /dev/null +++ b/blog/loaderMap.ts @@ -0,0 +1,57 @@ +/** + * Blog loader map factory for CMS block resolution. + * + * Returns a `Record` that the site spreads into its + * block loader registry. + */ + +import AuthorLoader from "./loaders/Author"; +import BlogPostItemLoader from "./loaders/BlogPostItem"; +import BlogPostPageLoader from "./loaders/BlogPostPage"; +import BlogpostLoader from "./loaders/Blogpost"; +import BlogpostListingLoader from "./loaders/BlogpostListing"; +import BlogRelatedPostsLoader from "./loaders/BlogRelatedPosts"; +import CategoryLoader from "./loaders/Category"; +import GetCategoriesLoader from "./loaders/GetCategories"; + +// biome-ignore lint/suspicious/noExplicitAny: loader props/returns vary per block +export type LoaderFn = (props: any, request?: Request) => Promise | any; + +/** + * Create the blog loader map. + * + * @example + * ```ts + * import { createBlogLoaders } from "@decocms/apps/blog"; + * + * const COMMERCE_LOADERS = { + * ...createVtexCommerceLoaders(), + * ...createBlogLoaders(), + * }; + * ``` + */ +export function createBlogLoaders(): Record { + return { + // Loader keys match the Deno app's __resolveType paths + "blog/loaders/BlogPostPage.ts": BlogPostPageLoader, + "blog/loaders/BlogPostPage": BlogPostPageLoader, + "blog/loaders/BlogpostListing.ts": BlogpostListingLoader, + "blog/loaders/BlogpostListing": BlogpostListingLoader, + "blog/loaders/BlogRelatedPosts.ts": BlogRelatedPostsLoader, + "blog/loaders/BlogRelatedPosts": BlogRelatedPostsLoader, + "blog/loaders/GetCategories.ts": GetCategoriesLoader, + "blog/loaders/GetCategories": GetCategoriesLoader, + "blog/loaders/Blogpost.ts": BlogpostLoader, + "blog/loaders/Blogpost": BlogpostLoader, + "blog/loaders/Category.ts": CategoryLoader, + "blog/loaders/Category": CategoryLoader, + "blog/loaders/Author.ts": AuthorLoader, + "blog/loaders/Author": AuthorLoader, + + // BlogPostItem: looks up a single post by slug, returns BlogPost + "blog/loaders/BlogPostItem.ts": BlogPostItemLoader, + "blog/loaders/BlogPostItem": BlogPostItemLoader, + "blog/loaders/BlogpostList.ts": BlogpostListingLoader, + "blog/loaders/BlogpostList": BlogpostListingLoader, + }; +} diff --git a/blog/loaders/Author.ts b/blog/loaders/Author.ts new file mode 100644 index 0000000..d77d24c --- /dev/null +++ b/blog/loaders/Author.ts @@ -0,0 +1,9 @@ +import type { Author } from "../types"; + +/** + * @title Author + * @description Defines a blog post author. + */ +const loader = ({ author }: { author: Author }): Author => author; + +export default loader; diff --git a/blog/loaders/BlogPostItem.ts b/blog/loaders/BlogPostItem.ts new file mode 100644 index 0000000..b258f1f --- /dev/null +++ b/blog/loaders/BlogPostItem.ts @@ -0,0 +1,19 @@ +import { getRecordsByPath } from "../core/records"; +import type { BlogPost } from "../types"; + +export interface Props { + slug: string; +} + +/** + * @title BlogPostItem + * @description Fetches a single blog post by slug. Returns the BlogPost + * directly (not wrapped in BlogPostPage). + */ +export default function BlogPostItem(props: Props & { __pageUrl?: string }): BlogPost | null { + const { slug } = props; + if (!slug) return null; + + const posts = getRecordsByPath("collections/blog/posts", "post"); + return posts.find((p) => p?.slug === slug) ?? null; +} diff --git a/blog/loaders/BlogPostPage.ts b/blog/loaders/BlogPostPage.ts new file mode 100644 index 0000000..a29e84b --- /dev/null +++ b/blog/loaders/BlogPostPage.ts @@ -0,0 +1,39 @@ +import { getRecordsByPath } from "../core/records"; +import type { BlogPost, BlogPostPage } from "../types"; + +const COLLECTION_PATH = "collections/blog/posts"; +const ACCESSOR = "post"; + +export interface Props { + slug: string; +} + +/** + * @title BlogPostPage + * @description Fetches a specific blog post page by its slug. + */ +export default function BlogPostPageLoader( + props: Props & { __pageUrl?: string }, + req?: Request, +): BlogPostPage | null { + const { slug } = props; + const posts = getRecordsByPath(COLLECTION_PATH, ACCESSOR); + + const rawUrl = req?.url ?? props.__pageUrl ?? "http://localhost/"; + const url = new URL(rawUrl); + const post = posts.find((p) => p?.slug === slug); + + if (!post) return null; + + return { + "@type": "BlogPostPage", + post, + seo: { + title: post?.seo?.title || post?.title, + description: post?.seo?.description || post?.excerpt, + canonical: post?.seo?.canonical || url.href, + image: post?.seo?.image || post?.image, + noIndexing: post?.seo?.noIndexing || false, + }, + }; +} diff --git a/blog/loaders/BlogRelatedPosts.ts b/blog/loaders/BlogRelatedPosts.ts new file mode 100644 index 0000000..358db47 --- /dev/null +++ b/blog/loaders/BlogRelatedPosts.ts @@ -0,0 +1,66 @@ +import handlePosts, { slicePosts } from "../core/handlePosts"; +import { getRecordsByPath } from "../core/records"; +import type { BlogPost, SortBy } from "../types"; + +const COLLECTION_PATH = "collections/blog/posts"; +const ACCESSOR = "post"; + +export interface Props { + /** + * @title Items per page + * @description Number of posts per page to display. + */ + count?: number; + /** + * @title Page query parameter + * @description The current page number. Defaults to 1. + */ + page?: number; + /** + * @title Category Slug + * @description Filter by a specific category slug. + */ + slug?: string | string[]; + /** + * @title Page sorting parameter + * @description The sorting option. Default is "date_desc" + */ + sortBy?: SortBy; + /** + * @description Overrides the query term at url + */ + query?: string; + /** + * @title Exclude Post Slug + * @description Excludes a post slug from the list + */ + excludePostSlug?: string; +} + +export type BlogRelatedPosts = BlogPost[] | null; + +/** + * @title BlogRelatedPosts + * @description Retrieves a list of blog related posts. + */ +export default function BlogRelatedPostsLoader( + props: Props & { __pageUrl?: string }, + req?: Request, +): BlogRelatedPosts { + const { page, count, slug, sortBy, query, excludePostSlug } = props; + const rawUrl = req?.url ?? props.__pageUrl ?? "http://localhost/"; + const url = new URL(rawUrl); + const postsPerPage = Number(count ?? url.searchParams.get("count") ?? 12); + const pageNumber = Number(page ?? url.searchParams.get("page") ?? 1); + const pageSort = sortBy ?? (url.searchParams.get("sortBy") as SortBy) ?? "date_desc"; + const term = query ?? url.searchParams.get("q") ?? undefined; + + const posts = getRecordsByPath(COLLECTION_PATH, ACCESSOR); + + const handledPosts = handlePosts(posts, pageSort, slug, undefined, term, excludePostSlug); + + if (!handledPosts) return null; + + const slicedPosts = slicePosts(handledPosts, pageNumber, postsPerPage); + return slicedPosts.length > 0 ? slicedPosts : null; +} diff --git a/blog/loaders/Blogpost.ts b/blog/loaders/Blogpost.ts new file mode 100644 index 0000000..ec54703 --- /dev/null +++ b/blog/loaders/Blogpost.ts @@ -0,0 +1,9 @@ +import type { BlogPost } from "../types"; + +/** + * @title Blogpost + * @description Defines a blog post. + */ +const loader = ({ post }: { post: BlogPost }): BlogPost => post; + +export default loader; diff --git a/blog/loaders/BlogpostListing.ts b/blog/loaders/BlogpostListing.ts new file mode 100644 index 0000000..88cef53 --- /dev/null +++ b/blog/loaders/BlogpostListing.ts @@ -0,0 +1,101 @@ +import handlePosts, { slicePosts } from "../core/handlePosts"; +import { getRecordsByPath } from "../core/records"; +import type { BlogPost, BlogPostListingPage, PageInfo, SortBy } from "../types"; + +const COLLECTION_PATH = "collections/blog/posts"; +const ACCESSOR = "post"; + +export interface Props { + /** + * @title Category Slug + * @description Filter by a specific category slug. + */ + slug?: string; + /** + * @title Items per page + * @description Number of posts per page to display. + */ + count?: number; + /** + * @title Page query parameter + * @description The current page number. Defaults to 1. + */ + page?: number; + /** + * @title Page sorting parameter + * @description The sorting option. Default is "date_desc" + */ + sortBy?: SortBy; + /** + * @description Overrides the query term at url + */ + query?: string; +} + +/** + * @title BlogPostList + * @description Retrieves a paginated list of blog posts. + */ +export default function BlogPostList( + props: Props & { __pageUrl?: string }, + req?: Request, +): BlogPostListingPage | null { + const { page, count, slug, sortBy, query } = props; + const rawUrl = req?.url ?? props.__pageUrl ?? "http://localhost/"; + const url = new URL(rawUrl); + const params = url.searchParams; + const postsPerPage = Number(count ?? params.get("count") ?? 12); + const pageNumber = Number(page ?? params.get("page") ?? 1); + const pageSort = sortBy ?? (params.get("sortBy") as SortBy) ?? "date_desc"; + const term = query ?? params.get("q") ?? undefined; + + const posts = getRecordsByPath(COLLECTION_PATH, ACCESSOR); + + try { + const handledPosts = handlePosts(posts, pageSort, slug, undefined, term); + + if (!handledPosts) return null; + + const slicedPosts = slicePosts(handledPosts, pageNumber, postsPerPage); + if (slicedPosts.length === 0) return null; + + const category = slicedPosts[0].categories?.find((c) => c.slug === slug); + + return { + posts: slicedPosts, + pageInfo: toPageInfo(handledPosts, postsPerPage, pageNumber, params), + seo: { + title: category?.name ?? "", + canonical: new URL(url.pathname, url.origin).href, + }, + }; + } catch (e) { + console.error("[BlogpostListing]", e); + return null; + } +} + +function toPageInfo( + posts: BlogPost[], + postsPerPage: number, + pageNumber: number, + params: URLSearchParams, +): PageInfo { + const totalPosts = posts.length; + const totalPages = Math.ceil(totalPosts / postsPerPage); + const hasNextPage = totalPages > pageNumber; + const hasPrevPage = pageNumber > 1; + const nextPage = new URLSearchParams(params); + const previousPage = new URLSearchParams(params); + + if (hasNextPage) nextPage.set("page", (pageNumber + 1).toString()); + if (hasPrevPage) previousPage.set("page", (pageNumber - 1).toString()); + + return { + nextPage: hasNextPage ? `?${nextPage}` : undefined, + previousPage: hasPrevPage ? `?${previousPage}` : undefined, + currentPage: pageNumber, + records: totalPosts, + recordPerPage: postsPerPage, + }; +} diff --git a/blog/loaders/Category.ts b/blog/loaders/Category.ts new file mode 100644 index 0000000..1deec91 --- /dev/null +++ b/blog/loaders/Category.ts @@ -0,0 +1,9 @@ +import type { Category } from "../types"; + +/** + * @title Category + * @description Defines a blog post category. + */ +const loader = ({ category }: { category: Category }): Category => category; + +export default loader; diff --git a/blog/loaders/GetCategories.ts b/blog/loaders/GetCategories.ts new file mode 100644 index 0000000..c26f5b1 --- /dev/null +++ b/blog/loaders/GetCategories.ts @@ -0,0 +1,48 @@ +import { getRecordsByPath } from "../core/records"; +import type { Category } from "../types"; + +const COLLECTION_PATH = "collections/blog/categories"; +const ACCESSOR = "category"; + +export interface Props { + /** + * @title Category Slug + * @description Get the category data from a specific slug. + */ + slug?: string; + /** + * @title Items count + * @description Number of categories to return + */ + count?: number; + /** + * @title Sort + * @description The sorting option. Default is "title_desc" + */ + sortBy?: "title_asc" | "title_desc"; +} + +/** + * @title GetCategories + * @description Retrieves a list of blog categories. + */ +export default function GetCategories({ + count, + slug, + sortBy = "title_desc", +}: Props): Category[] | null { + const categories = getRecordsByPath(COLLECTION_PATH, ACCESSOR); + + if (!categories?.length) return null; + + if (slug) { + return categories.filter((c) => c.slug === slug); + } + + const sortedCategories = categories.sort((a, b) => { + const comparison = a.name.localeCompare(b.name); + return sortBy.endsWith("_desc") ? comparison : -comparison; + }); + + return count ? sortedCategories.slice(0, count) : sortedCategories; +} diff --git a/blog/manifest.gen.ts b/blog/manifest.gen.ts new file mode 100644 index 0000000..4babb56 --- /dev/null +++ b/blog/manifest.gen.ts @@ -0,0 +1,27 @@ +// AUTO-GENERATED by scripts/generate-manifests.ts — DO NOT EDIT +// This file is checked into source control and updated via: npm run generate:manifests +import * as loaders_Author from "./loaders/Author"; +import * as loaders_BlogPostPage from "./loaders/BlogPostPage"; +import * as loaders_Blogpost from "./loaders/Blogpost"; +import * as loaders_BlogpostListing from "./loaders/BlogpostListing"; +import * as loaders_BlogRelatedPosts from "./loaders/BlogRelatedPosts"; +import * as loaders_Category from "./loaders/Category"; +import * as loaders_GetCategories from "./loaders/GetCategories"; + +const manifest = { + name: "blog", + loaders: { + "blog/loaders/Author": loaders_Author, + "blog/loaders/Blogpost": loaders_Blogpost, + "blog/loaders/BlogPostPage": loaders_BlogPostPage, + "blog/loaders/BlogpostListing": loaders_BlogpostListing, + "blog/loaders/BlogRelatedPosts": loaders_BlogRelatedPosts, + "blog/loaders/Category": loaders_Category, + "blog/loaders/GetCategories": loaders_GetCategories, + }, + actions: {}, + sections: {}, +} as const; + +export type Manifest = typeof manifest; +export default manifest; diff --git a/blog/mod.ts b/blog/mod.ts new file mode 100644 index 0000000..f62f1b3 --- /dev/null +++ b/blog/mod.ts @@ -0,0 +1,39 @@ +/** + * Blog app module — standard autoconfig contract. + * + * Exports `configure` following the AppModContract pattern. + * Provides blog post, category, and author loaders for the site. + */ + +import type { AppDefinition, ResolveSecretFn } from "../commerce/app-types"; +import manifest from "./manifest.gen"; + +// ------------------------------------------------------------------------- +// State +// ------------------------------------------------------------------------- + +// biome-ignore lint/complexity/noBannedTypes: empty state placeholder for future use +export type BlogState = {}; + +// ------------------------------------------------------------------------- +// Configure +// ------------------------------------------------------------------------- + +/** + * Configure the Blog app from CMS block data. + * Always returns an AppDefinition (no required fields). + */ +export async function configure( + // biome-ignore lint/suspicious/noExplicitAny: block data comes from CMS with no fixed schema + _block: any, + _resolveSecret: ResolveSecretFn, +): Promise> { + return { + name: "blog", + manifest, + state: {}, + }; +} + +/** Placeholder preview for CMS editor. */ +export const preview = undefined; diff --git a/blog/types.ts b/blog/types.ts new file mode 100644 index 0000000..5ee85fa --- /dev/null +++ b/blog/types.ts @@ -0,0 +1,105 @@ +import type { ImageWidget } from "../website/types"; + +/** + * @titleBy name + * @widget author + */ +export interface Author { + name: string; + email: string; + avatar?: ImageWidget; + jobTitle?: string; + company?: string; +} + +export interface Category { + name: string; + slug: string; +} + +export interface BlogPost { + title: string; + excerpt: string; + /** + * @title Main image + */ + image?: ImageWidget; + /** + * @title Alt text for the image + */ + alt?: string; + /** + * @widget blog + * @collection authors + */ + authors?: Author[]; + /** + * @widget blog + * @collection categories + */ + categories?: Category[]; + /** + * @format date + */ + date: string; + slug: string; + /** + * @title Post Content + * @format rich-text + */ + content?: string; + /** + * @title Sections + * @label hidden + * @changeable true + */ + sections?: unknown[]; + /** + * @title SEO + */ + seo?: Seo; + /** + * @title ReadTime in minutes + */ + readTime?: number; + /** + * @title Extra Props + */ + extraProps?: ExtraProps[]; + id?: string; +} + +export interface ExtraProps { + key: string; + value: string; +} + +export interface Seo { + title?: string; + description?: string; + image?: ImageWidget; + canonical?: string; + noIndexing?: boolean; +} + +export interface BlogPostPage { + "@type": "BlogPostPage"; + post: BlogPost; + seo?: Seo | null; +} + +export type SortBy = "date_desc" | "date_asc" | "title_asc" | "title_desc"; + +export interface PageInfo { + nextPage?: string; + previousPage?: string; + currentPage: number; + records?: number; + recordPerPage?: number; +} + +export interface BlogPostListingPage { + posts: BlogPost[]; + pageInfo: PageInfo; + seo: Seo; +} diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..e50d452 --- /dev/null +++ b/bun.lock @@ -0,0 +1,1564 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "@decocms/apps", + "devDependencies": { + "@biomejs/biome": "^2.4.7", + "@decocms/start": "5.3.0", + "@semantic-release/exec": "^7.1.0", + "@tanstack/react-query": "^5.90.21", + "@types/react": "^19.0.0", + "@vitest/coverage-v8": "^4.1.0", + "algoliasearch": "^5.53.0", + "happy-dom": "^20.9.0", + "knip": "^5.86.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tsx": "^4.21.0", + "typescript": "^5.9.3", + "vitest": "^4.1.0", + }, + "peerDependencies": { + "@decocms/start": ">=5.3.0", + "@tanstack/react-query": ">=5", + "algoliasearch": "^5", + "react": ">=18", + "react-dom": ">=18", + }, + "optionalPeers": [ + "algoliasearch", + ], + }, + }, + "packages": { + "@actions/core": ["@actions/core@3.0.1", "", { "dependencies": { "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0" } }, "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA=="], + + "@actions/exec": ["@actions/exec@3.0.0", "", { "dependencies": { "@actions/io": "^3.0.2" } }, "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw=="], + + "@actions/http-client": ["@actions/http-client@4.0.1", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^6.23.0" } }, "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg=="], + + "@actions/io": ["@actions/io@3.0.2", "", {}, "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw=="], + + "@algolia/abtesting": ["@algolia/abtesting@1.19.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-Lhnez3hhXHk25lfxLAMxvkP4fmN3+1RgADhD2ssMDBYuAsDVReeyP+3SGRx+ntq8ijMrLqUyfvO72TB6jsTteQ=="], + + "@algolia/client-abtesting": ["@algolia/client-abtesting@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-0ZjA5Hcmaoz5Lj6OG0zhfIyeqzJZnLW2CRJA1W17UwMFGRtZAJ9yJKRvPEDA6gkpsIoQxORTSW6sWFiuYncPNQ=="], + + "@algolia/client-analytics": ["@algolia/client-analytics@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-kWNodP75iiEaOtemC9F/hlxNBG5E2QUjN1BusnE6m2b4l7Qh/BUO3fGCVsmKJI65VO4VKGGmT43ICvHtTcJ2JQ=="], + + "@algolia/client-common": ["@algolia/client-common@5.53.0", "", {}, "sha512-YPN45TXD9Wrse185t/Ta7nktZsqpv97oOjCzp2sblHnCL6rBc9TDeJAg1IGl2UpdwnSD05Zu/5wLB4watOUMyg=="], + + "@algolia/client-insights": ["@algolia/client-insights@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-qAcYTDJE6m924FDDUQvdD6vh7DYaqOeSpFS74IP37/JRV0v4cGBauyxTF2WzDnokUylQDbqreoFIJZfg0Fitmw=="], + + "@algolia/client-personalization": ["@algolia/client-personalization@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-fQaY+DkSJOpuUVUe8MQTwrdiKAqkJGhpDarB08duBn/sUv7Bkib6MDRQauCcWTWTe4HIW+EbwQP9R4kci1V/Yw=="], + + "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-o72tsiEZGfeS/dxL9IADfzcZWGEwKDEe5CvtrBuT//3JR+SHuTtHRI2ZTf7D7bcKagcbojvO8hnkHdfoakSlYg=="], + + "@algolia/client-search": ["@algolia/client-search@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-Ds16IyPm/dNJPCU8OzApo2gwGrgWT5BYHhE3NFwZbpCveqyvPDB9sZDDkJ5DsdOGT2aC+R3i0/M1OVXF2qdgPg=="], + + "@algolia/ingestion": ["@algolia/ingestion@1.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-oNbT6z4NwD8Pou9VPINGlN/tlG1afESh2EbxqnP6rwl95xKVD/Zlciis1PpNeO/9U/rrajc1+7DcfKi03tX1KQ=="], + + "@algolia/monitoring": ["@algolia/monitoring@1.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-G+KZb/yd+qAOFn/cEvTGeLxQm8aP3a0od50l3z/ylccY+/o4YG3TNcjU1tFQHW4mXC137GPyR7W70R0kRQDLnA=="], + + "@algolia/recommend": ["@algolia/recommend@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-6aVfYd55Un6IUgPLbo84WfgFZlS3L0vA1ttzXL5vahHewUJ8jYgd89TzlWRTeej7w70mb9RWsVlFYGmJ/diQww=="], + + "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0" } }, "sha512-ke27DqgzCOlt+RbeEdCxtXxMQOnAOi8ujr2wid0DmDKzR95Kw/f9sBsuhBxtjevCqJRJszfRTLY0B1pbO6IhkA=="], + + "@algolia/requester-fetch": ["@algolia/requester-fetch@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0" } }, "sha512-GngiOqt2Gq4oLno6yXQVj9om+qSO9SWAoduoTOEg79dKZ62brB8OOIvSJG/vDNoanYi6a7Al9uDZwXvi+bcVTg=="], + + "@algolia/requester-node-http": ["@algolia/requester-node-http@5.53.0", "", { "dependencies": { "@algolia/client-common": "5.53.0" } }, "sha512-6mF9LZMUk0QqWvrnxkxBqhswwz6Xfiwy6/gmTzL5HrlhdVG3ITAqGV2k3XmVThP1h0Ulc3VQwiNCD7/Nr4JNlQ=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.3", "", {}, "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], + + "@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="], + + "@biomejs/biome": ["@biomejs/biome@2.4.15", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.15", "@biomejs/cli-darwin-x64": "2.4.15", "@biomejs/cli-linux-arm64": "2.4.15", "@biomejs/cli-linux-arm64-musl": "2.4.15", "@biomejs/cli-linux-x64": "2.4.15", "@biomejs/cli-linux-x64-musl": "2.4.15", "@biomejs/cli-win32-arm64": "2.4.15", "@biomejs/cli-win32-x64": "2.4.15" }, "bin": { "biome": "bin/biome" } }, "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.15", "", { "os": "linux", "cpu": "x64" }, "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.15", "", { "os": "linux", "cpu": "x64" }, "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.15", "", { "os": "win32", "cpu": "x64" }, "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ=="], + + "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], + + "@deco-cx/warp-node": ["@deco-cx/warp-node@0.3.20", "", { "dependencies": { "undici": "^6.21.0", "ws": "^8.18.0" } }, "sha512-rdRWrT5eMhu1zhAzliRkoQCUr2j6Dg9npUKoP4uP+rV9wIbYKSmXJbM2z/fOiy5FVvzQlpvY16ACNRIRz+UWqw=="], + + "@decocms/start": ["@decocms/start@5.3.0", "", { "dependencies": { "@deco-cx/warp-node": "^0.3.16", "@opentelemetry/api": "^1.9.1", "clsx": "^2.1.1", "fast-json-patch": "^3.1.0", "tailwind-merge": "^3.3.1", "tsx": "^4.19.0", "ws": "^8.18.0" }, "peerDependencies": { "@tanstack/react-query": ">=5.0.0", "@tanstack/react-start": ">=1.0.0", "@tanstack/store": ">=0.7.0", "react": "^19.0.0", "react-dom": "^19.0.0", "vite": ">=6.0.0 || >=7.0.0 || >=8.0.0" }, "bin": { "deco-migrate": "scripts/migrate.ts", "deco-post-cleanup": "scripts/migrate-post-cleanup.ts", "deco-htmx-analyze": "scripts/htmx-analyze.ts", "deco-cf-observability": "scripts/migrate-to-cf-observability.ts", "deco-audit-observability": "scripts/audit-observability-config.ts" } }, "sha512-98FH8wHClYDHZQDtnaKWTA2AIn5gKl29sIIqEDAB4MqHX0FbV5fHsetG0aYKjdWBUrxln/GZ9nzckgibdUVz9w=="], + + "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.0", "", { "os": "android", "cpu": "arm" }, "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.0", "", { "os": "android", "cpu": "arm64" }, "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.0", "", { "os": "android", "cpu": "x64" }, "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.0", "", { "os": "linux", "cpu": "x64" }, "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.0", "", { "os": "none", "cpu": "x64" }, "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.0", "", { "os": "win32", "cpu": "x64" }, "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], + + "@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="], + + "@octokit/endpoint": ["@octokit/endpoint@11.0.3", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag=="], + + "@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="], + + "@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@14.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw=="], + + "@octokit/plugin-retry": ["@octokit/plugin-retry@8.1.0", "", { "dependencies": { "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": ">=7" } }, "sha512-O1FZgXeiGb2sowEr/hYTr6YunGdSAFWnr2fyW39Ah85H8O33ELASQxcvOFF5LE6Tjekcyu2ms4qAzJVhSaJxTw=="], + + "@octokit/plugin-throttling": ["@octokit/plugin-throttling@11.0.3", "", { "dependencies": { "@octokit/types": "^16.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^7.0.0" } }, "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg=="], + + "@octokit/request": ["@octokit/request@10.0.9", "", { "dependencies": { "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "content-type": "^2.0.0", "fast-content-type-parse": "^3.0.0", "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" } }, "sha512-o8Bi3f608eyM+7BmBiUWxFsdjLb3/ym1cQek5LZOv9KkZcxRrHCPhhRzm6xjO6HVZ85ItD6+sTsjxo821SVa/A=="], + + "@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + + "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], + + "@oozcitak/dom": ["@oozcitak/dom@2.0.2", "", { "dependencies": { "@oozcitak/infra": "^2.0.2", "@oozcitak/url": "^3.0.0", "@oozcitak/util": "^10.0.0" } }, "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w=="], + + "@oozcitak/infra": ["@oozcitak/infra@2.0.2", "", { "dependencies": { "@oozcitak/util": "^10.0.0" } }, "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA=="], + + "@oozcitak/url": ["@oozcitak/url@3.0.0", "", { "dependencies": { "@oozcitak/infra": "^2.0.2", "@oozcitak/util": "^10.0.0" } }, "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ=="], + + "@oozcitak/util": ["@oozcitak/util@10.0.0", "", {}, "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA=="], + + "@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="], + + "@oxc-project/types": ["@oxc-project/types@0.130.0", "", {}, "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q=="], + + "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="], + + "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.19.1", "", { "os": "android", "cpu": "arm64" }, "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA=="], + + "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.19.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ=="], + + "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.19.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ=="], + + "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.19.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw=="], + + "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A=="], + + "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ=="], + + "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig=="], + + "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew=="], + + "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.19.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ=="], + + "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w=="], + + "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw=="], + + "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.19.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA=="], + + "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ=="], + + "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw=="], + + "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.19.1", "", { "os": "none", "cpu": "arm64" }, "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA=="], + + "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.19.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg=="], + + "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.19.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ=="], + + "@oxc-resolver/binding-win32-ia32-msvc": ["@oxc-resolver/binding-win32-ia32-msvc@11.19.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA=="], + + "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.19.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw=="], + + "@pnpm/config.env-replace": ["@pnpm/config.env-replace@1.1.0", "", {}, "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="], + + "@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="], + + "@pnpm/npm-conf": ["@pnpm/npm-conf@3.0.2", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA=="], + + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.1", "", { "os": "android", "cpu": "arm64" }, "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg=="], + + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg=="], + + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg=="], + + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw=="], + + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ=="], + + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A=="], + + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg=="], + + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg=="], + + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ=="], + + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw=="], + + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ=="], + + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.1", "", { "os": "none", "cpu": "arm64" }, "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ=="], + + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.1", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ=="], + + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw=="], + + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.1", "", { "os": "win32", "cpu": "x64" }, "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.40", "", {}, "sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w=="], + + "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], + + "@semantic-release/commit-analyzer": ["@semantic-release/commit-analyzer@13.0.1", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "micromatch": "^4.0.2" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ=="], + + "@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="], + + "@semantic-release/exec": ["@semantic-release/exec@7.1.0", "", { "dependencies": { "@semantic-release/error": "^4.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "execa": "^9.0.0", "lodash-es": "^4.17.21", "parse-json": "^8.0.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" } }, "sha512-4ycZ2atgEUutspPZ2hxO6z8JoQt4+y/kkHvfZ1cZxgl9WKJId1xPj+UadwInj+gMn2Gsv+fLnbrZ4s+6tK2TFQ=="], + + "@semantic-release/github": ["@semantic-release/github@12.0.8", "", { "dependencies": { "@octokit/core": "^7.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-retry": "^8.0.0", "@octokit/plugin-throttling": "^11.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "debug": "^4.3.4", "dir-glob": "^3.0.1", "http-proxy-agent": "^9.0.0", "https-proxy-agent": "^9.0.0", "issue-parser": "^7.0.0", "lodash-es": "^4.17.21", "mime": "^4.0.0", "p-filter": "^4.0.0", "tinyglobby": "^0.2.14", "undici": "^7.0.0", "url-join": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" } }, "sha512-tej5AAgK5X9wHRoDmYhecMXEHEkFeGOY1XsEblKxu8pIQwahzf1STYyr7iPU6Lpbg6C5I3N2w/ocXrBo+L7jhw=="], + + "@semantic-release/npm": ["@semantic-release/npm@13.1.5", "", { "dependencies": { "@actions/core": "^3.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "env-ci": "^11.2.0", "execa": "^9.0.0", "fs-extra": "^11.0.0", "lodash-es": "^4.17.21", "nerf-dart": "^1.0.0", "normalize-url": "^9.0.0", "npm": "^11.6.2", "rc": "^1.2.8", "read-pkg": "^10.0.0", "registry-auth-token": "^5.0.0", "semver": "^7.1.2", "tempy": "^3.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-Hq5UxzoatN3LHiq2rTsWS54nCdqJHlsssGERCo8WlvdfFA9LoN0vO+OuKVSjtNapIc/S8C2LBj206wKLHg62mg=="], + + "@semantic-release/release-notes-generator": ["@semantic-release/release-notes-generator@14.1.1", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "read-package-up": "^11.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-Pbd2e2XRMUD0OxehHpgd5/YghsE76cddkRHSoDvKLK+OCy4Ewxn49rWR631MEUU01lgwF/uyVXvbnVuu6+Z6VA=="], + + "@simple-libs/stream-utils": ["@simple-libs/stream-utils@1.2.0", "", {}, "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA=="], + + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + + "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@tanstack/history": ["@tanstack/history@1.162.0", "", {}, "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA=="], + + "@tanstack/query-core": ["@tanstack/query-core@5.100.11", "", {}, "sha512-lmE0994apShXPj8CUxgx4ch5yUJhE9k/+tVwihBvPOyerACWdBocfFg24t8+0RhtlTd7tEgchDkhlCxNssvDxw=="], + + "@tanstack/react-query": ["@tanstack/react-query@5.100.11", "", { "dependencies": { "@tanstack/query-core": "5.100.11" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-J0f9s5x3LE1450nNNfYx+e/n0DMa0uOBdFJUy5r0RvmsXd4nB/n0rbHtHI1vYXhikNFan+wf51p6Tmp4c8ucrg=="], + + "@tanstack/react-router": ["@tanstack/react-router@1.170.4", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.2", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-cusL4YCTuGGJhjfsXEBm6/SmOAs/G8wRVNadeyN3ofu4OZwX69KAybBEf217buxYzI+FohdJVoigEpJV+tGzIw=="], + + "@tanstack/react-start": ["@tanstack/react-start@1.168.6", "", { "dependencies": { "@tanstack/react-router": "1.170.4", "@tanstack/react-start-client": "1.167.4", "@tanstack/react-start-rsc": "0.1.6", "@tanstack/react-start-server": "1.167.4", "@tanstack/router-utils": "1.162.0", "@tanstack/start-client-core": "1.169.4", "@tanstack/start-plugin-core": "1.170.6", "@tanstack/start-server-core": "1.168.4", "pathe": "^2.0.3" }, "peerDependencies": { "@rsbuild/core": "^2.0.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0", "vite": ">=7.0.0" }, "optionalPeers": ["@rsbuild/core", "vite"] }, "sha512-0/vMhec98zdBvcagQB3NKuz4jZX3Z/djOXjpMLeQclYMRWqbj5XA0WBAFLCuA8p84eUoP8yiUkEDH1OUfIYf7A=="], + + "@tanstack/react-start-client": ["@tanstack/react-start-client@1.167.4", "", { "dependencies": { "@tanstack/react-router": "1.170.4", "@tanstack/router-core": "1.171.2", "@tanstack/start-client-core": "1.169.4" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-HYr9kbEuXjoqEVhmkuIXK9ckfrx08nHCPQ+PQbZlwHd01wghljcBsdAe/8/xujiKnbihC05owBDmXQoE3v27bQ=="], + + "@tanstack/react-start-rsc": ["@tanstack/react-start-rsc@0.1.6", "", { "dependencies": { "@tanstack/react-router": "1.170.4", "@tanstack/react-start-server": "1.167.4", "@tanstack/router-core": "1.171.2", "@tanstack/router-utils": "1.162.0", "@tanstack/start-client-core": "1.169.4", "@tanstack/start-fn-stubs": "1.162.0", "@tanstack/start-plugin-core": "1.170.6", "@tanstack/start-server-core": "1.168.4", "@tanstack/start-storage-context": "1.167.4", "pathe": "^2.0.3" }, "peerDependencies": { "@rspack/core": ">=2.0.0-0", "@vitejs/plugin-rsc": ">=0.5.20", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0", "react-server-dom-rspack": ">=0.0.2" }, "optionalPeers": ["@rspack/core", "@vitejs/plugin-rsc", "react-server-dom-rspack"] }, "sha512-EIP5Vnc4quTZm5rhhkHAqANHGaXRks+S3FomGMHcN7noTJ3OZviifJXc1nN8pYSFeP8NQ2Sqrkn1Kr/87iWXWA=="], + + "@tanstack/react-start-server": ["@tanstack/react-start-server@1.167.4", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-router": "1.170.4", "@tanstack/router-core": "1.171.2", "@tanstack/start-client-core": "1.169.4", "@tanstack/start-server-core": "1.168.4" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-FckuV/6uQQqycU8ufTtxyQiY4hL3bGn23kq/XFsJVXWtpflY6LAtfOi23CoRL4G8eTVvUa2+WGReZhivwNGZiw=="], + + "@tanstack/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="], + + "@tanstack/router-core": ["@tanstack/router-core@1.171.2", "", { "dependencies": { "@tanstack/history": "1.162.0", "cookie-es": "^3.0.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4" } }, "sha512-sUd+BhGYkBF64LVhmOHnYsc1AutPNch/huohEXiXL4IUgmk17Gy+RkUazvjQhptVdYW5QT+qtATrUr2cQZNHFA=="], + + "@tanstack/router-generator": ["@tanstack/router-generator@1.167.5", "", { "dependencies": { "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.2", "@tanstack/router-utils": "1.162.0", "@tanstack/virtual-file-routes": "1.162.0", "jiti": "^2.7.0", "magic-string": "^0.30.21", "prettier": "^3.5.0", "zod": "^3.24.2" } }, "sha512-S7h9qs7WjwF1IlMiOxSv+xB/bSOQ6QS84NlApM9iWLVdkbOVUn7RzTaCqw2qdDa5cPrfSiZJ2wK2a6RFDmFubA=="], + + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.168.6", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.2", "@tanstack/router-generator": "1.167.5", "@tanstack/router-utils": "1.162.0", "@tanstack/virtual-file-routes": "1.162.0", "chokidar": "^3.6.0", "unplugin": "^3.0.0", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2 || ^2.0.0", "@tanstack/react-router": "^1.170.4", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-u5CNtTWGyFvV8gGWKBt9LdwVGg+ISSBXG/aeeU1/d1YpEKPqlJHS6oN3tvNKOScubeV64HjpeV0tD6fqRfCpvw=="], + + "@tanstack/router-utils": ["@tanstack/router-utils@1.162.0", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "ansis": "^4.1.0", "babel-dead-code-elimination": "^1.0.12", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-c3GhqhBRCP636B41nf3TKvVz8EWzC5PTZ3I4J4LDH2tVjpxbyFNYsQKRtbNWiMFl+GTtgK4nCha346Wv7j4hcQ=="], + + "@tanstack/start-client-core": ["@tanstack/start-client-core@1.169.4", "", { "dependencies": { "@tanstack/router-core": "1.171.2", "@tanstack/start-fn-stubs": "1.162.0", "@tanstack/start-storage-context": "1.167.4", "seroval": "^1.5.4" } }, "sha512-2UZ1hLCY80eXkYjRLYASLiJqDXfmlCE3kUknNARgZr7232TMk4ADPDMCp2l506zLXTLKAnI+Wu4jXL2CEadUxQ=="], + + "@tanstack/start-fn-stubs": ["@tanstack/start-fn-stubs@1.162.0", "", {}, "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ=="], + + "@tanstack/start-plugin-core": ["@tanstack/start-plugin-core@1.170.6", "", { "dependencies": { "@babel/code-frame": "7.27.1", "@babel/core": "^7.28.5", "@babel/types": "^7.28.5", "@rolldown/pluginutils": "1.0.0-beta.40", "@tanstack/router-core": "1.171.2", "@tanstack/router-generator": "1.167.5", "@tanstack/router-plugin": "1.168.6", "@tanstack/router-utils": "1.162.0", "@tanstack/start-client-core": "1.169.4", "@tanstack/start-server-core": "1.168.4", "cheerio": "^1.0.0", "exsolve": "^1.0.7", "lightningcss": "^1.32.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", "seroval": "^1.5.4", "source-map": "^0.7.6", "srvx": "^0.11.9", "tinyglobby": "^0.2.15", "ufo": "^1.5.4", "vitefu": "^1.1.1", "xmlbuilder2": "^4.0.3", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": "^2.0.0", "vite": ">=7.0.0" }, "optionalPeers": ["@rsbuild/core", "vite"] }, "sha512-8XzrZwNvYODjTf6zByQhYd1286YU8O1iecZ2zMhchvkHLTLfvku8xJavjLTaz9MAMM08KiX/oqEwpRiP/aOalg=="], + + "@tanstack/start-server-core": ["@tanstack/start-server-core@1.168.4", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/router-core": "1.171.2", "@tanstack/start-client-core": "1.169.4", "@tanstack/start-storage-context": "1.167.4", "fetchdts": "^0.1.6", "h3-v2": "npm:h3@2.0.1-rc.20", "seroval": "^1.5.4" } }, "sha512-YF9HRjIh8SyprQxOiAB1puXkGI4PqF2/StX00CXtmLOphFTfuShYOPvmQZXl2XZp6H9vt+qY+BNXucSuLzag9g=="], + + "@tanstack/start-storage-context": ["@tanstack/start-storage-context@1.167.4", "", { "dependencies": { "@tanstack/router-core": "1.171.2" } }, "sha512-hI93yABbvcaMWkCtewjxNAZOXcJIWhh7P8um7A76OHA2LmLFaR36Sm8eZ6OQHhPdFob4DMOkwDiCv9sckRvCow=="], + + "@tanstack/store": ["@tanstack/store@0.11.0", "", {}, "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw=="], + + "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.162.0", "", {}, "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], + + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + + "@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="], + + "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], + + "@types/react": ["@types/react@19.2.15", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q=="], + + "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], + + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "@vitest/coverage-v8": ["@vitest/coverage-v8@4.1.6", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.1.6", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.2", "obug": "^2.1.1", "std-env": "^4.0.0-rc.1", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "@vitest/browser": "4.1.6", "vitest": "4.1.6" }, "optionalPeers": ["@vitest/browser"] }, "sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ=="], + + "@vitest/expect": ["@vitest/expect@4.1.6", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.6", "@vitest/utils": "4.1.6", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg=="], + + "@vitest/mocker": ["@vitest/mocker@4.1.6", "", { "dependencies": { "@vitest/spy": "4.1.6", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@4.1.6", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw=="], + + "@vitest/runner": ["@vitest/runner@4.1.6", "", { "dependencies": { "@vitest/utils": "4.1.6", "pathe": "^2.0.3" } }, "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA=="], + + "@vitest/snapshot": ["@vitest/snapshot@4.1.6", "", { "dependencies": { "@vitest/pretty-format": "4.1.6", "@vitest/utils": "4.1.6", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw=="], + + "@vitest/spy": ["@vitest/spy@4.1.6", "", {}, "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg=="], + + "@vitest/utils": ["@vitest/utils@4.1.6", "", { "dependencies": { "@vitest/pretty-format": "4.1.6", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ=="], + + "agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + + "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + + "algoliasearch": ["algoliasearch@5.53.0", "", { "dependencies": { "@algolia/abtesting": "1.19.0", "@algolia/client-abtesting": "5.53.0", "@algolia/client-analytics": "5.53.0", "@algolia/client-common": "5.53.0", "@algolia/client-insights": "5.53.0", "@algolia/client-personalization": "5.53.0", "@algolia/client-query-suggestions": "5.53.0", "@algolia/client-search": "5.53.0", "@algolia/ingestion": "1.53.0", "@algolia/monitoring": "1.53.0", "@algolia/recommend": "5.53.0", "@algolia/requester-browser-xhr": "5.53.0", "@algolia/requester-fetch": "5.53.0", "@algolia/requester-node-http": "5.53.0" } }, "sha512-OGW1q6b91CRSSeiOnM8LxuR5NYJ2esvw66jUZ4IIvdv+ItNkx3pwLuyR+jaCdbGee4ov5WgUnyPryyh11xvByQ=="], + + "ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], + + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "ansis": ["ansis@4.3.0", "", {}, "sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg=="], + + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "argv-formatter": ["argv-formatter@1.0.0", "", {}, "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw=="], + + "array-ify": ["array-ify@1.0.0", "", {}, "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], + + "ast-v8-to-istanbul": ["ast-v8-to-istanbul@1.0.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "estree-walker": "^3.0.3", "js-tokens": "^10.0.0" } }, "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg=="], + + "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.31", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q=="], + + "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001793", "", {}, "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA=="], + + "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], + + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], + + "cheerio": ["cheerio@1.2.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.1.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="], + + "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], + + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + + "cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="], + + "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="], + + "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="], + + "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="], + + "content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + + "conventional-changelog-angular": ["conventional-changelog-angular@8.3.1", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg=="], + + "conventional-changelog-writer": ["conventional-changelog-writer@8.4.0", "", { "dependencies": { "@simple-libs/stream-utils": "^1.2.0", "conventional-commits-filter": "^5.0.0", "handlebars": "^4.7.7", "meow": "^13.0.0", "semver": "^7.5.2" }, "bin": { "conventional-changelog-writer": "dist/cli/index.js" } }, "sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g=="], + + "conventional-commits-filter": ["conventional-commits-filter@5.0.0", "", {}, "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q=="], + + "conventional-commits-parser": ["conventional-commits-parser@6.4.0", "", { "dependencies": { "@simple-libs/stream-utils": "^1.2.0", "meow": "^13.0.0" }, "bin": { "conventional-commits-parser": "dist/cli/index.js" } }, "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw=="], + + "convert-hrtime": ["convert-hrtime@5.0.0", "", {}, "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cookie-es": ["cookie-es@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "cosmiconfig": ["cosmiconfig@9.0.1", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "crypto-random-string": ["crypto-random-string@4.0.0", "", { "dependencies": { "type-fest": "^1.0.1" } }, "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], + + "duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.360", "", {}, "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "emojilib": ["emojilib@2.4.0", "", {}, "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw=="], + + "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], + + "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "env-ci": ["env-ci@11.2.0", "", { "dependencies": { "execa": "^8.0.0", "java-properties": "^1.0.2" } }, "sha512-D5kWfzkmaOQDioPmiviWAVtKmpPT4/iJmMVQxWxMPJTFyTkdc5JQUfc5iXEeWxcOdsYTKSAiA/Age4NUOqKsRA=="], + + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "es-module-lexer": ["es-module-lexer@2.1.0", "", {}, "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ=="], + + "esbuild": ["esbuild@0.28.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.0", "@esbuild/android-arm": "0.28.0", "@esbuild/android-arm64": "0.28.0", "@esbuild/android-x64": "0.28.0", "@esbuild/darwin-arm64": "0.28.0", "@esbuild/darwin-x64": "0.28.0", "@esbuild/freebsd-arm64": "0.28.0", "@esbuild/freebsd-x64": "0.28.0", "@esbuild/linux-arm": "0.28.0", "@esbuild/linux-arm64": "0.28.0", "@esbuild/linux-ia32": "0.28.0", "@esbuild/linux-loong64": "0.28.0", "@esbuild/linux-mips64el": "0.28.0", "@esbuild/linux-ppc64": "0.28.0", "@esbuild/linux-riscv64": "0.28.0", "@esbuild/linux-s390x": "0.28.0", "@esbuild/linux-x64": "0.28.0", "@esbuild/netbsd-arm64": "0.28.0", "@esbuild/netbsd-x64": "0.28.0", "@esbuild/openbsd-arm64": "0.28.0", "@esbuild/openbsd-x64": "0.28.0", "@esbuild/openharmony-arm64": "0.28.0", "@esbuild/sunos-x64": "0.28.0", "@esbuild/win32-arm64": "0.28.0", "@esbuild/win32-ia32": "0.28.0", "@esbuild/win32-x64": "0.28.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="], + + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + + "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-patch": ["fast-json-patch@3.1.1", "", {}, "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fetchdts": ["fetchdts@0.1.7", "", {}, "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA=="], + + "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-up": ["find-up@2.1.0", "", { "dependencies": { "locate-path": "^2.0.0" } }, "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ=="], + + "find-up-simple": ["find-up-simple@1.0.1", "", {}, "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ=="], + + "find-versions": ["find-versions@6.0.0", "", { "dependencies": { "semver-regex": "^4.0.5", "super-regex": "^1.0.0" } }, "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA=="], + + "formatly": ["formatly@0.3.0", "", { "dependencies": { "fd-package-json": "^2.0.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w=="], + + "fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-timeout": ["function-timeout@1.0.2", "", {}, "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], + + "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], + + "git-log-parser": ["git-log-parser@1.2.1", "", { "dependencies": { "argv-formatter": "~1.0.0", "spawn-error-forwarder": "~1.0.0", "split2": "~1.0.0", "stream-combiner2": "~1.1.1", "through2": "~2.0.0", "traverse": "0.6.8" } }, "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ=="], + + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "h3-v2": ["h3@2.0.1-rc.20", "", { "dependencies": { "rou3": "^0.8.1", "srvx": "^0.11.13" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"], "bin": { "h3": "bin/h3.mjs" } }, "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg=="], + + "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], + + "happy-dom": ["happy-dom@20.9.0", "", { "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "entities": "^7.0.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.18.3" } }, "sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], + + "hook-std": ["hook-std@4.0.0", "", {}, "sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ=="], + + "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], + + "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + + "http-proxy-agent": ["http-proxy-agent@9.0.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4" } }, "sha512-FcF8VhXYLQcxWCnt/cCpT2apKsRDUGeVEeMqGu4HSTu29U8Yw0TLOjdYIlDsYk3IkUh+taX4IDWpPcCqKDhCjA=="], + + "https-proxy-agent": ["https-proxy-agent@9.0.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4" } }, "sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g=="], + + "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], + + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "import-from-esm": ["import-from-esm@2.0.0", "", { "dependencies": { "debug": "^4.3.4", "import-meta-resolve": "^4.0.0" } }, "sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g=="], + + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + + "is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], + + "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isbot": ["isbot@5.1.40", "", {}, "sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "issue-parser": ["issue-parser@7.0.2", "", { "dependencies": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "sha512-7atWPjhGEIX3JEtMrOYd8TKzboYlq+5sNbdl9POiLYOI14G5HZiQbZP0Xj5EZdrufQVXfJlpTV0hys0CuxwxZw=="], + + "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], + + "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], + + "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], + + "java-properties": ["java-properties@1.0.2", "", {}, "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ=="], + + "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + + "js-tokens": ["js-tokens@10.0.0", "", {}, "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-with-bigint": ["json-with-bigint@3.5.8", "", {}, "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], + + "knip": ["knip@5.88.1", "", { "dependencies": { "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", "formatly": "^0.3.0", "jiti": "^2.6.0", "minimist": "^1.2.8", "oxc-resolver": "^11.19.1", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.5.2", "strip-json-comments": "5.0.3", "unbash": "^2.2.0", "yaml": "^2.8.2", "zod": "^4.1.11" }, "peerDependencies": { "@types/node": ">=18", "typescript": ">=5.0.4 <7" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-tpy5o7zu1MjawVkLPuahymVJekYY3kYjvzcoInhIchgePxTlo+api90tBv2KfhAIe5uXh+mez1tAfmbv8/TiZg=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "load-json-file": ["load-json-file@4.0.0", "", { "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" } }, "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw=="], + + "locate-path": ["locate-path@2.0.0", "", { "dependencies": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA=="], + + "lodash-es": ["lodash-es@4.18.1", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="], + + "lodash.capitalize": ["lodash.capitalize@4.2.1", "", {}, "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw=="], + + "lodash.escaperegexp": ["lodash.escaperegexp@4.1.2", "", {}, "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="], + + "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], + + "lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="], + + "lodash.uniqby": ["lodash.uniqby@4.7.0", "", {}, "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww=="], + + "lru-cache": ["lru-cache@11.4.0", "", {}, "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "magicast": ["magicast@0.5.3", "", { "dependencies": { "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw=="], + + "make-asynchronous": ["make-asynchronous@1.1.0", "", { "dependencies": { "p-event": "^6.0.0", "type-fest": "^4.6.0", "web-worker": "^1.5.0" } }, "sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg=="], + + "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], + + "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], + + "marked-terminal": ["marked-terminal@7.3.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "ansi-regex": "^6.1.0", "chalk": "^5.4.1", "cli-highlight": "^2.1.11", "cli-table3": "^0.6.5", "node-emoji": "^2.2.0", "supports-hyperlinks": "^3.1.0" }, "peerDependencies": { "marked": ">=1 <16" } }, "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw=="], + + "meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="], + + "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], + + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "nerf-dart": ["nerf-dart@1.0.0", "", {}, "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g=="], + + "node-emoji": ["node-emoji@2.2.0", "", { "dependencies": { "@sindresorhus/is": "^4.6.0", "char-regex": "^1.0.2", "emojilib": "^2.4.0", "skin-tone": "^2.0.0" } }, "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw=="], + + "node-releases": ["node-releases@2.0.44", "", {}, "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ=="], + + "normalize-package-data": ["normalize-package-data@8.0.0", "", { "dependencies": { "hosted-git-info": "^9.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "normalize-url": ["normalize-url@9.0.0", "", {}, "sha512-z9nC87iaZXXySbWWtTHfCFJyFvKaUAW6lODhikG7ILSbVgmwuFjUqkgnheHvAUcGedO29e2QGBRXMUD64aurqQ=="], + + "npm": ["npm@11.14.1", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^9.5.0", "@npmcli/config": "^10.9.0", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", "@npmcli/metavuln-calculator": "^9.0.3", "@npmcli/package-json": "^7.0.5", "@npmcli/promise-spawn": "^9.0.1", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.4", "@sigstore/tuf": "^4.0.2", "abbrev": "^4.0.0", "archy": "~1.0.0", "cacache": "^20.0.4", "chalk": "^5.6.2", "ci-info": "^4.4.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", "glob": "^13.0.6", "graceful-fs": "^4.2.11", "hosted-git-info": "^9.0.2", "ini": "^6.0.0", "init-package-json": "^8.2.5", "is-cidr": "^6.0.4", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", "libnpmdiff": "^8.1.7", "libnpmexec": "^10.2.7", "libnpmfund": "^7.0.21", "libnpmorg": "^8.0.1", "libnpmpack": "^9.1.7", "libnpmpublish": "^11.1.3", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", "libnpmversion": "^8.0.3", "make-fetch-happen": "^15.0.5", "minimatch": "^10.2.5", "minipass": "^7.1.3", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^12.3.0", "nopt": "^9.0.0", "npm-audit-report": "^7.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.2", "npm-pick-manifest": "^11.0.3", "npm-profile": "^12.0.1", "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", "pacote": "^21.5.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", "read": "^5.0.1", "semver": "^7.7.4", "spdx-expression-parse": "^4.0.0", "ssri": "^13.0.1", "supports-color": "^10.2.2", "tar": "^7.5.13", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", "validate-npm-package-name": "^7.0.2", "which": "^6.0.1" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" } }, "sha512-aopNZ0eEl6LbxoFcrXLmTEPzNBNxfiQnVgR9RmJBqzm+5h5pFoOmRljpRJbsXxocBeSl7GLcx3MoDf2UlEOjZw=="], + + "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], + + "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], + + "oxc-resolver": ["oxc-resolver@11.19.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.19.1", "@oxc-resolver/binding-android-arm64": "11.19.1", "@oxc-resolver/binding-darwin-arm64": "11.19.1", "@oxc-resolver/binding-darwin-x64": "11.19.1", "@oxc-resolver/binding-freebsd-x64": "11.19.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-musl": "11.19.1", "@oxc-resolver/binding-openharmony-arm64": "11.19.1", "@oxc-resolver/binding-wasm32-wasi": "11.19.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" } }, "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg=="], + + "p-each-series": ["p-each-series@3.0.0", "", {}, "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw=="], + + "p-event": ["p-event@6.0.1", "", { "dependencies": { "p-timeout": "^6.1.2" } }, "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w=="], + + "p-filter": ["p-filter@4.1.0", "", { "dependencies": { "p-map": "^7.0.1" } }, "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw=="], + + "p-limit": ["p-limit@1.3.0", "", { "dependencies": { "p-try": "^1.0.0" } }, "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="], + + "p-locate": ["p-locate@2.0.0", "", { "dependencies": { "p-limit": "^1.1.0" } }, "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg=="], + + "p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], + + "p-reduce": ["p-reduce@3.0.0", "", {}, "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q=="], + + "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="], + + "p-try": ["p-try@1.0.0", "", {}, "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="], + + "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], + + "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="], + + "path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="], + + "pkg-conf": ["pkg-conf@2.1.0", "", { "dependencies": { "find-up": "^2.0.0", "load-json-file": "^4.0.0" } }, "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g=="], + + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + + "prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="], + + "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + + "react": ["react@19.2.6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="], + + "react-dom": ["react-dom@19.2.6", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="], + + "read-package-up": ["read-package-up@12.0.0", "", { "dependencies": { "find-up-simple": "^1.0.1", "read-pkg": "^10.0.0", "type-fest": "^5.2.0" } }, "sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw=="], + + "read-pkg": ["read-pkg@10.1.0", "", { "dependencies": { "@types/normalize-package-data": "^2.4.4", "normalize-package-data": "^8.0.0", "parse-json": "^8.3.0", "type-fest": "^5.4.4", "unicorn-magic": "^0.4.0" } }, "sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "registry-auth-token": ["registry-auth-token@5.1.1", "", { "dependencies": { "@pnpm/npm-conf": "^3.0.2" } }, "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rolldown": ["rolldown@1.0.1", "", { "dependencies": { "@oxc-project/types": "=0.130.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.1", "@rolldown/binding-darwin-arm64": "1.0.1", "@rolldown/binding-darwin-x64": "1.0.1", "@rolldown/binding-freebsd-x64": "1.0.1", "@rolldown/binding-linux-arm-gnueabihf": "1.0.1", "@rolldown/binding-linux-arm64-gnu": "1.0.1", "@rolldown/binding-linux-arm64-musl": "1.0.1", "@rolldown/binding-linux-ppc64-gnu": "1.0.1", "@rolldown/binding-linux-s390x-gnu": "1.0.1", "@rolldown/binding-linux-x64-gnu": "1.0.1", "@rolldown/binding-linux-x64-musl": "1.0.1", "@rolldown/binding-openharmony-arm64": "1.0.1", "@rolldown/binding-wasm32-wasi": "1.0.1", "@rolldown/binding-win32-arm64-msvc": "1.0.1", "@rolldown/binding-win32-x64-msvc": "1.0.1" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ=="], + + "rou3": ["rou3@0.8.1", "", {}, "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "semantic-release": ["semantic-release@25.0.3", "", { "dependencies": { "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/error": "^4.0.0", "@semantic-release/github": "^12.0.0", "@semantic-release/npm": "^13.1.1", "@semantic-release/release-notes-generator": "^14.1.0", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", "env-ci": "^11.0.0", "execa": "^9.0.0", "figures": "^6.0.0", "find-versions": "^6.0.0", "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^4.0.0", "hosted-git-info": "^9.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "marked": "^15.0.0", "marked-terminal": "^7.3.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", "p-reduce": "^3.0.0", "read-package-up": "^12.0.0", "resolve-from": "^5.0.0", "semver": "^7.3.2", "signale": "^1.2.1", "yargs": "^18.0.0" }, "bin": { "semantic-release": "bin/semantic-release.js" } }, "sha512-WRgl5GcypwramYX4HV+eQGzUbD7UUbljVmS+5G1uMwX/wLgYuJAxGeerXJDMO2xshng4+FXqCgyB5QfClV6WjA=="], + + "semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="], + + "semver-regex": ["semver-regex@4.0.5", "", {}, "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw=="], + + "seroval": ["seroval@1.5.4", "", {}, "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw=="], + + "seroval-plugins": ["seroval-plugins@1.5.4", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "signale": ["signale@1.4.0", "", { "dependencies": { "chalk": "^2.3.2", "figures": "^2.0.0", "pkg-conf": "^2.1.0" } }, "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w=="], + + "skin-tone": ["skin-tone@2.0.0", "", { "dependencies": { "unicode-emoji-modifier-base": "^1.0.0" } }, "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA=="], + + "smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="], + + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "spawn-error-forwarder": ["spawn-error-forwarder@1.0.0", "", {}, "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g=="], + + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + + "split2": ["split2@1.0.0", "", { "dependencies": { "through2": "~2.0.0" } }, "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg=="], + + "srvx": ["srvx@0.11.15", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg=="], + + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + + "std-env": ["std-env@4.1.0", "", {}, "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ=="], + + "stream-combiner2": ["stream-combiner2@1.1.1", "", { "dependencies": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" } }, "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw=="], + + "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], + + "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + + "super-regex": ["super-regex@1.1.0", "", { "dependencies": { "function-timeout": "^1.0.1", "make-asynchronous": "^1.0.1", "time-span": "^5.1.0" } }, "sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-hyperlinks": ["supports-hyperlinks@3.2.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig=="], + + "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], + + "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], + + "temp-dir": ["temp-dir@3.0.0", "", {}, "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw=="], + + "tempy": ["tempy@3.2.0", "", { "dependencies": { "is-stream": "^3.0.0", "temp-dir": "^3.0.0", "type-fest": "^2.12.2", "unique-string": "^3.0.0" } }, "sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ=="], + + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + + "through2": ["through2@2.0.5", "", { "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="], + + "time-span": ["time-span@5.1.0", "", { "dependencies": { "convert-hrtime": "^5.0.0" } }, "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA=="], + + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "tinyrainbow": ["tinyrainbow@3.1.0", "", {}, "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "traverse": ["traverse@0.6.8", "", {}, "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tsx": ["tsx@4.22.3", "", { "dependencies": { "esbuild": "~0.28.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg=="], + + "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], + + "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], + + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + + "unbash": ["unbash@2.2.0", "", {}, "sha512-X2wH19RAPZE3+ldGicOkoj/SIA83OIxcJ6Cuaw23hf8Xc6fQpvZXY0SftE2JgS0QhYLUG4uwodSI3R53keyh7w=="], + + "undici": ["undici@6.25.0", "", {}, "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg=="], + + "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="], + + "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="], + + "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], + + "unique-string": ["unique-string@3.0.0", "", { "dependencies": { "crypto-random-string": "^4.0.0" } }, "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ=="], + + "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "unplugin": ["unplugin@3.0.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "url-join": ["url-join@5.0.0", "", {}, "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA=="], + + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + + "vite": ["vite@8.0.13", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.14", "rolldown": "1.0.1", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw=="], + + "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], + + "vitest": ["vitest@4.1.6", "", { "dependencies": { "@vitest/expect": "4.1.6", "@vitest/mocker": "4.1.6", "@vitest/pretty-format": "4.1.6", "@vitest/runner": "4.1.6", "@vitest/snapshot": "4.1.6", "@vitest/spy": "4.1.6", "@vitest/utils": "4.1.6", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.6", "@vitest/browser-preview": "4.1.6", "@vitest/browser-webdriverio": "4.1.6", "@vitest/coverage-istanbul": "4.1.6", "@vitest/coverage-v8": "4.1.6", "@vitest/ui": "4.1.6", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ=="], + + "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + + "web-worker": ["web-worker@1.5.0", "", {}, "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw=="], + + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + + "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], + + "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + + "ws": ["ws@8.20.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w=="], + + "xmlbuilder2": ["xmlbuilder2@4.0.3", "", { "dependencies": { "@oozcitak/dom": "^2.0.2", "@oozcitak/infra": "^2.0.2", "@oozcitak/util": "^10.0.0", "js-yaml": "^4.1.1" } }, "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + + "yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], + + "yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + + "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], + + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + + "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], + + "@semantic-release/github/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="], + + "@semantic-release/github/undici": ["undici@7.25.0", "", {}, "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ=="], + + "@semantic-release/npm/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="], + + "@semantic-release/release-notes-generator/read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="], + + "@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.9.3", "", {}, "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw=="], + + "@tanstack/router-generator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@tanstack/router-plugin/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@tanstack/start-plugin-core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + + "@tanstack/start-plugin-core/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "cheerio/undici": ["undici@7.25.0", "", {}, "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ=="], + + "cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], + + "cli-highlight/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "cli-highlight/parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], + + "cli-highlight/parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="], + + "cli-highlight/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], + + "cli-table3/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cosmiconfig/parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + + "crypto-random-string/type-fest": ["type-fest@1.4.0", "", {}, "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="], + + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "env-ci/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], + + "handlebars/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "load-json-file/parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="], + + "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "npm/@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="], + + "npm/@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + + "npm/@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", { "bundled": true }, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], + + "npm/@npmcli/agent": ["@npmcli/agent@4.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA=="], + + "npm/@npmcli/arborist": ["@npmcli/arborist@9.5.0", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bundled": true, "bin": { "arborist": "bin/index.js" } }, "sha512-qS+TtKWC58sjBjD+szLrhEj2TCLnwzUA9vlMyCnU9ztw01ZjQSu25iQPxeBa0sk9sS9/Hzs/xJMWl7J/vRCjGQ=="], + + "npm/@npmcli/config": ["@npmcli/config@10.9.0", "", { "dependencies": { "@npmcli/map-workspaces": "^5.0.0", "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "ini": "^6.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-qOqb+RoMH+y0OsvjCNafav5U4NqjnqRwHsfQlMmMqBt/N8Yt2LjW5tF4VCp4oG9KZXSMpuveOFi9b+GfIVsE5g=="], + + "npm/@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" }, "bundled": true }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="], + + "npm/@npmcli/git": ["@npmcli/git@7.0.2", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^9.0.0", "ini": "^6.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^11.0.1", "proc-log": "^6.0.0", "semver": "^7.3.5", "which": "^6.0.0" } }, "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg=="], + + "npm/@npmcli/installed-package-contents": ["@npmcli/installed-package-contents@4.0.0", "", { "dependencies": { "npm-bundled": "^5.0.0", "npm-normalize-package-bin": "^5.0.0" }, "bin": { "installed-package-contents": "bin/index.js" } }, "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA=="], + + "npm/@npmcli/map-workspaces": ["@npmcli/map-workspaces@5.0.3", "", { "dependencies": { "@npmcli/name-from-folder": "^4.0.0", "@npmcli/package-json": "^7.0.0", "glob": "^13.0.0", "minimatch": "^10.0.3" }, "bundled": true }, "sha512-o2grssXo1e774E5OtEwwrgoszYRh0lqkJH+Pb9r78UcqdGJRDRfhpM8DvZPjzNLLNYeD/rNbjOKM3Ss5UABROw=="], + + "npm/@npmcli/metavuln-calculator": ["@npmcli/metavuln-calculator@9.0.3", "", { "dependencies": { "cacache": "^20.0.0", "json-parse-even-better-errors": "^5.0.0", "pacote": "^21.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5" }, "bundled": true }, "sha512-94GLSYhLXF2t2LAC7pDwLaM4uCARzxShyAQKsirmlNcpidH89VA4/+K1LbJmRMgz5gy65E/QBBWQdUvGLe2Frg=="], + + "npm/@npmcli/name-from-folder": ["@npmcli/name-from-folder@4.0.0", "", {}, "sha512-qfrhVlOSqmKM8i6rkNdZzABj8MKEITGFAY+4teqBziksCQAOLutiAxM1wY2BKEd8KjUSpWmWCYxvXr0y4VTlPg=="], + + "npm/@npmcli/node-gyp": ["@npmcli/node-gyp@5.0.0", "", {}, "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ=="], + + "npm/@npmcli/package-json": ["@npmcli/package-json@7.0.5", "", { "dependencies": { "@npmcli/git": "^7.0.0", "glob": "^13.0.0", "hosted-git-info": "^9.0.0", "json-parse-even-better-errors": "^5.0.0", "proc-log": "^6.0.0", "semver": "^7.5.3", "spdx-expression-parse": "^4.0.0" }, "bundled": true }, "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ=="], + + "npm/@npmcli/promise-spawn": ["@npmcli/promise-spawn@9.0.1", "", { "dependencies": { "which": "^6.0.0" }, "bundled": true }, "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q=="], + + "npm/@npmcli/query": ["@npmcli/query@5.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ=="], + + "npm/@npmcli/redact": ["@npmcli/redact@4.0.0", "", { "bundled": true }, "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q=="], + + "npm/@npmcli/run-script": ["@npmcli/run-script@10.0.4", "", { "dependencies": { "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", "proc-log": "^6.0.0" }, "bundled": true }, "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg=="], + + "npm/@sigstore/bundle": ["@sigstore/bundle@4.0.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A=="], + + "npm/@sigstore/core": ["@sigstore/core@3.2.0", "", {}, "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA=="], + + "npm/@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.5.1", "", {}, "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g=="], + + "npm/@sigstore/sign": ["@sigstore/sign@4.1.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.2", "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.0", "@sigstore/protobuf-specs": "^0.5.0", "make-fetch-happen": "^15.0.4", "proc-log": "^6.1.0" } }, "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ=="], + + "npm/@sigstore/tuf": ["@sigstore/tuf@4.0.2", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0", "tuf-js": "^4.1.0" }, "bundled": true }, "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ=="], + + "npm/@sigstore/verify": ["@sigstore/verify@3.1.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag=="], + + "npm/@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], + + "npm/@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], + + "npm/abbrev": ["abbrev@4.0.0", "", { "bundled": true }, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], + + "npm/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "npm/aproba": ["aproba@2.1.0", "", {}, "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="], + + "npm/archy": ["archy@1.0.0", "", { "bundled": true }, "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="], + + "npm/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "npm/bin-links": ["bin-links@6.0.0", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w=="], + + "npm/binary-extensions": ["binary-extensions@3.1.0", "", {}, "sha512-Jvvd9hy1w+xUad8+ckQsWA/V1AoyubOvqn0aygjMOVM4BfIaRav1NFS3LsTSDaV4n4FtcCtQXvzep1E6MboqwQ=="], + + "npm/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "npm/cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" }, "bundled": true }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="], + + "npm/chalk": ["chalk@5.6.2", "", { "bundled": true }, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "npm/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + + "npm/ci-info": ["ci-info@4.4.0", "", { "bundled": true }, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "npm/cidr-regex": ["cidr-regex@5.0.5", "", {}, "sha512-59tdLZcC+BJXa4C5rOmVSuJTy/UneqfJJtCraqwdx5BDHTkGrBtKCUl3u2uiCFvXu+wk0kVuX8axX7yHCZOI9w=="], + + "npm/cmd-shim": ["cmd-shim@8.0.0", "", {}, "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA=="], + + "npm/common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], + + "npm/cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "npm/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "npm/diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + + "npm/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "npm/exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], + + "npm/fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", { "bundled": true }, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="], + + "npm/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "npm/fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" }, "bundled": true }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + + "npm/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" }, "bundled": true }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "npm/graceful-fs": ["graceful-fs@4.2.11", "", { "bundled": true }, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "npm/hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" }, "bundled": true }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + + "npm/http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + + "npm/http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "npm/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "npm/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + + "npm/ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], + + "npm/ini": ["ini@6.0.0", "", { "bundled": true }, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], + + "npm/init-package-json": ["init-package-json@8.2.5", "", { "dependencies": { "@npmcli/package-json": "^7.0.0", "npm-package-arg": "^13.0.0", "promzard": "^3.0.1", "read": "^5.0.1", "semver": "^7.7.2", "validate-npm-package-name": "^7.0.0" }, "bundled": true }, "sha512-IknQ+upLuJU6t3p0uo9wS3GjFD/1GtxIwcIGYOWR8zL2HxQeJwvxYTgZr9brJ8pyZ4kvpkebM8ZKcyqOeLOHSg=="], + + "npm/ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], + + "npm/is-cidr": ["is-cidr@6.0.4", "", { "dependencies": { "cidr-regex": "^5.0.4" }, "bundled": true }, "sha512-tOIBU3QiXy0W4LvHbcKWAWSuQfGwDiEILphFCAZtDqj7C57uv3ClO6K8aNEGV4VTA7bWJlpQ0suKQkUe6Rd6ag=="], + + "npm/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "npm/json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", { "bundled": true }, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="], + + "npm/json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], + + "npm/jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], + + "npm/just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="], + + "npm/just-diff-apply": ["just-diff-apply@5.5.0", "", {}, "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw=="], + + "npm/libnpmaccess": ["libnpmaccess@10.0.3", "", { "dependencies": { "npm-package-arg": "^13.0.0", "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-JPHTfWJxIK+NVPdNMNGnkz4XGX56iijPbe0qFWbdt68HL+kIvSzh+euBL8npLZvl2fpaxo+1eZSdoG15f5YdIQ=="], + + "npm/libnpmdiff": ["libnpmdiff@8.1.7", "", { "dependencies": { "@npmcli/arborist": "^9.5.0", "@npmcli/installed-package-contents": "^4.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", "minimatch": "^10.0.3", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2", "tar": "^7.5.1" }, "bundled": true }, "sha512-6ISfPg+OEHnTPBqHhnFLC3pS9sGdVtflrDMdJ/EfgJshjdq3C28LV7X9rBgW3zBbs7gFrZkUjpzwcuHpbgGl+w=="], + + "npm/libnpmexec": ["libnpmexec@10.2.7", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/arborist": "^9.5.0", "@npmcli/package-json": "^7.0.0", "@npmcli/run-script": "^10.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2", "proc-log": "^6.0.0", "read": "^5.0.1", "semver": "^7.3.7", "signal-exit": "^4.1.0", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-kAmmRkN22ODFc9hkmgOxXL6qq6LkqlOyyfKUBI4E3Fu0igmdINfYWN2wnjQg5UD9D86YiP09Ze3WS40/X7vJpQ=="], + + "npm/libnpmfund": ["libnpmfund@7.0.21", "", { "dependencies": { "@npmcli/arborist": "^9.5.0" }, "bundled": true }, "sha512-0GlVzx8LR1BGk1lT+zqvyhG4VbU471Hg4PNmAWT9wlzCgvevEVu4Q5kadauasa/uFC2w00gmERiy0V5yRa1VsQ=="], + + "npm/libnpmorg": ["libnpmorg@8.0.1", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-/QeyXXg4hqMw0ESM7pERjIT2wbR29qtFOWIOug/xO4fRjS3jJJhoAPQNsnHtdwnCqgBdFpGQ45aIdFFZx2YhTA=="], + + "npm/libnpmpack": ["libnpmpack@9.1.7", "", { "dependencies": { "@npmcli/arborist": "^9.5.0", "@npmcli/run-script": "^10.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2" }, "bundled": true }, "sha512-4K0T2HWf9GpjxBIGwitgSEySHJNOCbFugYtuOWixox/+yXdZlK54KTF8lvHK++nujGacPGmL8+CTIRamBlLXgQ=="], + + "npm/libnpmpublish": ["libnpmpublish@11.1.3", "", { "dependencies": { "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^13.0.0", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "semver": "^7.3.7", "sigstore": "^4.0.0", "ssri": "^13.0.0" }, "bundled": true }, "sha512-NVPTth/71cfbdYHqypcO9Lt5WFGTzFEcx81lWd7GDJIgZ95ERdYHGUfCtFejHCyqodKsQkNEx2JCkMpreDty/A=="], + + "npm/libnpmsearch": ["libnpmsearch@9.0.1", "", { "dependencies": { "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-oKw58X415ERY/BOGV3jQPVMcep8YeMRWMzuuqB0BAIM5VxicOU1tQt19ExCu4SV77SiTOEoziHxGEgJGw3FBYQ=="], + + "npm/libnpmteam": ["libnpmteam@8.0.2", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-ypLrDUQoi8EhG+gzx5ENMcYq23YjPV17Mfvx4nOnQiHOi8vp47+4GvZBrMsEM4yeHPwxguF/HZoXH4rJfHdH/w=="], + + "npm/libnpmversion": ["libnpmversion@8.0.3", "", { "dependencies": { "@npmcli/git": "^7.0.0", "@npmcli/run-script": "^10.0.0", "json-parse-even-better-errors": "^5.0.0", "proc-log": "^6.0.0", "semver": "^7.3.7" }, "bundled": true }, "sha512-Avj1GG3DT6MGzWOOk3yA7rORcMDUPizkIGbI8glHCO7WoYn3NYNmskLDwxg2NMY1Tyf2vrHAqTuSG58uqd1lJg=="], + + "npm/lru-cache": ["lru-cache@11.4.0", "", {}, "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA=="], + + "npm/make-fetch-happen": ["make-fetch-happen@15.0.5", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" }, "bundled": true }, "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg=="], + + "npm/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" }, "bundled": true }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "npm/minipass": ["minipass@7.1.3", "", { "bundled": true }, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "npm/minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + + "npm/minipass-fetch": ["minipass-fetch@5.0.2", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^2.0.0", "minizlib": "^3.0.1" }, "optionalDependencies": { "iconv-lite": "^0.7.2" } }, "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ=="], + + "npm/minipass-flush": ["minipass-flush@1.0.7", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA=="], + + "npm/minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" }, "bundled": true }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + + "npm/minipass-sized": ["minipass-sized@2.0.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA=="], + + "npm/minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], + + "npm/ms": ["ms@2.1.3", "", { "bundled": true }, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "npm/mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="], + + "npm/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "npm/node-gyp": ["node-gyp@12.3.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", "undici": "^6.25.0", "which": "^6.0.0" }, "bundled": true, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg=="], + + "npm/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bundled": true, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], + + "npm/npm-audit-report": ["npm-audit-report@7.0.0", "", { "bundled": true }, "sha512-bluLL4xwGr/3PERYz50h2Upco0TJMDcLcymuFnfDWeGO99NqH724MNzhWi5sXXuXf2jbytFF0LyR8W+w1jTI6A=="], + + "npm/npm-bundled": ["npm-bundled@5.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^5.0.0" } }, "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw=="], + + "npm/npm-install-checks": ["npm-install-checks@8.0.0", "", { "dependencies": { "semver": "^7.1.1" }, "bundled": true }, "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA=="], + + "npm/npm-normalize-package-bin": ["npm-normalize-package-bin@5.0.0", "", {}, "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag=="], + + "npm/npm-package-arg": ["npm-package-arg@13.0.2", "", { "dependencies": { "hosted-git-info": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^7.0.0" }, "bundled": true }, "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA=="], + + "npm/npm-packlist": ["npm-packlist@10.0.4", "", { "dependencies": { "ignore-walk": "^8.0.0", "proc-log": "^6.0.0" } }, "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng=="], + + "npm/npm-pick-manifest": ["npm-pick-manifest@11.0.3", "", { "dependencies": { "npm-install-checks": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "npm-package-arg": "^13.0.0", "semver": "^7.3.5" }, "bundled": true }, "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ=="], + + "npm/npm-profile": ["npm-profile@12.0.1", "", { "dependencies": { "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0" }, "bundled": true }, "sha512-Xs1mejJ1/9IKucCxdFMkiBJUre0xaxfCpbsO7DB7CadITuT4k68eI05HBlw4kj+Em1rsFMgeFNljFPYvPETbVQ=="], + + "npm/npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" }, "bundled": true }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="], + + "npm/npm-user-validate": ["npm-user-validate@4.0.0", "", { "bundled": true }, "sha512-TP+Ziq/qPi/JRdhaEhnaiMkqfMGjhDLoh/oRfW+t5aCuIfJxIUxvwk6Sg/6ZJ069N/Be6gs00r+aZeJTfS9uHQ=="], + + "npm/p-map": ["p-map@7.0.4", "", { "bundled": true }, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], + + "npm/pacote": ["pacote@21.5.0", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bundled": true, "bin": { "pacote": "bin/index.js" } }, "sha512-VtZ0SB8mb5Tzw3dXDfVAIjhyVKUHZkS/ZH9/5mpKenwC9sFOXNI0JI7kEF7IMkwOnsWMFrvAZHzx1T5fmrp9FQ=="], + + "npm/parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" }, "bundled": true }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], + + "npm/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "npm/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "npm/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], + + "npm/proc-log": ["proc-log@6.1.0", "", { "bundled": true }, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="], + + "npm/proggy": ["proggy@4.0.0", "", {}, "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ=="], + + "npm/promise-all-reject-late": ["promise-all-reject-late@1.0.1", "", {}, "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw=="], + + "npm/promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="], + + "npm/promzard": ["promzard@3.0.1", "", { "dependencies": { "read": "^5.0.0" } }, "sha512-M5mHhWh+Adz0BIxgSrqcc6GTCSconR7zWQV9vnOSptNtr6cSFlApLc28GbQhuN6oOWBQeV2C0bNE47JCY/zu3Q=="], + + "npm/qrcode-terminal": ["qrcode-terminal@0.12.0", "", { "bundled": true, "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="], + + "npm/read": ["read@5.0.1", "", { "dependencies": { "mute-stream": "^3.0.0" }, "bundled": true }, "sha512-+nsqpqYkkpet2UVPG8ZiuE8d113DK4vHYEoEhcrXBAlPiq6di7QRTuNiKQAbaRYegobuX2BpZ6QjanKOXnJdTA=="], + + "npm/read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="], + + "npm/safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "npm/semver": ["semver@7.8.0", "", { "bundled": true, "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="], + + "npm/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "npm/sigstore": ["sigstore@4.1.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.1.0", "@sigstore/tuf": "^4.0.1", "@sigstore/verify": "^3.1.0" } }, "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA=="], + + "npm/smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + + "npm/socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="], + + "npm/socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + + "npm/spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "npm/spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" }, "bundled": true }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="], + + "npm/spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + + "npm/ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" }, "bundled": true }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="], + + "npm/supports-color": ["supports-color@10.2.2", "", { "bundled": true }, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + + "npm/tar": ["tar@7.5.15", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "bundled": true }, "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="], + + "npm/text-table": ["text-table@0.2.0", "", { "bundled": true }, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], + + "npm/tiny-relative-date": ["tiny-relative-date@2.0.2", "", { "bundled": true }, "sha512-rGxAbeL9z3J4pI2GtBEoFaavHdO4RKAU54hEuOef5kfx5aPqiQtbhYktMOTL5OA33db8BjsDcLXuNp+/v19PHw=="], + + "npm/tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "npm/treeverse": ["treeverse@3.0.0", "", { "bundled": true }, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], + + "npm/tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="], + + "npm/undici": ["undici@6.25.0", "", {}, "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg=="], + + "npm/util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "npm/validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", { "bundled": true }, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="], + + "npm/walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + + "npm/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bundled": true, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + + "npm/write-file-atomic": ["write-file-atomic@7.0.1", "", { "dependencies": { "signal-exit": "^4.0.1" } }, "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg=="], + + "npm/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "read-package-up/type-fest": ["type-fest@5.6.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA=="], + + "read-pkg/type-fest": ["type-fest@5.6.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA=="], + + "read-pkg/unicorn-magic": ["unicorn-magic@0.4.0", "", {}, "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw=="], + + "readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], + + "semantic-release/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="], + + "semantic-release/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "signale/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "signale/figures": ["figures@2.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA=="], + + "tempy/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], + + "tempy/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "@semantic-release/github/aggregate-error/clean-stack": ["clean-stack@5.3.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg=="], + + "@semantic-release/github/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], + + "@semantic-release/npm/aggregate-error/clean-stack": ["clean-stack@5.3.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg=="], + + "@semantic-release/npm/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], + + "@semantic-release/release-notes-generator/read-package-up/read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="], + + "@tanstack/start-plugin-core/@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "cli-highlight/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "cli-highlight/parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], + + "cli-highlight/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + + "cli-highlight/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cli-highlight/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + + "cli-table3/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cli-table3/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "env-ci/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + + "env-ci/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], + + "env-ci/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], + + "env-ci/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], + + "env-ci/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], + + "npm/minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "npm/minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "semantic-release/aggregate-error/clean-stack": ["clean-stack@5.3.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg=="], + + "semantic-release/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], + + "signale/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "signale/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "signale/figures/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "@semantic-release/release-notes-generator/read-package-up/read-pkg/normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="], + + "@semantic-release/release-notes-generator/read-package-up/read-pkg/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + + "cli-highlight/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "cli-highlight/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cli-highlight/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "cli-highlight/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cli-highlight/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cli-table3/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "env-ci/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + + "npm/minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "npm/minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "signale/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "@semantic-release/release-notes-generator/read-package-up/read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], + + "cli-highlight/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "cli-highlight/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "cli-highlight/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "cli-highlight/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@semantic-release/release-notes-generator/read-package-up/read-pkg/normalize-package-data/hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "cli-highlight/yargs/cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "cli-highlight/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + } +} diff --git a/knip.json b/knip.json index d92b45d..20ac8c1 100644 --- a/knip.json +++ b/knip.json @@ -12,6 +12,9 @@ "shopify/loaders/*.ts", "shopify/utils/*.ts", "shopify/utils/**/*.ts", + "salesforce/*.ts", + "salesforce/loaders/products/*.ts", + "salesforce/utils/*.ts", "commerce/components/*.tsx", "commerce/sdk/*.ts", "commerce/types/*.ts", diff --git a/magento/README.md b/magento/README.md new file mode 100644 index 0000000..177de53 --- /dev/null +++ b/magento/README.md @@ -0,0 +1,65 @@ +# Magento app — initial scaffold + +This folder ports the Magento integration from `deco-cx/apps/magento` +(Fresh/Deno) to `@decocms/apps/magento` (TanStack Start/Node), following +the same shape as the existing `vtex/` and `shopify/` packages. + +## Status + +**Initial scaffold** — covers the configure/client surface and 2 reference +loaders (`features`, `cart`) so that downstream sites can wire magento at +all. The remaining 20+ loaders/actions exist as production-grade code in +the original deco-cx/apps repo and need adaptation passes (Deno → Node, +ctx-based to client-based state access, cookie helpers from +`@decocms/start/sdk/cookie`). + +A real-world consumer (deco-sites/granadobr-tanstack) is wiring magento +in-site today using a thin adapter that wraps the legacy `magento/mod.ts` +shape. Their adapter is the migration target — once this package covers +the surface area they need, the in-site copy goes away. + +## What's here + +- `client.ts` — `configureMagento({ baseUrl, apiKey, storeId, ... })` + + `getMagentoConfig()` global accessor. Mirrors the `configureVtex` + pattern. +- `types.ts` — request/response shapes shared between loaders. +- `loaders/features.ts` — returns the feature flags block. The simplest + loader, used as a smoke test. +- `loaders/cart.ts` — fetches the customer's active cart by cookie. + Pulls cookies via `@decocms/start/sdk/cookie`. +- `middleware.ts` — passthrough today; real-world cart-id reconciliation + lives in the consumer site for now. +- `index.ts` — re-export entry. + +## Pending port (PR follow-ups) + +| Path | Original location | +|---|---| +| `loaders/product/{detailsPage,detailsPageGQL,listingPage,list,relatedProducts}.ts` | `deco-cx/apps/magento/loaders/product/*` | +| `loaders/{proxy,user,wishlist}.ts` | `deco-cx/apps/magento/loaders/*` | +| `loaders/routes/getRouteType.ts` | idem | +| `actions/cart/{addCoupon,addItem,removeCoupon,removeItem,setSimulation,simulation,updateItem}.ts` | `deco-cx/apps/magento/actions/cart/*` | +| `actions/newsletter/subscribe.ts` | idem | +| `actions/product/stockAlert.ts` | idem | +| `actions/wishlist/{addItem,removeItem}.ts` | idem | +| `utils/{clientGraphql,client,transform,cache,graphql,cart}.ts` | `deco-cx/apps/magento/utils/*` | +| `hooks/{useCart,useUser,useWishlist}.ts` | `deco-cx/apps/magento/hooks/*` (refactor to react-query, like `vtex/hooks/`) | +| `inline-loaders/*` | new, follow `vtex/inline-loaders/` shape | + +**Site-specific extensions (Livelo, Amasty)** in the deco-cx/apps repo +should stay out of this package — they belong in consumer sites via the +`ExtensionOf` pattern. Preserving that pattern in the generic loaders +above is a hard requirement of this port. + +## Why a stub now + +The deco-sites/granadobr-tanstack migration hit a HIGH parity finding: + +``` +invoke(magento/loaders/features) failed: handler not found +``` + +…because no `@decocms/apps/magento/*` resolver existed. The site is +working around it locally; this PR begins the upstream fix so future +magento sites don't have to repeat the in-site adapter. diff --git a/magento/__tests__/cart.test.ts b/magento/__tests__/cart.test.ts new file mode 100644 index 0000000..acfcbc7 --- /dev/null +++ b/magento/__tests__/cart.test.ts @@ -0,0 +1,139 @@ +/** + * Tests for the cart loader. + * + * Parity goals against deco-cx/apps/magento/loaders/cart.ts (Fresh/Deno, + * prod): + * + * - Reads `dataservices_cart_id` cookie when caller doesn't supply + * `cartId` in props (matches `getCartCookie(req.headers)` in prod). + * - Honors props.cartId override (matches `_cartId ?? getCartCookie()`). + * - Hits /rest/:site/V1/carts/:cartId — the /rest/ prefix is what the + * Magento REST API exposes; the legacy clientAdmin's typed key was + * "GET /rest/:site/V1/carts/:cartId". + * - Encodes site + cartId so a malicious cookie can't escape the path + * segment and reach another admin endpoint with the Bearer token. + * - Returns null when no cookie (anonymous visitor — matches prod's + * `if (!cartId) return null`). + * - Returns null on 404 (expired cookie — prod hits this via the same + * branch but throws on other non-2xx; we surface a plain Error). + * + * NOT covered by this initial port (and intentionally not tested here): + * - Pre-cart `GET /rest/:site/V1/carts/mine` warm-up for logged-in + * users (the original does it inside a try/catch and discards the + * result — it's a cache primer, not a correctness invariant). + * - Parallel /totals fetch + image-pipeline transform — those land in + * follow-up PRs that port utils/cart.ts + utils/cache.ts. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { configureMagento } from "../client"; +import cart from "../loaders/cart"; + +function mockResponse(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +function requestWithCookie(cookie: string): Request { + const r = new Request("http://localhost/"); + // Headers in a freshly-constructed Request enter "request" guard mode + // which silently drops `cookie`. Build a Headers manually then attach. + const headers = new Headers(); + headers.set("cookie", cookie); + Object.defineProperty(r, "headers", { value: headers, configurable: true }); + return r; +} + +describe("cart loader", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("returns null when no cart cookie is present", async () => { + const req = new Request("http://localhost/"); + const result = await cart(undefined, req); + expect(result).toBeNull(); + expect(fetchSpy).not.toHaveBeenCalled(); + }); + + it("reads cartId from the dataservices_cart_id cookie (JSON-encoded)", async () => { + fetchSpy.mockResolvedValue(mockResponse({ id: "abc123", items: [] })); + const req = requestWithCookie('dataservices_cart_id="abc123"'); + await cart(undefined, req); + const [target] = fetchSpy.mock.calls[0] as [URL]; + expect(target.toString()).toBe("https://loja.example.com/rest/example/V1/carts/abc123"); + }); + + it("reads cartId from the cookie when it's not JSON-quoted", async () => { + fetchSpy.mockResolvedValue(mockResponse({ id: "raw-id", items: [] })); + const req = requestWithCookie("dataservices_cart_id=raw-id"); + await cart(undefined, req); + const [target] = fetchSpy.mock.calls[0] as [URL]; + expect(target.toString()).toBe("https://loja.example.com/rest/example/V1/carts/raw-id"); + }); + + it("honors props.cartId override (cookie ignored)", async () => { + fetchSpy.mockResolvedValue(mockResponse({ id: "from-props", items: [] })); + const req = requestWithCookie('dataservices_cart_id="from-cookie"'); + await cart({ cartId: "from-props" }, req); + const [target] = fetchSpy.mock.calls[0] as [URL]; + expect(target.toString()).toContain("/rest/example/V1/carts/from-props"); + }); + + it("URL-encodes the cartId to prevent path injection", async () => { + // A malicious cookie value tries to break out of the path segment + // and reach a different admin endpoint with the Bearer attached. + fetchSpy.mockResolvedValue(mockResponse(null, 404)); + const req = requestWithCookie('dataservices_cart_id="../admin/leak?secret=1"'); + await cart(undefined, req); + const [target] = fetchSpy.mock.calls[0] as [URL]; + // Encoded: %2F (slash), %3F (?), %3D (=). The trailing + // "/admin/leak?secret=1" stays inside the path segment. + expect(target.pathname).toMatch( + /^\/rest\/example\/V1\/carts\/(\.\.|%2E%2E)%2Fadmin%2Fleak%3Fsecret%3D1$/i, + ); + }); + + it("returns null on 404 (expired cart cookie)", async () => { + fetchSpy.mockResolvedValue(mockResponse(null, 404)); + const req = requestWithCookie('dataservices_cart_id="stale"'); + const result = await cart(undefined, req); + expect(result).toBeNull(); + }); + + it("throws on non-404 errors", async () => { + fetchSpy.mockResolvedValue(mockResponse(null, 500)); + const req = requestWithCookie('dataservices_cart_id="abc"'); + await expect(cart(undefined, req)).rejects.toThrow(/cart loader: 500/); + }); + + it("attaches Bearer + x-origin-header (same-origin) on the cart fetch", async () => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + originHeader: "origin-secret", + }); + fetchSpy.mockResolvedValue(mockResponse({ id: "abc", items: [] })); + const req = requestWithCookie('dataservices_cart_id="abc"'); + await cart(undefined, req); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("authorization")).toBe("Bearer secret"); + expect(headers.get("x-origin-header")).toBe("origin-secret"); + }); +}); diff --git a/magento/__tests__/client.test.ts b/magento/__tests__/client.test.ts new file mode 100644 index 0000000..122dff1 --- /dev/null +++ b/magento/__tests__/client.test.ts @@ -0,0 +1,252 @@ +/** + * Tests for the Magento client config + magentoFetch wrapper. + * + * Parity goals — behavior these tests pin down so the port stays aligned + * with deco-cx/apps/magento (Fresh/Deno, prod): + * + * - configureMagento / getMagentoConfig is a write-once-read-many global + * (mirrors configureVtex). getMagentoConfig() throws before configure(). + * - magentoFetch: + * • Same-origin: attaches Authorization (Bearer apiKey), + * x-origin-header (when configured), and a forced Referer pointing + * at baseUrl — exactly the headers the Fresh `clientAdmin` was + * built with at App() time. + * • Cross-origin: strips ALL Magento-only identity headers so the + * admin Bearer + origin secret never leak to a third party. Caller + * headers pass through. + * • authenticated:false opt-out drops Bearer even on same-origin. + * • Relative paths resolve against baseUrl with proper "/" handling. + * • Absolute https://… paths bypass baseUrl entirely. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { configureMagento, getMagentoConfig, magentoFetch } from "../client"; + +// Reset module-global config between tests by re-importing. +beforeEach(() => { + vi.resetModules(); +}); + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("configureMagento / getMagentoConfig", () => { + it("throws before configureMagento() is called", async () => { + const { getMagentoConfig: freshGet } = await import("../client"); + expect(() => freshGet()).toThrow(/configureMagento\(\) must be called/); + }); + + it("returns the configured value after configureMagento()", async () => { + const { configureMagento: c, getMagentoConfig: g } = await import("../client"); + c({ + baseUrl: "https://loja.example.com/", + apiKey: "test-key", + storeId: 1, + site: "example", + }); + expect(g().baseUrl).toBe("https://loja.example.com/"); + expect(g().apiKey).toBe("test-key"); + }); +}); + +describe("magentoFetch — same-origin (configured baseUrl)", () => { + const baseUrl = "https://loja.example.com/"; + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl, + apiKey: "secret-bearer", + storeId: 1, + site: "example", + originHeader: "origin-secret", + }); + fetchSpy = vi + .spyOn(globalThis, "fetch") + .mockResolvedValue( + new Response("{}", { status: 200, headers: { "content-type": "application/json" } }), + ); + }); + + it("attaches Authorization, x-origin-header, and forced Referer", async () => { + await magentoFetch("/rest/example/V1/carts/123"); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("authorization")).toBe("Bearer secret-bearer"); + expect(headers.get("x-origin-header")).toBe("origin-secret"); + expect(headers.get("referer")).toBe(baseUrl); + }); + + it("resolves relative path against baseUrl with correct slash handling", async () => { + await magentoFetch("rest/example/V1/carts/123"); // no leading slash + const [target] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe("https://loja.example.com/rest/example/V1/carts/123"); + }); + + it("authenticated:false suppresses Bearer even on same-origin", async () => { + await magentoFetch("/rest/example/V1/carts/123", { authenticated: false }); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("authorization")).toBeNull(); + // Same-origin still gets the other Magento-identity headers. + expect(headers.get("x-origin-header")).toBe("origin-secret"); + }); + + it("preserves caller-supplied Referer (no force-overwrite when caller set one)", async () => { + await magentoFetch("/rest/example/V1/carts/123", { + headers: { Referer: "https://caller.example/page" }, + }); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("referer")).toBe("https://caller.example/page"); + }); +}); + +describe("magentoFetch — cross-origin guard", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret-bearer", + storeId: 1, + site: "example", + originHeader: "origin-secret", + }); + fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response("{}", { status: 200 })); + }); + + it("strips Bearer when fetching a non-Magento host", async () => { + await magentoFetch("https://attacker.example/api"); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("authorization")).toBeNull(); + }); + + it("strips x-origin-header when fetching a non-Magento host", async () => { + // Regression for cubic review: the previous fix only dropped Bearer + // while x-origin-header and Referer still leaked. + await magentoFetch("https://attacker.example/api"); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("x-origin-header")).toBeNull(); + }); + + it("strips forced Referer when fetching a non-Magento host", async () => { + await magentoFetch("https://attacker.example/api"); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + // Referer to https://loja.example.com/ would broadcast the Magento + // host to the third party — must not be set by us. + expect(headers.get("referer")).toBeNull(); + }); + + it("still forwards caller-supplied headers cross-origin", async () => { + await magentoFetch("https://partner.example/api", { + headers: { "x-correlation-id": "abc123" }, + }); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + const headers = init.headers as Headers; + expect(headers.get("x-correlation-id")).toBe("abc123"); + }); + + it("treats an absolute URL with the same origin as same-origin", async () => { + await magentoFetch("https://loja.example.com/rest/example/V1/carts/123"); + const [target, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe("https://loja.example.com/rest/example/V1/carts/123"); + expect((init.headers as Headers).get("authorization")).toBe("Bearer secret-bearer"); + }); +}); + +describe("initMagentoFromBlocks — secret resolution", () => { + beforeEach(() => { + vi.resetModules(); + }); + + it("returns early when the `magento` block is absent", async () => { + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + const { initMagentoFromBlocks, getMagentoConfig } = await import("../client"); + await initMagentoFromBlocks({}); + expect(warn).toHaveBeenCalledWith(expect.stringContaining("No `magento` block")); + expect(() => getMagentoConfig()).toThrow(/configureMagento\(\) must be called/); + }); + + it("reads plain-string apiKey directly", async () => { + const { initMagentoFromBlocks, getMagentoConfig } = await import("../client"); + await initMagentoFromBlocks({ + magento: { + apiConfig: { + baseUrl: "https://loja.example.com/", + apiKey: "plain-string-key", + site: "example", + storeId: 1, + }, + }, + }); + expect(getMagentoConfig().apiKey).toBe("plain-string-key"); + }); + + it("dereferences a Secret-shaped apiKey via process.env (the env fallback path)", async () => { + process.env.TEST_MAGENTO_KEY = "from-env"; + const { initMagentoFromBlocks, getMagentoConfig } = await import("../client"); + await initMagentoFromBlocks({ + magento: { + apiConfig: { + baseUrl: "https://loja.example.com/", + apiKey: { + __resolveType: "website/loaders/secret.ts", + name: "TEST_MAGENTO_KEY", + }, + site: "example", + storeId: 1, + }, + }, + }); + expect(getMagentoConfig().apiKey).toBe("from-env"); + delete process.env.TEST_MAGENTO_KEY; + }); + + it("falls back to empty string when secret is unresolvable", async () => { + // no DECO_CRYPTO_KEY, no env var with this name, no decrypt + // → resolveSecret returns null → init writes "". + delete process.env.DECO_CRYPTO_KEY; + const { initMagentoFromBlocks, getMagentoConfig } = await import("../client"); + await initMagentoFromBlocks({ + magento: { + apiConfig: { + baseUrl: "https://loja.example.com/", + apiKey: { + __resolveType: "website/loaders/secret.ts", + encrypted: "deadbeef", + name: "UNDEFINED_ENV_VAR_DO_NOT_SET", + }, + site: "example", + storeId: 1, + }, + }, + }); + expect(getMagentoConfig().apiKey).toBe(""); + }); + + it("resolves both apiKey and originHeader independently", async () => { + process.env.TEST_API_KEY = "api-from-env"; + process.env.TEST_ORIGIN = "origin-from-env"; + const { initMagentoFromBlocks, getMagentoConfig } = await import("../client"); + await initMagentoFromBlocks({ + magento: { + apiConfig: { + baseUrl: "https://loja.example.com/", + apiKey: { name: "TEST_API_KEY" }, + originHeader: { name: "TEST_ORIGIN" }, + site: "example", + storeId: 1, + }, + }, + }); + const cfg = getMagentoConfig(); + expect(cfg.apiKey).toBe("api-from-env"); + expect(cfg.originHeader).toBe("origin-from-env"); + delete process.env.TEST_API_KEY; + delete process.env.TEST_ORIGIN; + }); +}); diff --git a/magento/__tests__/features.test.ts b/magento/__tests__/features.test.ts new file mode 100644 index 0000000..1975f6c --- /dev/null +++ b/magento/__tests__/features.test.ts @@ -0,0 +1,51 @@ +/** + * Tests for the features loader. + * + * Parity with deco-cx/apps/magento/loaders/features.ts (Fresh/Deno, prod): + * the legacy loader was a 3-arg `(_props, _req, ctx) => ctx.features`. + * The ported version uses the module-global config instead of a per- + * request ctx, but the surface area downstream is the same — a plain + * object pulled from the resolved magento CMS block. + */ +import { beforeEach, describe, expect, it } from "vitest"; +import { configureMagento } from "../client"; +import features from "../loaders/features"; + +describe("features loader", () => { + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "key", + storeId: 1, + site: "example", + features: { + dangerouslyDisableWishlist: false, + dangerouslyDisableOnLoadUpdate: true, + dangerouslyReturnNullAfterAction: true, + dangerouslyDontReturnCartAfterAction: true, + dangerouslyDisableOnVisibilityChangeUpdate: true, + }, + }); + }); + + it("returns the feature flags object from the config", () => { + expect(features()).toEqual({ + dangerouslyDisableWishlist: false, + dangerouslyDisableOnLoadUpdate: true, + dangerouslyReturnNullAfterAction: true, + dangerouslyDontReturnCartAfterAction: true, + dangerouslyDisableOnVisibilityChangeUpdate: true, + }); + }); + + it("returns an empty object when features are not configured", () => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "key", + storeId: 1, + site: "example", + // features omitted + }); + expect(features()).toEqual({}); + }); +}); diff --git a/magento/__tests__/graphql.test.ts b/magento/__tests__/graphql.test.ts new file mode 100644 index 0000000..813b3fa --- /dev/null +++ b/magento/__tests__/graphql.test.ts @@ -0,0 +1,183 @@ +/** + * Tests for the GraphQL helpers used by product loaders. + * + * Parity with deco-cx/apps/magento/utils/graphql.ts — pure functions, + * so behavior is exhaustively pinnable. Each test mirrors a real call + * site in the (still-unported) product loaders. + */ +import { describe, expect, it } from "vitest"; +import { + filtersFromLoaderGraphQL, + filtersFromUrlGraphQL, + formatUrlSuffix, + getCustomFields, + transformFilterGraphQL, + transformFilterValueGraphQL, + transformSortGraphQL, +} from "../utils/graphql"; + +describe("transformSortGraphQL", () => { + it("returns undefined when sortBy is absent", () => { + expect(transformSortGraphQL({})).toBeUndefined(); + expect(transformSortGraphQL({ order: "DESC" })).toBeUndefined(); + }); + + it("defaults order to ASC when not provided", () => { + expect(transformSortGraphQL({ sortBy: { value: "price" } })).toEqual({ + price: "ASC", + }); + }); + + it("respects DESC order", () => { + expect(transformSortGraphQL({ sortBy: { value: "name" }, order: "DESC" })).toEqual({ + name: "DESC", + }); + }); + + it("supports custom sort options (any string value)", () => { + expect(transformSortGraphQL({ sortBy: { value: "best_seller_rank" } as any })).toEqual({ + best_seller_rank: "ASC", + }); + }); +}); + +describe("transformFilterValueGraphQL", () => { + it("EQUAL → { eq: value }", () => { + expect(transformFilterValueGraphQL("ABC", "EQUAL")).toEqual({ eq: "ABC" }); + }); + + it("MATCH → { match: value }", () => { + expect(transformFilterValueGraphQL("foo bar", "MATCH")).toEqual({ + match: "foo bar", + }); + }); + + it("RANGE → { from, to } split on the FIRST underscore", () => { + expect(transformFilterValueGraphQL("10_50", "RANGE")).toEqual({ + from: "10", + to: "50", + }); + }); + + it("RANGE with multi-underscore value: only first underscore splits", () => { + // Magento's URL param `price=10_50_extra` is unusual but pinned + // to substring(0, idx) + substring(idx+1) which keeps the trailing + // underscore on the `to` side. + expect(transformFilterValueGraphQL("10_50_extra", "RANGE")).toEqual({ + from: "10", + to: "50_extra", + }); + }); +}); + +describe("filtersFromUrlGraphQL", () => { + it("picks up known filter keys from URL searchParams", () => { + const url = new URL("https://x.test/?sku=ABC&color=red&unknown=zzz"); + expect(filtersFromUrlGraphQL(url)).toEqual({ + sku: { eq: "ABC" }, + color: { eq: "red" }, + }); + }); + + it("handles RANGE filters (price)", () => { + const url = new URL("https://x.test/?price=10_50"); + expect(filtersFromUrlGraphQL(url)).toEqual({ + price: { from: "10", to: "50" }, + }); + }); + + it("handles MATCH filters (name, description)", () => { + const url = new URL("https://x.test/?name=foo+bar"); + expect(filtersFromUrlGraphQL(url)).toEqual({ + name: { match: "foo bar" }, + }); + }); + + it("layers customFilters on top of defaults", () => { + const url = new URL("https://x.test/?tag__phebo=fragrancia&sku=X"); + expect(filtersFromUrlGraphQL(url, [{ value: "tag__phebo", type: "EQUAL" }])).toEqual({ + tag__phebo: { eq: "fragrancia" }, + sku: { eq: "X" }, + }); + }); + + it("returns empty object when no filterable param is set", () => { + expect(filtersFromUrlGraphQL(new URL("https://x.test/?totally=other"))).toEqual({}); + }); +}); + +describe("filtersFromLoaderGraphQL", () => { + it("returns empty object when undefined", () => { + expect(filtersFromLoaderGraphQL(undefined)).toEqual({}); + }); + + it("collapses array of FilterProps into a keyed object", () => { + expect( + filtersFromLoaderGraphQL([ + { name: "sku", type: { eq: "A" } }, + { name: "color", type: { in: ["red", "blue"] } }, + ]), + ).toEqual({ + sku: { eq: "A" }, + color: { in: ["red", "blue"] }, + }); + }); +}); + +describe("transformFilterGraphQL — merge order", () => { + it("loader-derived filters override URL-derived ones on key collisions", () => { + // A section hard-coding `sale=true` should ignore any conflicting URL hint. + const url = new URL("https://x.test/?sale=false"); + expect( + transformFilterGraphQL(url, undefined, [{ name: "sale", type: { eq: "true" } }]), + ).toEqual({ + sale: { eq: "true" }, + }); + }); + + it("non-colliding sources merge cleanly", () => { + const url = new URL("https://x.test/?sku=ABC"); + expect( + transformFilterGraphQL(url, undefined, [{ name: "category_id", type: { eq: "42" } }]), + ).toEqual({ + sku: { eq: "ABC" }, + category_id: { eq: "42" }, + }); + }); +}); + +describe("formatUrlSuffix", () => { + it("strips a single leading slash", () => { + expect(formatUrlSuffix("/granado/")).toBe("granado/"); + }); + + it("appends trailing slash when missing", () => { + expect(formatUrlSuffix("granado")).toBe("granado/"); + }); + + it("leaves trailing slash alone", () => { + expect(formatUrlSuffix("granado/")).toBe("granado/"); + }); +}); + +describe("getCustomFields", () => { + it("returns undefined when active=false", () => { + expect(getCustomFields({ active: false }, ["a", "b"])).toBeUndefined(); + }); + + it("returns overrideList when present (ignores fallback)", () => { + expect(getCustomFields({ active: true, overrideList: ["x", "y"] }, ["a", "b"])).toEqual([ + "x", + "y", + ]); + }); + + it("falls back to provided customFields when overrideList is empty/absent", () => { + expect(getCustomFields({ active: true, overrideList: [] }, ["a", "b"])).toEqual(["a", "b"]); + expect(getCustomFields({ active: true }, ["a", "b"])).toEqual(["a", "b"]); + }); + + it("defaults config to {active:false} when omitted", () => { + expect(getCustomFields(undefined, ["a"])).toBeUndefined(); + }); +}); diff --git a/magento/__tests__/newsletter-subscribe.test.ts b/magento/__tests__/newsletter-subscribe.test.ts new file mode 100644 index 0000000..50f7769 --- /dev/null +++ b/magento/__tests__/newsletter-subscribe.test.ts @@ -0,0 +1,86 @@ +/** + * Tests for the newsletter/subscribe action. + * + * Parity with deco-cx/apps/magento/actions/newsletter/subscribe.ts: + * - POSTs to /rest/:site/V1/newsletter/subscribed + * - Body shape: { email, store_id: number } + * - storeId is coerced to number even if the CMS block holds it as string + * - Returns null on non-2xx or when `success === false`, the payload otherwise + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import subscribe from "../actions/newsletter/subscribe"; +import { configureMagento } from "../client"; + +function mockResponse(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +describe("newsletter/subscribe", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 21, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("POSTs to the correct REST path with the encoded site", async () => { + fetchSpy.mockResolvedValue(mockResponse({ success: true, message: "ok" })); + await subscribe({ email: "a@b.com" }); + const [target, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe( + "https://loja.example.com/rest/example/V1/newsletter/subscribed", + ); + expect(init.method).toBe("POST"); + }); + + it("sends { email, store_id (number) } as JSON body", async () => { + fetchSpy.mockResolvedValue(mockResponse({ success: true, message: "ok" })); + await subscribe({ email: "a@b.com" }); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(JSON.parse(init.body as string)).toEqual({ email: "a@b.com", store_id: 21 }); + }); + + it("coerces storeId to number even if config holds a string-shaped value", async () => { + // Some CMS blocks store storeId as a string. The prod loader did + // `Number(storeId)` defensively; we keep that behavior so the + // Magento backend never receives a string for an int field. + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: "42" as unknown as number, + site: "example", + }); + fetchSpy.mockResolvedValue(mockResponse({ success: true, message: "ok" })); + await subscribe({ email: "a@b.com" }); + const [, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(JSON.parse(init.body as string).store_id).toBe(42); + }); + + it("returns the payload on success", async () => { + const payload = { success: true, message: "ok" }; + fetchSpy.mockResolvedValue(mockResponse(payload)); + expect(await subscribe({ email: "a@b.com" })).toEqual(payload); + }); + + it("returns null on success:false (Magento failure shape)", async () => { + fetchSpy.mockResolvedValue(mockResponse({ success: false, message: "no" })); + expect(await subscribe({ email: "a@b.com" })).toBeNull(); + }); + + it("returns null on non-2xx HTTP status", async () => { + fetchSpy.mockResolvedValue(mockResponse(null, 500)); + expect(await subscribe({ email: "a@b.com" })).toBeNull(); + }); +}); diff --git a/magento/__tests__/product-stockAlert.test.ts b/magento/__tests__/product-stockAlert.test.ts new file mode 100644 index 0000000..acd4a8a --- /dev/null +++ b/magento/__tests__/product-stockAlert.test.ts @@ -0,0 +1,80 @@ +/** + * Tests for the product/stockAlert action. + * + * Parity with deco-cx/apps/magento/actions/product/stockAlert.ts: + * - Calls Magento's GraphQL endpoint at /graphql. + * - Sends operationName ProductStockAlert + variables {product_id, name, email}. + * - Returns { data: { productStockAlert } } on success. + * - Returns { error } on thrown exceptions / missing payload. + * + * The legacy code passed a STALE cache hint to clientGraphql.query but + * mutations are never cached server-side, so the TanStack port omits it + * — behavior is observationally identical from a consumer perspective. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import stockAlert from "../actions/product/stockAlert"; +import { configureMagento } from "../client"; + +function mockResponse(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +describe("product/stockAlert", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("POSTs to /graphql with the ProductStockAlert mutation", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + data: { productStockAlert: { message: "ok", status: true } }, + }), + ); + await stockAlert({ product_id: 42, name: "Alice", email: "a@b.com" }); + const [target, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe("https://loja.example.com/graphql"); + expect(init.method).toBe("POST"); + + const body = JSON.parse(init.body as string); + expect(body.operationName).toBe("ProductStockAlert"); + expect(body.variables).toEqual({ product_id: 42, name: "Alice", email: "a@b.com" }); + expect(body.query).toMatch(/mutation ProductStockAlert/); + }); + + it("returns { data: { productStockAlert } } on success", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + data: { productStockAlert: { message: "added", status: true } }, + }), + ); + const out = await stockAlert({ product_id: 1, name: "n", email: "e@e.com" }); + expect(out).toEqual({ data: { productStockAlert: { message: "added", status: true } } }); + }); + + it("returns { error } when the GraphQL response lacks productStockAlert", async () => { + fetchSpy.mockResolvedValue(mockResponse({ data: {} })); + const out = await stockAlert({ product_id: 1, name: "n", email: "e@e.com" }); + expect(out).toHaveProperty("error"); + }); + + it("returns { error } when fetch throws (network error)", async () => { + fetchSpy.mockRejectedValue(new Error("ECONNREFUSED")); + const out = await stockAlert({ product_id: 1, name: "n", email: "e@e.com" }); + expect(out).toEqual({ error: "ECONNREFUSED" }); + }); +}); diff --git a/magento/__tests__/stringifySearchCriteria.test.ts b/magento/__tests__/stringifySearchCriteria.test.ts new file mode 100644 index 0000000..834b02f --- /dev/null +++ b/magento/__tests__/stringifySearchCriteria.test.ts @@ -0,0 +1,56 @@ +/** + * Tests for stringifySearchCriteria. + * + * Parity goal with deco-cx/apps/magento/utils/stringifySearchCriteria.ts + * — the Fresh implementation produces query-string keys that Magento's + * REST API depends on byte-for-byte. These tests pin the exact bracket + * layout so the port can't silently drift from prod. + */ +import { describe, expect, it } from "vitest"; +import stringifySearchCriteria from "../utils/stringifySearchCriteria"; + +describe("stringifySearchCriteria", () => { + it("flattens a top-level scalar field into a bracketed key", () => { + expect( + stringifySearchCriteria({ + pageSize: 20, + }), + ).toEqual({ + "searchCriteria[pageSize]": 20, + }); + }); + + it("flattens nested objects with the [key] path style", () => { + expect( + stringifySearchCriteria({ + filterGroups: [ + { + filters: [{ field: "sku", value: "ABC" }], + }, + ], + }), + ).toEqual({ + "searchCriteria[filterGroups][0][filters][0][field]": "sku", + "searchCriteria[filterGroups][0][filters][0][value]": "ABC", + }); + }); + + it("handles multiple filterGroups (OR semantics in Magento)", () => { + const out = stringifySearchCriteria({ + filterGroups: [ + { filters: [{ field: "sku", value: "A" }] }, + { filters: [{ field: "sku", value: "B" }] }, + ], + }); + expect(out).toEqual({ + "searchCriteria[filterGroups][0][filters][0][field]": "sku", + "searchCriteria[filterGroups][0][filters][0][value]": "A", + "searchCriteria[filterGroups][1][filters][0][field]": "sku", + "searchCriteria[filterGroups][1][filters][0][value]": "B", + }); + }); + + it("returns an empty object for empty input", () => { + expect(stringifySearchCriteria({})).toEqual({}); + }); +}); diff --git a/magento/__tests__/transform.test.ts b/magento/__tests__/transform.test.ts new file mode 100644 index 0000000..006a97f --- /dev/null +++ b/magento/__tests__/transform.test.ts @@ -0,0 +1,346 @@ +/** + * Tests for utils/transform.ts — the schema.org mapping layer. + * + * Parity goals against deco-cx/apps/magento/utils/transform.ts: + * each helper is exercised against the same input shapes the legacy + * code handled and we assert on the same output shapes the storefront + * sections render against. The goal is to keep this file as a + * regression dam so future refactors don't silently shift output + * structure on real consumer sites. + */ +import { describe, expect, it } from "vitest"; +import type { MagentoProduct } from "../utils/client/types"; +import { toBreadcrumbList, toImages, toOffer, toProduct, toSeo, toURL } from "../utils/transform"; + +const baseProduct = (): MagentoProduct => ({ + id: 42, + sku: "SKU-42", + name: "Test Product", + price: 100, + status: 1, + visibility: 4, + type_id: "simple", + created_at: "", + updated_at: "", + weight: 0, + url: "https://loja.example.com/p/test", + extension_attributes: { + category_links: [], + stock_item: { + item_id: 1, + product_id: 42, + stock_id: 1, + is_in_stock: true, + qty: 7, + }, + }, + custom_attributes: [ + { attribute_code: "title", value: "Test Title" }, + { attribute_code: "meta_title", value: "Test Meta Title" }, + { attribute_code: "meta_description", value: "Test Meta Description" }, + ], + currency_code: "BRL", + price_info: { + final_price: 80, + max_price: 100, + max_regular_price: 100, + minimal_regular_price: 100, + special_price: null, + minimal_price: 80, + regular_price: 100, + formatted_prices: { + final_price: "R$ 80,00", + max_price: "R$ 100,00", + minimal_price: "R$ 80,00", + max_regular_price: "R$ 100,00", + minimal_regular_price: null, + special_price: null, + regular_price: "R$ 100,00", + }, + extension_attributes: { + msrp: { + msrp_price: "", + is_applicable: "", + is_shown_price_on_gesture: "", + msrp_message: "", + explanation_message: "", + }, + tax_adjustments: { + final_price: 80, + max_price: 100, + max_regular_price: 100, + minimal_regular_price: 100, + special_price: 80, + minimal_price: 80, + regular_price: 100, + formatted_prices: { + final_price: "R$ 80,00", + max_price: "R$ 100,00", + minimal_price: "R$ 80,00", + max_regular_price: "R$ 100,00", + minimal_regular_price: null, + special_price: "R$ 80,00", + regular_price: "R$ 100,00", + }, + }, + weee_attributes: [], + weee_adjustment: "", + }, + }, +}); + +describe("toURL", () => { + it("promotes protocol-relative URLs to https", () => { + expect(toURL("//cdn.example.com/img.jpg")).toBe("https://cdn.example.com/img.jpg"); + }); + + it("leaves https URLs untouched", () => { + expect(toURL("https://x.com/i.jpg")).toBe("https://x.com/i.jpg"); + }); + + it("leaves http URLs untouched (no upgrade)", () => { + // Prod only promotes the // form; http:// is passed through to match. + expect(toURL("http://x.com/i.jpg")).toBe("http://x.com/i.jpg"); + }); +}); + +describe("toSeo", () => { + it("prefers meta_title over title", () => { + const seo = toSeo( + [ + { attribute_code: "title", value: "A" }, + { attribute_code: "meta_title", value: "B" }, + { attribute_code: "meta_description", value: "D" }, + ], + "https://x.test/p", + ); + expect(seo).toEqual({ title: "B", description: "D", canonical: "https://x.test/p" }); + }); + + it("falls back to title when meta_title is absent", () => { + const seo = toSeo([{ attribute_code: "title", value: "A" }], "https://x.test/p"); + expect(seo.title).toBe("A"); + }); + + it("returns empty title/description when neither attr is present", () => { + const seo = toSeo([], "https://x.test/p"); + expect(seo).toEqual({ title: "", description: "", canonical: "https://x.test/p" }); + }); + + it("joins string-array attribute values with comma+space", () => { + const seo = toSeo( + [{ attribute_code: "meta_description", value: ["a", "b", "c"] }], + "https://x.test/p", + ); + expect(seo.description).toBe("a, b, c"); + }); +}); + +describe("toOffer", () => { + it("returns [] when price_info is absent", () => { + const p = baseProduct(); + p.price_info = undefined; + expect(toOffer(p, 30, 10)).toEqual([]); + }); + + it("maps InStock availability when stock_item.is_in_stock=true", () => { + const offers = toOffer(baseProduct(), 30, 10); + expect(offers[0].availability).toBe("https://schema.org/InStock"); + expect(offers[0].inventoryLevel).toEqual({ value: 7 }); + }); + + it("maps OutOfStock availability when stock_item.is_in_stock=false", () => { + const p = baseProduct(); + p.extension_attributes.stock_item!.is_in_stock = false; + const offers = toOffer(p, 30, 10); + expect(offers[0].availability).toBe("https://schema.org/OutOfStock"); + expect(offers[0].inventoryLevel).toEqual({ value: 0 }); + }); + + it("emits ListPrice + SalePrice in priceSpecification", () => { + const offers = toOffer(baseProduct(), 30, 10); + const types = (offers[0].priceSpecification ?? []).map((s: any) => s.priceType); + expect(types).toContain("https://schema.org/ListPrice"); + expect(types).toContain("https://schema.org/SalePrice"); + }); + + it("calculates installments capped by maxInstallments AND minInstallmentValue", () => { + // finalPrice 80, minInstallmentValue 30 → floor(80/30) = 2 possible + // maxInstallments 10 → bounded by 2 + const offers = toOffer(baseProduct(), 30, 10); + const installments = (offers[0].priceSpecification ?? []).filter( + (s: any) => s.priceComponentType === "https://schema.org/Installment", + ); + expect(installments.length).toBe(2); + expect((installments[0] as any).description).toBe("À vista"); + expect((installments[1] as any).description).toBe("2x sem juros"); + }); + + it("always emits at least 1 installment (À vista) when finalPrice < minInstallmentValue", () => { + // finalPrice 80, minInstallmentValue 200 → floor = 0 → || 1 + const offers = toOffer(baseProduct(), 200, 10); + const installments = (offers[0].priceSpecification ?? []).filter( + (s: any) => s.priceComponentType === "https://schema.org/Installment", + ); + expect(installments.length).toBe(1); + expect((installments[0] as any).description).toBe("À vista"); + }); +}); + +describe("toImages", () => { + it("maps media_gallery_entries when imagesUrl is provided", () => { + const p = baseProduct(); + p.media_gallery_entries = [ + { + id: 1, + media_type: "image", + label: null, + position: 1, + disabled: false, + types: [], + file: "/x/y.jpg", + }, + ]; + const imgs = toImages(p, "https://cdn.example/media"); + expect(imgs).toEqual([ + { + "@type": "ImageObject", + encodingFormat: "image", + alternateName: "/x/y.jpg", + url: "https://cdn.example/media/x/y.jpg", + disabled: false, + }, + ]); + }); + + it("falls back to `images` when imagesUrl is empty", () => { + const p = baseProduct(); + p.images = [ + { + url: "https://x.test/i.jpg", + code: "image", + height: 1, + width: 1, + label: "x", + resized_width: 1, + resized_height: 1, + disabled: false, + }, + ]; + const imgs = toImages(p, ""); + expect(imgs?.[0]).toMatchObject({ url: "https://x.test/i.jpg", alternateName: "x" }); + }); + + it("promotes // URLs to https via toURL inside the prefix", () => { + const p = baseProduct(); + p.media_gallery_entries = [ + { + id: 1, + media_type: "image", + label: null, + position: 1, + disabled: false, + types: [], + file: "/x.jpg", + }, + ]; + const imgs = toImages(p, "//cdn.example/m"); + expect(imgs?.[0].url).toBe("https://cdn.example/m/x.jpg"); + }); +}); + +describe("toBreadcrumbList", () => { + const PRODUCT_URL = new URL("https://x.test/produto/abc"); + + it("returns a single ListItem with the product name when categories=[] and flag=true", () => { + const out = toBreadcrumbList( + [], + true, + { "@type": "Product", productID: "1", sku: "1", name: "Foo" } as any, + PRODUCT_URL, + ); + expect(out).toEqual([ + { + "@type": "ListItem", + name: "Foo", + position: 1, + item: "https://x.test/Foo", + }, + ]); + }); + + it("maps each valid category to a ListItem ordered by position", () => { + const out = toBreadcrumbList( + [{ id: 1, name: "A", position: 1 } as any, { id: 2, name: "B", position: 2 } as any], + false, + { name: "Foo" } as any, + PRODUCT_URL, + ); + expect(out).toEqual([ + { "@type": "ListItem", name: "A", position: 1, item: "https://x.test/A" }, + { "@type": "ListItem", name: "B", position: 2, item: "https://x.test/B" }, + ]); + }); + + it("filters out null/empty-name/zero-position categories", () => { + const out = toBreadcrumbList( + [ + null, + { id: 1, name: "", position: 1 } as any, + { id: 2, name: "B", position: 0 } as any, + { id: 3, name: "C", position: 3 } as any, + ], + false, + { name: "Foo" } as any, + PRODUCT_URL, + ); + expect(out).toEqual([ + { "@type": "ListItem", name: "C", position: 3, item: "https://x.test/C" }, + ]); + }); +}); + +describe("toProduct", () => { + it("maps a base product into a schema.org Product with offers, image, additionalProperty", () => { + const out = toProduct({ + product: baseProduct(), + options: { + currencyCode: "BRL", + imagesUrl: "", + maxInstallments: 10, + minInstallmentValue: 30, + }, + }); + + expect(out["@type"]).toBe("Product"); + expect(out.productID).toBe("42"); + expect(out.sku).toBe("SKU-42"); + expect(out.name).toBe("Test Product"); + expect(out.url).toBe("https://loja.example.com/p/test"); + expect((out.offers as any).highPrice).toBe(100); + expect((out.offers as any).lowPrice).toBe(80); + expect(out.additionalProperty?.length).toBe(3); + }); + + it("wraps the product in isVariantOf with the same productID", () => { + const out = toProduct({ + product: baseProduct(), + options: { maxInstallments: 10, minInstallmentValue: 30 }, + }); + expect(out.isVariantOf?.productGroupID).toBe("42"); + expect(out.isVariantOf?.hasVariant?.[0].productID).toBe("42"); + }); + + it("falls back to product.price when price_info is absent for highPrice/lowPrice", () => { + const p = baseProduct(); + p.price_info = undefined; + const out = toProduct({ + product: p, + options: { maxInstallments: 10, minInstallmentValue: 30 }, + }); + expect((out.offers as any).highPrice).toBe(100); + expect((out.offers as any).lowPrice).toBe(100); + // And offers array is empty when price_info is absent (toOffer returns []) + expect((out.offers as any).offerCount).toBe(0); + }); +}); diff --git a/magento/__tests__/user-loader.test.ts b/magento/__tests__/user-loader.test.ts new file mode 100644 index 0000000..2226a88 --- /dev/null +++ b/magento/__tests__/user-loader.test.ts @@ -0,0 +1,134 @@ +/** + * Tests for the user loader. + * + * Parity goals against deco-cx/apps/magento/loaders/user.ts: + * - Returns null when no PHPSESSID cookie is present (anonymous). + * - Calls /customer/section/load?sections=customer,carbono-customer + * with the Cookie header set from PHPSESSID. + * - Maps the bundle into schema.org Person { @id, email, givenName, + * familyName? }. + * - Derives familyName by stripping firstname from fullname (matches + * prod's `fullname.replace(firstname, "").trim()`). + * - Returns null when carbono-customer.data_id is missing OR when + * customer slice is absent. + * - Swallows fetch errors and returns null (the storefront re-renders + * the logged-out UI rather than crashing). + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { configureMagento } from "../client"; +import user from "../loaders/user"; + +function mockResponse(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +function requestWithCookie(cookie: string): Request { + const r = new Request("http://localhost/"); + const headers = new Headers(); + headers.set("cookie", cookie); + Object.defineProperty(r, "headers", { value: headers, configurable: true }); + return r; +} + +describe("user loader", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("returns null when no PHPSESSID cookie is present", async () => { + const result = await user(null, new Request("http://localhost/")); + expect(result).toBeNull(); + expect(fetchSpy).not.toHaveBeenCalled(); + }); + + it("requests /customer/section/load with the Cookie header", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + customer: { data_id: 1, fullname: "Alice Doe", firstname: "Alice" }, + "carbono-customer": { data_id: 1, customerId: "c1", email: "a@b.com" }, + }), + ); + await user(null, requestWithCookie("PHPSESSID=abc")); + const [target, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe( + "https://loja.example.com/example/customer/section/load?sections=customer,carbono-customer", + ); + const cookieHeader = new Headers(init.headers).get("cookie"); + expect(cookieHeader).toBe("PHPSESSID=abc"); + }); + + it("maps a happy-path bundle into a schema.org Person", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + customer: { data_id: 1, fullname: "Alice Doe", firstname: "Alice" }, + "carbono-customer": { data_id: 1, customerId: "c1", email: "a@b.com" }, + }), + ); + const out = await user(null, requestWithCookie("PHPSESSID=abc")); + expect(out).toEqual({ + "@id": "c1", + email: "a@b.com", + givenName: "Alice", + familyName: "Doe", + }); + }); + + it("omits familyName when fullname is just firstname (no surname)", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + customer: { data_id: 1, fullname: "Alice", firstname: "Alice" }, + "carbono-customer": { data_id: 1, customerId: "c1", email: "a@b.com" }, + }), + ); + const out = await user(null, requestWithCookie("PHPSESSID=abc")); + expect(out).toMatchObject({ givenName: "Alice" }); + // Magento returns fullname=firstname; prod's `replace(firstname, "").trim()` + // yields "" — we include the key with an empty string. Test the + // surface, not the empty-vs-missing detail. + expect(out?.familyName ?? "").toBe(""); + }); + + it("returns null when carbono-customer.data_id is missing", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + customer: { data_id: 1, fullname: "Alice Doe", firstname: "Alice" }, + "carbono-customer": { customerId: "c1", email: "a@b.com" }, // no data_id + }), + ); + expect(await user(null, requestWithCookie("PHPSESSID=abc"))).toBeNull(); + }); + + it("returns null when customer slice is absent", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + "carbono-customer": { data_id: 1, customerId: "c1", email: "a@b.com" }, + }), + ); + expect(await user(null, requestWithCookie("PHPSESSID=abc"))).toBeNull(); + }); + + it("returns null when fetch throws", async () => { + fetchSpy.mockRejectedValue(new Error("ECONNREFUSED")); + expect(await user(null, requestWithCookie("PHPSESSID=abc"))).toBeNull(); + }); + + it("returns null on non-2xx response", async () => { + fetchSpy.mockResolvedValue(mockResponse(null, 500)); + expect(await user(null, requestWithCookie("PHPSESSID=abc"))).toBeNull(); + }); +}); diff --git a/magento/__tests__/wishlist-actions.test.ts b/magento/__tests__/wishlist-actions.test.ts new file mode 100644 index 0000000..d61ccb9 --- /dev/null +++ b/magento/__tests__/wishlist-actions.test.ts @@ -0,0 +1,140 @@ +/** + * Tests for the wishlist add/remove actions. + * + * Parity goals against deco-cx/apps/magento/actions/wishlist/{addItem,removeItem}: + * - Both require PHPSESSID + form_key cookies; return null when either absent. + * - addItem POSTs FormData {product, form_key} to /wishlist/index/add/. + * - removeItem POSTs FormData {item, uenc:"", form_key} to /wishlist/index/remove/. + * - On success ({success:true}) both delegate to the wishlist loader to + * fetch the refreshed list. + * - Failure / thrown / success:false → null. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import addItem from "../actions/wishlist/addItem"; +import removeItem from "../actions/wishlist/removeItem"; +import { configureMagento } from "../client"; + +function mockResponse(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +function requestWithCookies(cookieHeader: string): Request { + const r = new Request("http://localhost/"); + const headers = new Headers(); + headers.set("cookie", cookieHeader); + Object.defineProperty(r, "headers", { value: headers, configurable: true }); + return r; +} + +const AUTHED = "PHPSESSID=abc; form_key=xyz"; + +describe("wishlist/addItem", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => vi.restoreAllMocks()); + + it("returns null when PHPSESSID is missing", async () => { + expect(await addItem({ productId: "1" }, requestWithCookies("form_key=xyz"))).toBeNull(); + }); + + it("returns null when form_key is missing", async () => { + expect(await addItem({ productId: "1" }, requestWithCookies("PHPSESSID=abc"))).toBeNull(); + }); + + it("POSTs FormData {product, form_key} to /wishlist/index/add/", async () => { + fetchSpy + .mockResolvedValueOnce(mockResponse({ success: true })) // POST add + .mockResolvedValueOnce( + mockResponse({ + wishlist: { counter: "1", items: [], counter_number: 1, data_id: 1 }, + }), + ); // wishlist loader fetch + + await addItem({ productId: "p42" }, requestWithCookies(AUTHED)); + + const [target, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe("https://loja.example.com/example/wishlist/index/add/"); + expect(init.method).toBe("POST"); + + const fd = init.body as FormData; + expect(fd.get("product")).toBe("p42"); + expect(fd.get("form_key")).toBe("xyz"); + }); + + it("delegates to the wishlist loader on success", async () => { + const wl = { counter: "1", items: [], counter_number: 1, data_id: 1 }; + fetchSpy + .mockResolvedValueOnce(mockResponse({ success: true })) + .mockResolvedValueOnce(mockResponse({ wishlist: wl })); + + expect(await addItem({ productId: "p42" }, requestWithCookies(AUTHED))).toEqual(wl); + }); + + it("returns null when Magento responds with success:false", async () => { + fetchSpy.mockResolvedValueOnce(mockResponse({ success: false })); + expect(await addItem({ productId: "p42" }, requestWithCookies(AUTHED))).toBeNull(); + }); + + it("returns null on a thrown fetch", async () => { + fetchSpy.mockRejectedValueOnce(new Error("boom")); + expect(await addItem({ productId: "p42" }, requestWithCookies(AUTHED))).toBeNull(); + }); +}); + +describe("wishlist/removeItem", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => vi.restoreAllMocks()); + + it("POSTs FormData {item, uenc:'', form_key} to /wishlist/index/remove/", async () => { + fetchSpy.mockResolvedValueOnce(mockResponse({ success: true })).mockResolvedValueOnce( + mockResponse({ + wishlist: { counter: "0", items: [], counter_number: 0, data_id: 1 }, + }), + ); + + await removeItem({ productId: "row-42" }, requestWithCookies(AUTHED)); + + const [target, init] = fetchSpy.mock.calls[0] as [URL, RequestInit]; + expect(target.toString()).toBe("https://loja.example.com/example/wishlist/index/remove/"); + const fd = init.body as FormData; + expect(fd.get("item")).toBe("row-42"); + expect(fd.get("uenc")).toBe(""); + expect(fd.get("form_key")).toBe("xyz"); + }); + + it("returns the refreshed wishlist on success", async () => { + const wl = { counter: "0", items: [], counter_number: 0, data_id: 1 }; + fetchSpy + .mockResolvedValueOnce(mockResponse({ success: true })) + .mockResolvedValueOnce(mockResponse({ wishlist: wl })); + expect(await removeItem({ productId: "row-42" }, requestWithCookies(AUTHED))).toEqual(wl); + }); + + it("returns null when PHPSESSID is missing", async () => { + expect(await removeItem({ productId: "x" }, requestWithCookies("form_key=xyz"))).toBeNull(); + }); +}); diff --git a/magento/__tests__/wishlist-loader.test.ts b/magento/__tests__/wishlist-loader.test.ts new file mode 100644 index 0000000..6ffa6eb --- /dev/null +++ b/magento/__tests__/wishlist-loader.test.ts @@ -0,0 +1,97 @@ +/** + * Tests for the wishlist loader. + * + * Parity goals against deco-cx/apps/magento/loaders/wishlist.ts: + * - Returns null when no PHPSESSID (anonymous). + * - Hits /customer/section/load?sections=wishlist with the Cookie header. + * - Returns the wishlist payload directly when present. + * - Returns null when the bundle has no wishlist slice. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { configureMagento } from "../client"; +import wishlist from "../loaders/wishlist"; + +function mockResponse(body: unknown, status = 200): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +function requestWithCookie(cookie: string): Request { + const r = new Request("http://localhost/"); + const headers = new Headers(); + headers.set("cookie", cookie); + Object.defineProperty(r, "headers", { value: headers, configurable: true }); + return r; +} + +describe("wishlist loader", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + configureMagento({ + baseUrl: "https://loja.example.com/", + apiKey: "secret", + storeId: 1, + site: "example", + }); + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("returns null when no PHPSESSID cookie is present", async () => { + expect(await wishlist(null, new Request("http://localhost/"))).toBeNull(); + expect(fetchSpy).not.toHaveBeenCalled(); + }); + + it("requests /customer/section/load?sections=wishlist", async () => { + fetchSpy.mockResolvedValue( + mockResponse({ + wishlist: { counter: "0", items: [], counter_number: 0, data_id: 1 }, + }), + ); + await wishlist(null, requestWithCookie("PHPSESSID=abc")); + const [target] = fetchSpy.mock.calls[0] as [URL]; + expect(target.toString()).toBe( + "https://loja.example.com/example/customer/section/load?sections=wishlist", + ); + }); + + it("returns the wishlist payload on success", async () => { + const wl = { + counter: "1", + counter_number: 1, + data_id: 1, + items: [ + { + image: { template: "", src: "", width: 0, height: 0, alt: "" }, + product_sku: "ABC", + product_id: "1", + product_url: "", + product_name: "n", + product_price: "10", + product_is_saleable_and_visible: true, + product_has_required_options: false, + add_to_cart_params: "", + delete_item_params: "", + }, + ], + }; + fetchSpy.mockResolvedValue(mockResponse({ wishlist: wl })); + expect(await wishlist(null, requestWithCookie("PHPSESSID=abc"))).toEqual(wl); + }); + + it("returns null when bundle lacks a wishlist slice", async () => { + fetchSpy.mockResolvedValue(mockResponse({})); + expect(await wishlist(null, requestWithCookie("PHPSESSID=abc"))).toBeNull(); + }); + + it("returns null on non-2xx response", async () => { + fetchSpy.mockResolvedValue(mockResponse(null, 500)); + expect(await wishlist(null, requestWithCookie("PHPSESSID=abc"))).toBeNull(); + }); +}); diff --git a/magento/actions/newsletter/subscribe.ts b/magento/actions/newsletter/subscribe.ts new file mode 100644 index 0000000..a09cf67 --- /dev/null +++ b/magento/actions/newsletter/subscribe.ts @@ -0,0 +1,40 @@ +/** + * Magento newsletter subscribe — POST a customer email to the + * `/V1/newsletter/subscribed` REST endpoint. + * + * Verbatim port of `deco-cx/apps/magento/actions/newsletter/subscribe.ts`: + * the legacy version took `(props, _req, ctx)` and pulled `storeId` / + * `clientAdmin` / `site` off the App() context. The TanStack/Node port + * reads the same fields from `getMagentoConfig()` and uses + * `magentoFetch` so auth/origin/Referer headers stay aligned with the + * rest of the magento app. Endpoint shape and request body are + * unchanged so the Magento backend doesn't need re-tuning. + */ +import { getMagentoConfig, magentoFetch } from "../../client"; +import type { NewsletterData } from "../../types"; + +export interface SubscribeProps { + /** + * @title Email + */ + email: string; +} + +export default async function subscribe(props: SubscribeProps): Promise { + const { site, storeId } = getMagentoConfig(); + const path = `/rest/${encodeURIComponent(site)}/V1/newsletter/subscribed`; + + const res = await magentoFetch(path, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + email: props.email, + store_id: Number(storeId), + }), + }); + + if (!res.ok) return null; + const result = (await res.json()) as NewsletterData | { success: false }; + if (!result || (result as NewsletterData).success === false) return null; + return result as NewsletterData; +} diff --git a/magento/actions/product/stockAlert.ts b/magento/actions/product/stockAlert.ts new file mode 100644 index 0000000..e2e5af2 --- /dev/null +++ b/magento/actions/product/stockAlert.ts @@ -0,0 +1,67 @@ +/** + * Magento product stock-alert subscribe — fires a GraphQL mutation so + * the customer gets notified when an out-of-stock SKU is replenished. + * + * Verbatim port of `deco-cx/apps/magento/actions/product/stockAlert.ts`. + * The Fresh version called `ctx.clientGraphql.query(...)` with a third + * `STALE` parameter that opted into a 1h SWR cache. The TanStack/Node + * port uses `magentoFetch` against `/graphql` directly; STALE was a + * cache hint only — the mutation is a write so no caching applies and + * we can drop the parameter (the original passed it but mutations are + * never cached server-side, so the behavior is identical). + * + * Response shape preserved: returns `{ data: { productStockAlert } }` + * on success or `{ error: string }` on failure. + */ +import { getMagentoConfig, magentoFetch } from "../../client"; +import type { ProductStockAlertResponse } from "../../types"; + +export interface StockAlertProps { + product_id: number; + name: string; + email: string; +} + +const MUTATION = `mutation ProductStockAlert($product_id: Int!, $name: String!, $email: String!) { + productStockAlert( + product_id: $product_id + name: $name + email: $email + ) { + message + status + } +}`; + +export default async function stockAlert( + props: StockAlertProps, +): Promise { + const { product_id, name, email } = props; + const { baseUrl } = getMagentoConfig(); + + try { + const res = await magentoFetch(`${baseUrl.replace(/\/$/, "")}/graphql`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + operationName: "ProductStockAlert", + variables: { product_id, name, email }, + query: MUTATION, + }), + }); + + const json = (await res.json()) as { + data?: { productStockAlert: { message: string; status: boolean } }; + }; + + if (!json.data?.productStockAlert) { + return { error: "productStockAlert payload missing in GraphQL response" }; + } + + return { data: { productStockAlert: json.data.productStockAlert } }; + } catch (error) { + return { + error: error instanceof Error ? error.message : "Erro desconhecido", + }; + } +} diff --git a/magento/actions/wishlist/addItem.ts b/magento/actions/wishlist/addItem.ts new file mode 100644 index 0000000..68b9d41 --- /dev/null +++ b/magento/actions/wishlist/addItem.ts @@ -0,0 +1,57 @@ +/** + * Adds a product to the customer's wishlist and returns the refreshed + * wishlist on success (or null on failure). + * + * Ported from `deco-cx/apps/magento/actions/wishlist/addItem.ts`. The + * Fresh version posted multipart FormData with `product` + `form_key` + * to `/wishlist/index/add/` and on success delegated to + * wishlistLoader to fetch the updated state. Same flow here — but the + * wishlistLoader is imported from the upstream port instead of the + * legacy in-site path. + */ +import { getCookies } from "@decocms/start/sdk/cookie"; +import { getMagentoConfig, magentoFetch } from "../../client"; +import wishlistLoader from "../../loaders/wishlist"; +import type { Wishlist } from "../../utils/client/types"; +import { FORM_KEY_COOKIE, SESSION_COOKIE } from "../../utils/constants"; +import { getUserCookie } from "../../utils/user"; + +export interface AddWishlistItemProps { + productId: string; +} + +export default async function addItem( + { productId }: AddWishlistItemProps, + req: Request, +): Promise { + try { + const sessionId = getUserCookie(req.headers); + if (!sessionId) return null; + + const cookies = getCookies(req.headers); + const formKey = cookies[FORM_KEY_COOKIE]; + if (!formKey) return null; + + const { site } = getMagentoConfig(); + const body = new FormData(); + body.append("product", productId); + body.append("form_key", formKey); + + const res = await magentoFetch(`/${encodeURIComponent(site)}/wishlist/index/add/`, { + method: "POST", + headers: { + Cookie: `${SESSION_COOKIE}=${sessionId}`, + "x-requested-with": "XMLHttpRequest", + }, + body, + }); + + if (!res.ok) return null; + const { success } = (await res.json()) as { success?: boolean }; + if (!success) return null; + + return wishlistLoader(null, req); + } catch { + return null; + } +} diff --git a/magento/actions/wishlist/removeItem.ts b/magento/actions/wishlist/removeItem.ts new file mode 100644 index 0000000..1f6df55 --- /dev/null +++ b/magento/actions/wishlist/removeItem.ts @@ -0,0 +1,59 @@ +/** + * Removes a wishlist item by its Magento item id and returns the + * refreshed wishlist on success (or null on failure). + * + * Ported from `deco-cx/apps/magento/actions/wishlist/removeItem.ts`. + * The legacy code also passed an empty `uenc=""` form param — kept + * here byte-for-byte because Magento's wishlist controller treats the + * absence of `uenc` differently from an empty value and we don't want + * a silent behavior shift. + */ +import { getCookies } from "@decocms/start/sdk/cookie"; +import { getMagentoConfig, magentoFetch } from "../../client"; +import wishlistLoader from "../../loaders/wishlist"; +import type { Wishlist } from "../../utils/client/types"; +import { FORM_KEY_COOKIE, SESSION_COOKIE } from "../../utils/constants"; +import { getUserCookie } from "../../utils/user"; + +export interface RemoveWishlistItemProps { + /** Magento wishlist item id (NOT the product id — the wishlist row id) */ + productId: string; +} + +export default async function removeItem( + { productId }: RemoveWishlistItemProps, + req: Request, +): Promise { + try { + const sessionId = getUserCookie(req.headers); + if (!sessionId) return null; + + const cookies = getCookies(req.headers); + const formKey = cookies[FORM_KEY_COOKIE]; + if (!formKey) return null; + + const { site } = getMagentoConfig(); + const body = new FormData(); + body.append("item", productId); + body.append("uenc", ""); + body.append("form_key", formKey); + + const res = await magentoFetch(`/${encodeURIComponent(site)}/wishlist/index/remove/`, { + method: "POST", + headers: { + Cookie: `${SESSION_COOKIE}=${sessionId}`, + "x-requested-with": "XMLHttpRequest", + "Content-Type": "application/x-www-form-urlencoded", + }, + body, + }); + + if (!res.ok) return null; + const { success } = (await res.json()) as { success?: boolean }; + if (!success) return null; + + return wishlistLoader(null, req); + } catch { + return null; + } +} diff --git a/magento/client.ts b/magento/client.ts new file mode 100644 index 0000000..5496828 --- /dev/null +++ b/magento/client.ts @@ -0,0 +1,228 @@ +/** + * Magento API client config — module-global, set once at app boot. + * + * Mirrors `vtex/client.ts`'s configureVtex/getVtexConfig pattern so the + * same wiring contract works across commerce apps. Sites should call + * `configureMagento(...)` once from their setup phase before any + * loader/action runs; loaders consume `getMagentoConfig()` to pick up + * baseUrl, auth, and feature toggles. + * + * Two reasons we don't pass config explicitly to every loader: + * 1. CMS-resolved loader instances don't know where the config block + * lives; the site's `initMagentoFromBlocks(blocks)` adapter is the + * single source of truth. + * 2. Matches the rest of @decocms/apps so a site touching VTEX and + * Magento has consistent muscle memory. + */ + +// --------------------------------------------------------------------------- +// Config shapes +// --------------------------------------------------------------------------- + +/** + * URL-search-param filter mapping consumed by GraphQL product loaders. + * Each entry pairs a Magento attribute slug (`value`) with the + * comparison operator the storefront's URL filters use (`type`). The + * default mapping lives in `utils/constants.ts:DEFAULT_GRAPHQL_FILTERS`; + * sites extend it via the `customFilters` prop on PLP/list loaders. + */ +export interface FiltersGraphQL { + value: string; + type: "EQUAL" | "MATCH" | "RANGE"; +} + +export interface MagentoFeatures { + dangerouslyDisableWishlist?: boolean; + dangerouslyDisableOnLoadUpdate?: boolean; + dangerouslyReturnNullAfterAction?: boolean; + dangerouslyDontReturnCartAfterAction?: boolean; + dangerouslyDisableOnVisibilityChangeUpdate?: boolean; +} + +export interface MagentoImagesConfig { + imagesQtd: number; + imagesUrl: string; +} + +export interface MagentoPricingConfig { + maxInstallments: number; + minInstallmentValue: number; +} + +export interface MagentoCartConfigs { + countProductImageInCart?: number; + changeCardIdAfterCheckout?: boolean; + cartErrorMessages?: string[]; +} + +export interface MagentoConfig { + /** Magento storefront base URL, e.g. `https://loja.granado.com.br/` */ + baseUrl: string; + /** Bearer token for `Authorization` header on admin REST calls */ + apiKey: string; + /** Store ID used in headers + path prefixes */ + storeId: number; + /** Site/site-code used in path segments */ + site: string; + /** Which Store header to send (default: "site") */ + storeHeader?: string; + /** Optional opaque header value sent as `x-origin-header` */ + originHeader?: string; + /** Currency code (e.g. "BRL") */ + currencyCode?: string; + /** Whether to append `_suffix` to admin endpoints */ + useSuffix?: boolean; + /** Behavior toggles surfaced to client hooks */ + features?: MagentoFeatures; + /** Cart-specific tunables */ + cartConfigs?: MagentoCartConfigs; + /** Images CDN config */ + imagesConfig?: MagentoImagesConfig; + /** Pricing rules for installments display */ + pricingConfig?: MagentoPricingConfig; +} + +// --------------------------------------------------------------------------- +// Module-global state +// --------------------------------------------------------------------------- + +let config: MagentoConfig | null = null; + +export function configureMagento(c: MagentoConfig): void { + config = c; +} + +export function getMagentoConfig(): MagentoConfig { + if (!config) { + throw new Error( + "[Magento] configureMagento() must be called before loaders run. " + + "Wire it in your site's setup, e.g. configureMagento(blocks.magento).", + ); + } + return config; +} + +/** + * Best-effort init from a CMS block — mirrors `initVtexFromBlocks`. + * + * Resolves secret references stored in the CMS block (`apiKey`, + * `originHeader`) in this priority: + * 1. Plain string (dev override) + * 2. `{ get: () => string }` object (legacy) + * 3. `{ encrypted: "" }` decrypted via `DECO_CRYPTO_KEY` (prod) + * 4. `{ name: "ENV_VAR" }` → `process.env[name]` (fallback) + * + * (3) is what the production Deco CMS actually stores — admin + * encrypts the secret with the site's `DECO_CRYPTO_KEY` so the value + * never leaves the worker in plain text. Previously this init only + * read `process.env[name]`, which silently produced `apiKey: ""` for + * any site that hadn't *also* set the named env var as a CF Worker + * secret. Result: `Authorization: Bearer ` header missing on every + * request → Magento 401 → minicart/cart-related loaders dead. The + * shared `resolveSecret` helper from `@decocms/start/sdk/crypto` + * handles the full chain, matching how VTEX and Shopify configure + * themselves. + * + * Because the AES-CBC decrypt step is async, this function is now + * `Promise` — site setups must `await` the call before any + * loader fires. + */ +export async function initMagentoFromBlocks(blocks: Record): Promise { + // Lazy-imported to keep `@decocms/start/sdk/crypto` out of the + // import graph for sites that wire Magento manually via + // `configureMagento({ apiKey: "..." })` without ever calling this + // helper (e.g. unit tests, CLI tools). + const { resolveSecret } = await import("@decocms/start/sdk/crypto"); + + const block = blocks.magento as Record | undefined; + if (!block) { + console.warn("[Magento] No `magento` block found in CMS; skipping init."); + return; + } + + const apiConfig = block.apiConfig ?? {}; + + // The env-var fallback names match the Secret block's `name` field + // when present. `resolveSecret` cycles through the chain documented + // above; an empty string here means every layer was empty, which we + // pass through verbatim so `buildHeaders` can detect it. + const extractEnvName = (value: unknown): string => { + if (value && typeof value === "object") { + const name = (value as { name?: unknown }).name; + if (typeof name === "string") return name; + } + return ""; + }; + const apiKeyEnvName = extractEnvName(apiConfig.apiKey); + const originHeaderEnvName = extractEnvName(apiConfig.originHeader); + + const apiKey = (await resolveSecret(apiConfig.apiKey, apiKeyEnvName)) ?? ""; + const originHeader = (await resolveSecret(apiConfig.originHeader, originHeaderEnvName)) ?? ""; + + configureMagento({ + baseUrl: apiConfig.baseUrl ?? "", + apiKey, + storeId: apiConfig.storeId ?? 1, + site: apiConfig.site ?? "", + storeHeader: apiConfig.storeHeader, + originHeader, + currencyCode: apiConfig.currencyCode, + useSuffix: apiConfig.useSuffix, + features: block.features, + cartConfigs: block.cartConfigs, + imagesConfig: block.imagesConfig, + pricingConfig: block.pricingConfig, + }); +} + +// --------------------------------------------------------------------------- +// HTTP helpers (thin wrappers over fetch with auth pre-applied) +// --------------------------------------------------------------------------- + +export interface MagentoFetchOpts extends RequestInit { + /** Whether to attach the admin Bearer token. Default true. */ + authenticated?: boolean; +} + +function buildHeaders( + opts: MagentoFetchOpts, + c: MagentoConfig, + attachMagentoIdentity: boolean, +): Headers { + const headers = new Headers(opts.headers ?? {}); + // `attachMagentoIdentity` is false when the request is going to a host + // that isn't the configured Magento backend. None of the Magento-only + // headers below should leak in that case: the Bearer is privileged, the + // `x-origin-header` is a secret that third parties shouldn't see, and a + // forced `Referer` would broadcast our Magento storefront URL. + if (!attachMagentoIdentity) return headers; + + if (opts.authenticated !== false && c.apiKey) { + headers.set("Authorization", `Bearer ${c.apiKey}`); + } + if (c.originHeader) { + headers.set("x-origin-header", c.originHeader); + } + if (!headers.has("Referer")) { + headers.set("Referer", c.baseUrl); + } + return headers; +} + +export function magentoFetch(path: string, opts: MagentoFetchOpts = {}): Promise { + const c = getMagentoConfig(); + const baseUrl = new URL(c.baseUrl); + const target = path.startsWith("http") + ? new URL(path) + : new URL(path.startsWith("/") ? path : `/${path}`, baseUrl); + + // Only attach Magento identity (Bearer, x-origin-header, forced Referer) + // when the request is going to the configured Magento host. An absolute + // URL to a different origin would otherwise leak the admin token *and* + // our origin/Referer secrets to that third party. Callers that genuinely + // want a third-party call must still pass `authenticated: false` for + // clarity at the call site. + const sameOrigin = target.origin === baseUrl.origin; + + return fetch(target, { ...opts, headers: buildHeaders(opts, c, sameOrigin) }); +} diff --git a/magento/index.ts b/magento/index.ts new file mode 100644 index 0000000..deaf4fe --- /dev/null +++ b/magento/index.ts @@ -0,0 +1,11 @@ +/** + * Magento app entry point for @decocms/apps. + * Re-exports client config + initializer. + * + * For actions/loaders/utils, use sub-path imports: + * import { features } from "@decocms/apps/magento/loaders/features" + * import { cart } from "@decocms/apps/magento/loaders/cart" + * import { magentoFetch } from "@decocms/apps/magento/client" + */ +export * from "./client"; +export type { MagentoCart } from "./types"; diff --git a/magento/loaders/cart.ts b/magento/loaders/cart.ts new file mode 100644 index 0000000..99c3103 --- /dev/null +++ b/magento/loaders/cart.ts @@ -0,0 +1,64 @@ +/** + * Magento cart loader — fetches the customer's active cart by cookie. + * + * Reads the `dataservices_cart_id` cookie from the request, calls the + * Magento admin REST endpoint, and returns the cart payload. Returns + * `null` when no cart cookie is present (anonymous visitor — expected). + * + * This is a minimal port of `deco-cx/apps/magento/loaders/cart.ts`. + * It omits, for now, the image-handling pipeline (`handleCartImages`) + * and the cart-items-with-images transform. Those depend on + * `utils/cache.ts` and `utils/cart.ts` from the original — both + * pending ports (see magento/README.md). + */ +import { getCookies } from "@decocms/start/sdk/cookie"; +import { getMagentoConfig, magentoFetch } from "../client"; +import type { MagentoCart } from "../types"; + +const CART_COOKIE = "dataservices_cart_id"; + +function readCartIdFromCookie(headers: Headers): string | null { + const cookies = getCookies(headers); + const raw = cookies[CART_COOKIE]; + if (!raw) return null; + // Magento sets the cookie as `""` (JSON-encoded). Try to parse; + // fall back to the raw string if it isn't quoted. + try { + const parsed = JSON.parse(raw); + return typeof parsed === "string" ? parsed : raw; + } catch { + return raw; + } +} + +export interface CartLoaderProps { + /** Override the cart id (used by checkout flows that already know it). */ + cartId?: string; +} + +export default async function cart( + props: CartLoaderProps | undefined, + req: Request, +): Promise { + const cartId = props?.cartId ?? readCartIdFromCookie(req.headers); + if (!cartId) return null; + + const { site } = getMagentoConfig(); + // Magento exposes the cart endpoint at /rest/:site/V1/carts/:cartId — the + // /rest/ prefix is mandatory and matches the Fresh/Deno original + // (deco-cx/apps/magento/loaders/cart.ts uses + // clientAdmin["GET /rest/:site/V1/carts/:cartId"]). + // + // cartId comes from the request cookie and is user-controlled. Both + // `site` and `cartId` are URL-encoded so neither can break out of its + // path segment and hit a different endpoint while the privileged + // Bearer token is still attached. + const path = `/rest/${encodeURIComponent(site)}/V1/carts/${encodeURIComponent(cartId)}`; + + const res = await magentoFetch(path); + if (!res.ok) { + if (res.status === 404) return null; // expired/invalid cart cookie + throw new Error(`[Magento] cart loader: ${res.status} ${res.statusText}`); + } + return (await res.json()) as MagentoCart; +} diff --git a/magento/loaders/features.ts b/magento/loaders/features.ts new file mode 100644 index 0000000..455846e --- /dev/null +++ b/magento/loaders/features.ts @@ -0,0 +1,16 @@ +/** + * Magento feature flags — returns the `features` block from the resolved + * Magento config. Sites read this to gate optional client-side behavior + * (cart on-load update, wishlist visibility, on-visibility-change update, + * etc.) without re-deploying. + * + * In the legacy deco-cx/apps shape this lived as a 3-arg loader + * `(_props, _req, ctx) => ctx.features`. The TanStack/Node port uses + * the module-global config set by `configureMagento(...)` instead of a + * per-request ctx, which matches the rest of @decocms/apps. + */ +import { getMagentoConfig, type MagentoFeatures } from "../client"; + +export default function features(): MagentoFeatures { + return getMagentoConfig().features ?? {}; +} diff --git a/magento/loaders/user.ts b/magento/loaders/user.ts new file mode 100644 index 0000000..630dc93 --- /dev/null +++ b/magento/loaders/user.ts @@ -0,0 +1,60 @@ +/** + * Resolves the current customer into a schema.org `Person` from + * Magento's `/customer/section/load?sections=customer,carbono-customer` + * endpoint, scoped by the visitor's PHPSESSID cookie. + * + * Ported from `deco-cx/apps/magento/loaders/user.ts`. The Fresh + * version used `clientAdmin["GET /:site/customer/section/load"]` with + * typed indexed routes — the TanStack/Node port uses `magentoFetch` + * (which already applies auth/origin headers for same-origin) plus an + * explicit `Cookie: PHPSESSID=…` header so Magento associates the + * request with the logged-in customer. + * + * Returns null when: + * - the session cookie is absent (anonymous visitor — expected), + * - the customer slice is missing or has no data_id (Magento returns + * {} for guest sessions), + * - the HTTP call throws or returns a non-2xx (defensive — the + * storefront just renders the logged-out UI). + */ +import type { Person } from "@decocms/apps/commerce/types"; +import { getMagentoConfig, magentoFetch } from "../client"; +import type { CustomerSectionLoad } from "../utils/client/types"; +import { SESSION_COOKIE } from "../utils/constants"; +import { getUserCookie } from "../utils/user"; + +export default async function user(_props: unknown, req: Request): Promise { + const sessionId = getUserCookie(req.headers); + if (!sessionId) return null; + + const { site } = getMagentoConfig(); + const path = `/${encodeURIComponent(site)}/customer/section/load?sections=customer,carbono-customer`; + + try { + const res = await magentoFetch(path, { + headers: { Cookie: `${SESSION_COOKIE}=${sessionId}` }, + }); + if (!res.ok) return null; + + const response = (await res.json()) as CustomerSectionLoad; + const carbono = response["carbono-customer"]; + const customer = response.customer; + + if (!carbono?.data_id || !customer) return null; + + const { customerId, email } = carbono; + const { fullname, firstname } = customer; + + return { + "@id": customerId, + email: email, + givenName: firstname, + ...(firstname && + fullname && { + familyName: fullname.replace(firstname, "").trim(), + }), + }; + } catch { + return null; + } +} diff --git a/magento/loaders/wishlist.ts b/magento/loaders/wishlist.ts new file mode 100644 index 0000000..919cdc4 --- /dev/null +++ b/magento/loaders/wishlist.ts @@ -0,0 +1,29 @@ +/** + * Resolves the visitor's saved wishlist via Magento's + * `/customer/section/load?sections=wishlist` endpoint, scoped by the + * PHPSESSID cookie. + * + * Ported from `deco-cx/apps/magento/loaders/wishlist.ts`. Returns null + * when the session cookie is absent or Magento reports no wishlist + * (e.g. a logged-in customer who never saved an item). + */ +import { getMagentoConfig, magentoFetch } from "../client"; +import type { CustomerSectionLoad, Wishlist } from "../utils/client/types"; +import { SESSION_COOKIE } from "../utils/constants"; +import { getUserCookie } from "../utils/user"; + +export default async function wishlist(_props: unknown, req: Request): Promise { + const sessionId = getUserCookie(req.headers); + if (!sessionId) return null; + + const { site } = getMagentoConfig(); + const path = `/${encodeURIComponent(site)}/customer/section/load?sections=wishlist`; + + const res = await magentoFetch(path, { + headers: { Cookie: `${SESSION_COOKIE}=${sessionId}` }, + }); + if (!res.ok) return null; + + const { wishlist } = (await res.json()) as CustomerSectionLoad; + return wishlist ?? null; +} diff --git a/magento/middleware.ts b/magento/middleware.ts new file mode 100644 index 0000000..e616609 --- /dev/null +++ b/magento/middleware.ts @@ -0,0 +1,19 @@ +/** + * Magento middleware — currently a passthrough. + * + * The legacy deco-cx/apps middleware reconciled the cart id cookie + * after checkout (`changeCardIdAfterCheckout`) and seeded the + * `form_key` for anonymous sessions. Both flows touched response + * headers and `customer/section/load` endpoints — non-trivial port, + * deferred to a follow-up PR. Today the consumer site (granadobr- + * tanstack) handles cart reconciliation on the client. + * + * Shape matches `@decocms/apps/commerce/app-types.ts` so it can be + * plugged into the autoconfig pipeline once magento is registered + * there. + */ +import type { AppMiddleware } from "../commerce/app-types"; + +export const magentoMiddleware: AppMiddleware = async (_request, next) => { + return next(); +}; diff --git a/magento/types.ts b/magento/types.ts new file mode 100644 index 0000000..6e42c66 --- /dev/null +++ b/magento/types.ts @@ -0,0 +1,51 @@ +/** + * Shared types for the Magento app — kept minimal in this initial port. + * Loader/action ports should extend this file rather than duplicating + * inline types. + */ +import type { MagentoFeatures } from "./client"; + +export interface MagentoCart { + id: string | null; + items: MagentoCartItem[]; + totals?: { + subtotal?: number; + grand_total?: number; + discount_amount?: number; + shipping_amount?: number; + }; + coupon_code?: string | null; +} + +export interface MagentoCartItem { + item_id: number; + sku: string; + name?: string; + qty: number; + price?: number; + row_total?: number; +} + +export type Features = MagentoFeatures; + +/** + * Magento newsletter subscription response shape — what + * `actions/newsletter/subscribe` returns to the storefront. + */ +export interface NewsletterData { + success: boolean; + message: string; +} + +/** + * Stock-alert mutation response from Magento's GraphQL endpoint — + * `actions/product/stockAlert` returns this (or `{ error }`). + */ +export interface ProductStockAlertResponse { + data?: { + productStockAlert: { + message: string; + status: boolean; + }; + }; +} diff --git a/magento/utils/cacheTimeControl.ts b/magento/utils/cacheTimeControl.ts new file mode 100644 index 0000000..09219d4 --- /dev/null +++ b/magento/utils/cacheTimeControl.ts @@ -0,0 +1,69 @@ +/** + * Cache-time-control helpers — verbatim port of + * `deco-cx/apps/magento/utils/cacheTimeControl.ts`. + * + * Magento product loaders pass the request URL through + * `filterSearchParamsFromURL` before using it as a cache key, so that + * tracking parameters (utm_*, gclid, fbclid, etc.) don't fragment the + * cache across thousands of variants for what is conceptually the + * same page. + */ + +export const DEFAULT_CACHE_MAX_AGE = 3600; // 1h + +/** + * Pattern list (each entry is a regex source) of URL search-param + * keys that get stripped before a Magento URL goes into the cache key + * or downstream search-criteria. Mirrors prod byte-for-byte — the + * `.*` suffixes intentionally match `utm_source`, `utm_medium`, etc. + */ +export const SEARCH_PARAMS_TO_IGNORE = [ + "gclid", + "gbraid", + "gdftrk", + "_ga", + "mc_.*", + "trk_.*", + "utm_.*", + "sc_.*", + "dm_i", + "_ke", + "fbclid", + "qitc", + "queryID", + "indexName", + "objectID", + "utm_source", + "utm_medium", + "utm_campaign", + "gad_.*", +]; + +/** + * Filter an array of [key, value] pairs, dropping any whose key matches + * one of the `SEARCH_PARAMS_TO_IGNORE` regex patterns. Pure function so + * callers can sort/transform after. + */ +export const filterSearchParams = (params: [string, string][]): [string, string][] => { + return params.filter( + ([key]) => !SEARCH_PARAMS_TO_IGNORE.find((matchKey) => new RegExp(matchKey).test(key)), + ); +}; + +/** + * Strip the tracking params from a URL (or URL string) and return the + * cleaned `href`. Used by Magento PDP/PLP loaders as the cache key + * basis so cache lookups don't depend on the visitor's referer chain. + */ +export const filterSearchParamsFromURL = (defaultURL: string | URL): string => { + const url = new URL(defaultURL); + const paramsArray = Array.from(url.searchParams.entries()); + const filteredParams = filterSearchParams(paramsArray); + + url.search = ""; + for (const [key, value] of filteredParams) { + url.searchParams.append(key, value); + } + + return url.href; +}; diff --git a/magento/utils/client/types.ts b/magento/utils/client/types.ts new file mode 100644 index 0000000..1c70ca7 --- /dev/null +++ b/magento/utils/client/types.ts @@ -0,0 +1,270 @@ +/** + * Magento REST API response shapes — the subset of types from + * `deco-cx/apps/magento/utils/client/types.ts` that the port has + * reached so far. Extended as more loaders/actions land. + * + * Keep field names **exactly** as Magento returns them (mostly + * snake_case, occasional camelCase from carbono-customer). Consumer + * sites already render against these shapes — any rename is a + * breaking change at the storefront, not just the API boundary. + */ + +// --------------------------------------------------------------------------- +// Customer / user section payloads (added by the user+wishlist port) +// --------------------------------------------------------------------------- + +/** + * `customer` slice of `/customer/section/load?sections=customer,…`. + * Magento returns this on every authenticated section call. + */ +export interface Customer { + data_id: number; + fullname?: string; + firstname?: string; +} + +/** + * `carbono-customer` slice. Granado-specific overlay that mirrors the + * `customer` slice plus a website/store id pair and a normalized email. + * Other magento sites that don't run the Carbono module will get this + * absent; loaders/user.ts checks for it before mapping to a Person. + */ +export interface CarbonoCustomer { + websiteId?: string; + email?: string; + customerId?: string; + data_id: number; +} + +/** + * `cart` slice of the customer section bundle — minimal projection of + * the cart that the minicart island renders before the full cart loader + * has resolved. Not the same as the full Cart payload from + * `/V1/carts/:cartId` (which lives in MagentoCart in types.ts). + */ +export interface CartUser { + summary_count: number; + subtotalAmount: number | null; + subtotal: string; + possible_onepage_checkout: boolean; + items: []; + isGuestCheckoutAllowed: boolean; + website_id: string; + storeId: string; + adyen_payment_methods: unknown[]; + extra_actions: string; + cart_empty_message: string; + subtotal_incl_tax: string; + subtotal_excl_tax: string; + mpFSBCartTotal: unknown | null; + data_id: number; + minicart_improvements: MinicartImprovements; +} + +export interface MinicartImprovements { + coupon_code: string | null; + country_id: string; + api_base_url: string; + is_logged_in: boolean; + quote_id: string; + base_url: string; +} + +/** + * Bundle shape returned by + * `GET /:site/customer/section/load?sections=customer,carbono-customer,wishlist,…`. + * Keys are optional because the caller picks which sections to request. + */ +export interface CustomerSectionLoad { + customer?: Customer; + "carbono-customer"?: CarbonoCustomer; + cart?: CartUser; + wishlist?: Wishlist; +} + +// --------------------------------------------------------------------------- +// Wishlist payloads +// --------------------------------------------------------------------------- + +export interface Wishlist { + counter: string; + items: WishlistItem[]; + counter_number: number; + data_id: number; +} + +export interface WishlistItem { + image: WishlistItemImage; + product_sku: string; + product_id: string; + product_url: string; + product_name: string; + product_price: string; + product_is_saleable_and_visible: boolean; + product_has_required_options: boolean; + add_to_cart_params: string; + delete_item_params: string; +} + +export interface WishlistItemImage { + template: string; + src: string; + width: number; + height: number; + alt: string; +} + +// --------------------------------------------------------------------------- +// Shared attribute/category shapes (added by the transform port) +// --------------------------------------------------------------------------- + +export interface CustomAttribute { + attribute_code: string; + value: string | string[]; +} + +export interface CategoryLink { + position: number; + category_id: string; +} + +export interface MagentoCategory { + id: number; + parent_id: number; + name: string; + is_active: boolean; + position: number; + level: number; + children: string; + created_at: string; + updated_at: string; + path: string; + include_in_menu: boolean; + custom_attributes: CustomAttribute[]; +} + +// --------------------------------------------------------------------------- +// Product detail shapes (used by PDP / PLP / list loaders) +// --------------------------------------------------------------------------- + +export interface MagentoPriceInfo { + final_price: number; + max_price: number; + max_regular_price: number; + minimal_regular_price: number; + special_price: number | null; + minimal_price: number; + regular_price: number; + formatted_prices: { + final_price: string; + max_price: string; + minimal_price: string; + max_regular_price: string; + minimal_regular_price: string | null; + special_price: string | null; + regular_price: string; + }; + extension_attributes: { + msrp: { + msrp_price: string; + is_applicable: string; + is_shown_price_on_gesture: string; + msrp_message: string; + explanation_message: string; + }; + tax_adjustments: { + final_price: number; + max_price: number; + max_regular_price: number; + minimal_regular_price: number; + special_price: number; + minimal_price: number; + regular_price: number; + formatted_prices: { + final_price: string; + max_price: string; + minimal_price: string; + max_regular_price: string; + minimal_regular_price: string | null; + special_price: string; + regular_price: string; + }; + }; + weee_attributes: unknown[]; + weee_adjustment: string; + }; +} + +export interface MagentoStock { + item_id: number; + product_id: number; + stock_id: number; + qty?: number; + is_in_stock?: boolean; + is_qty_decimal?: boolean; + show_default_notification_message?: boolean; + use_config_min_qty?: boolean; + min_qty?: number; + use_config_min_sale_qty?: boolean; + min_sale_qty?: number; + use_config_max_sale_qty?: boolean; + max_sale_qty?: number; + use_config_backorders?: boolean; + backorders?: number; + use_config_notify_stock_qty?: boolean; + notify_stock_qty?: number; + use_config_qty_increments?: boolean; + qty_increments?: number; + use_config_enable_qty_inc?: boolean; + enable_qty_increments?: boolean; + use_config_manage_stock?: boolean; + manage_stock?: boolean; + low_stock_date?: string | null; + is_decimal_divided?: boolean; + stock_status_changed_auto?: number; +} + +export interface MagentoImage { + url: string; + code: string; + height: number; + width: number; + label: string; + resized_width: number; + resized_height: number; + disabled: boolean; +} + +export interface MediaEntry { + id: number; + media_type: string; + label: string | null; + position: number; + disabled: boolean; + types: string[]; + file: string; +} + +export interface MagentoProduct { + id: number; + sku: string; + name: string; + price: number; + status: number; + visibility: number; + type_id: string; + created_at: string; + updated_at: string; + weight: number; + url: string; + extension_attributes: { + website_ids?: number[]; + category_links: CategoryLink[]; + stock_item?: MagentoStock; + }; + custom_attributes: CustomAttribute[]; + price_info?: MagentoPriceInfo; + currency_code?: string; + images?: MagentoImage[]; + media_gallery_entries?: MediaEntry[]; +} diff --git a/magento/utils/constants.ts b/magento/utils/constants.ts new file mode 100644 index 0000000..25a2757 --- /dev/null +++ b/magento/utils/constants.ts @@ -0,0 +1,101 @@ +/** + * Magento constants — ported verbatim from + * `deco-cx/apps/magento/utils/constants.ts`. + * + * Keep this file boring and append-only. Magento's REST and GraphQL + * payloads rely on these identifiers as-is (URL_KEY for PDP slug + * matching, GRAND_TOTAL/SUBTOTAL/… for the totals composition that + * cart.ts pulls, IN_STOCK/OUT_OF_STOCK for schema.org availability). + * Mutating any of these values would silently break consumer sites + * that already render against them. + */ + +import type { FiltersGraphQL } from "../client"; + +export const URL_KEY = "url_key"; + +// Schema.org availability mapping (used by utils/transform.ts to +// produce Offer.availability — kept here so transform doesn't import +// schema.org strings as magic literals). +export const IN_STOCK = "https://schema.org/InStock"; +export const OUT_OF_STOCK = "https://schema.org/OutOfStock"; + +// Rating bounds used by `utils/transform.ts` (and the review/rating +// loaders that follow) when mapping Magento's integer-rating scale +// into schema.org `AggregateRating`'s 1–5 range. +export const MAX_RATING_VALUE = 5; +export const MIN_RATING_VALUE = 1; + +/** + * Default filter mapping consumed by `utils/graphql.ts:filtersFromUrlGraphQL`. + * Each entry pairs a Magento attribute slug with the comparison operator + * the storefront's URL filters use. Sites can extend this via the + * `customFilters` prop on PLP/list loaders without forking the array. + */ +export const DEFAULT_GRAPHQL_FILTERS: FiltersGraphQL[] = [ + { value: "activity", type: "EQUAL" }, + { value: "category_gear", type: "EQUAL" }, + { value: "category_id", type: "EQUAL" }, + { value: "category_uid", type: "EQUAL" }, + { value: "category_url_path", type: "EQUAL" }, + { value: "climate", type: "EQUAL" }, + { value: "collar", type: "EQUAL" }, + { value: "color", type: "EQUAL" }, + { value: "description", type: "MATCH" }, + { value: "eco_collection", type: "EQUAL" }, + { value: "erin_recommends", type: "EQUAL" }, + { value: "features_bags", type: "EQUAL" }, + { value: "format", type: "EQUAL" }, + { value: "gender", type: "EQUAL" }, + { value: "material", type: "EQUAL" }, + { value: "name", type: "MATCH" }, + { value: "new", type: "EQUAL" }, + { value: "pattern", type: "EQUAL" }, + { value: "performance_fabric", type: "EQUAL" }, + { value: "price", type: "RANGE" }, + { value: "purpose", type: "EQUAL" }, + { value: "sale", type: "EQUAL" }, + { value: "short_description", type: "MATCH" }, + { value: "size", type: "EQUAL" }, + { value: "sku", type: "EQUAL" }, + { value: "sleeve", type: "EQUAL" }, + { value: "strap_bags", type: "EQUAL" }, + { value: "style_bags", type: "EQUAL" }, + { value: "style_bottom", type: "EQUAL" }, + { value: "style_general", type: "EQUAL" }, + { value: "url_key", type: "EQUAL" }, +]; + +/** + * Query-string keys that should be stripped before forwarding a request + * URL to Magento (e.g. when computing a cache key or building a + * paginated request). Mirrors the Fresh-era REMOVABLE_URL_SEARCHPARAMS. + */ +export const REMOVABLE_URL_SEARCHPARAMS = ["p", "product_list_order"]; + +// --------------------------------------------------------------------------- +// Cart totals composition — field names sent to Magento's +// /V1/carts/:cartId/totals?fields=… endpoint. The cart loader joins +// these into the `fields` query param to keep the response narrow. +// --------------------------------------------------------------------------- + +export const GRAND_TOTAL = "grand_total"; +export const SUBTOTAL = "subtotal"; +export const DISCOUNT_AMOUNT = "discount_amount"; +export const BASE_DISCOUNT_AMOUNT = "base_discount_amount"; +export const SHIPPING_AMOUNT = "shipping_amount"; +export const BASE_SHIPPING_AMOUNT = "base_shipping_amount"; +export const SHIPPING_DISCOUNT_AMOUNT = "shipping_discount_amount"; +export const COUPON_CODE = "coupon_code"; +export const BASE_CURRENCY_CODE = "base_currency_code"; + +// --------------------------------------------------------------------------- +// Cookie names — single source of truth so loaders/actions/middleware +// don't drift on string literals (Magento is case-sensitive about +// these and a typo produces a silent anonymous-session bug). +// --------------------------------------------------------------------------- + +export const SESSION_COOKIE = "PHPSESSID"; +export const CUSTOMER_COOKIE = "dataservices_customer_id"; +export const CART_COOKIE = "dataservices_cart_id"; +export const FORM_KEY_COOKIE = "form_key"; diff --git a/magento/utils/graphql-types.ts b/magento/utils/graphql-types.ts new file mode 100644 index 0000000..355dc63 --- /dev/null +++ b/magento/utils/graphql-types.ts @@ -0,0 +1,99 @@ +/** + * Magento GraphQL request input types used by the product loaders. + * + * Subset of `deco-cx/apps/magento/utils/clientGraphql/types.ts` that the + * port has reached so far — extended as more loaders land. These mirror + * Magento's GraphQL schema for product search/sort/filter so the + * storefront's URL params translate cleanly into GraphQL variables. + */ + +/** + * Magento ProductAttributeFilterInput shape — keys are Magento + * attribute codes; values are one of the three filter-type unions. + * Maps to: `filter: ProductAttributeFilterInput!` + */ +export interface ProductFilterInput { + [key: string]: FilterEqualTypeInput | FilterMatchTypeInput | FilterRangeTypeInput; +} + +/** + * Magento `FilterEqualTypeInput` — for exact-match attributes (sku, + * sale, color, size, etc.). `in` lets you OR multiple values; the + * single-value `eq` form is also accepted by the Magento schema and is + * the shape `transformFilterValueGraphQL` emits. + */ +export interface FilterEqualTypeInput { + in?: string[]; + eq?: string; +} + +/** + * Magento `FilterMatchTypeInput` — substring-match attributes (name, + * description, short_description). + */ +export interface FilterMatchTypeInput { + match: string; +} + +/** + * Magento `FilterRangeTypeInput` — numeric ranges (price). Both bounds + * are strings in the schema; ranges in URL params come as `from_to`. + */ +export interface FilterRangeTypeInput { + from: string; + to: string; +} + +/** + * Magento `ProductAttributeSortInput` — one entry per sortable + * attribute keyed by attribute code, ordered ASC or DESC. + */ +export interface ProductSortInput { + [key: string]: "ASC" | "DESC"; +} + +/** + * Built-in sort options surfaced in the CMS admin. Custom options can + * be added by sites via `CustomProductSortOption`. + */ +export interface DefaultProductSortOption { + value: "name" | "position" | "price" | "relevance"; +} + +export interface CustomProductSortOption { + value: string; +} + +/** + * Shared sort-prop shape used by PLP / list / relatedProducts loaders. + */ +export interface ProductSort { + /** @title Order by */ + sortBy: DefaultProductSortOption | CustomProductSortOption; + /** @title Sequency */ + order: "ASC" | "DESC"; +} + +/** + * Loader-supplied filter (vs URL-derived). The site can hard-code + * filters in the CMS section config and they layer on top of whatever + * the user picked from URL params. + */ +export interface FilterProps { + name: string; + type: FilterEqualTypeInput | FilterMatchTypeInput | FilterRangeTypeInput; +} + +/** + * Custom-fields toggle used by `getCustomFields()` to decide which + * Magento product attributes to project from a query. + */ +export interface CustomFields { + /** + * @description Search for global custom fields defined in App settings + * @default false + */ + active: boolean; + /** @description Will override global custom fields defined in App settings */ + overrideList?: string[]; +} diff --git a/magento/utils/graphql.ts b/magento/utils/graphql.ts new file mode 100644 index 0000000..2156df3 --- /dev/null +++ b/magento/utils/graphql.ts @@ -0,0 +1,155 @@ +/** + * GraphQL helpers for Magento product loaders. + * + * Ported from `deco-cx/apps/magento/utils/graphql.ts` (Fresh/Deno + * prod). Pure functions — no I/O, no client state — so behavior is + * pinned by `__tests__/graphql.test.ts` and shared across PDP, PLP, + * list, and relatedProducts loaders. + * + * - `transformSortGraphQL(ProductSort)` → `ProductSortInput` + * - `transformFilterGraphQL(url, customFilters, fromLoader)` → + * `ProductFilterInput` — merges URL-derived + loader-derived filters. + * - `transformFilterValueGraphQL(value, type)` → typed Filter*Input. + * - `formatUrlSuffix(str)` → ensures a path ends with `/` (used as + * `defaultPath` for the Magento URL rewrite resolver). + * - `getCustomFields(CustomFields, fallback)` → resolved custom + * attribute list for product projection. + */ + +import type { FiltersGraphQL } from "../client"; +import { DEFAULT_GRAPHQL_FILTERS } from "./constants"; +import type { + CustomFields, + FilterEqualTypeInput, + FilterMatchTypeInput, + FilterProps, + FilterRangeTypeInput, + ProductFilterInput, + ProductSort, + ProductSortInput, +} from "./graphql-types"; + +export const typeChecker = (v: T, prop: keyof T): boolean => prop in v; + +export const transformSortGraphQL = ({ + sortBy, + order, +}: Partial): ProductSortInput | undefined => { + if (!sortBy) { + return undefined; + } + return { + [sortBy.value]: order ?? "ASC", + }; +}; + +/** + * Compose the GraphQL `filter` payload from two sources, in order: + * + * 1. URL search params crossed against `DEFAULT_GRAPHQL_FILTERS` + * (+ any `customFilters` the site extends with). + * 2. Explicit `fromLoader` filters the CMS section pinned at config + * time. + * + * Loader-derived filters shadow URL-derived ones on key collisions + * (intentional — a section that hard-codes `sale=true` should ignore + * any conflicting URL hint). + */ +export const transformFilterGraphQL = ( + url: URL, + customFilters?: Array, + fromLoader?: Array, +): ProductFilterInput | undefined => ({ + ...filtersFromUrlGraphQL(url, customFilters), + ...filtersFromLoaderGraphQL(fromLoader), +}); + +export const filtersFromLoaderGraphQL = ( + fromLoader?: Array, +): ProductFilterInput | undefined => + fromLoader?.reduce( + (acc, f) => ({ + ...acc, + [f.name]: f.type, + }), + {}, + ) ?? {}; + +export const filtersFromUrlGraphQL = ( + url: URL, + customFilters?: Array, +): ProductFilterInput => + DEFAULT_GRAPHQL_FILTERS.concat(customFilters ?? []).reduce( + (acc, { type, value }) => { + const fromUrl = url.searchParams.get(value); + if (!fromUrl) { + return acc; + } + return { + ...acc, + [value]: transformFilterValueGraphQL(fromUrl, type), + }; + }, + {}, + ); + +export const transformFilterValueGraphQL = ( + value: string, + type: "EQUAL" | "MATCH" | "RANGE", +): FilterEqualTypeInput | FilterMatchTypeInput | FilterRangeTypeInput => { + if (type === "EQUAL") { + return { eq: value } as FilterEqualTypeInput; + } + + if (type === "MATCH") { + return { match: value } as FilterMatchTypeInput; + } + + if (type === "RANGE") { + const splitterIndex = value.indexOf("_"); + return { + from: value.substring(0, splitterIndex), + to: value.substring(splitterIndex + 1), + } as FilterRangeTypeInput; + } + + return {} as FilterEqualTypeInput; +}; + +/** + * Normalize a URL path into the form Magento's + * `urlResolver(url: "/")` expects: + * - Strip a single leading slash (the resolver doesn't want it). + * - Ensure the path ends with `/`. + * + * Used by PLP / PDP / list / relatedProducts loaders as `defaultPath` + * when `useSuffix` is enabled. + */ +export const formatUrlSuffix = (str: string): string => { + let s = str; + if (s.startsWith("/")) s = s.slice(1); + if (!s.endsWith("/")) s = `${s}/`; + return s; +}; + +/** + * Resolve which custom-attribute list a loader should request: + * + * - disabled (`active: false`) → undefined (loader projects nothing custom). + * - explicit override list set → return that list as-is. + * - otherwise → fall back to the global list provided by the loader. + */ +export const getCustomFields = ( + { active, overrideList }: CustomFields = { active: false, overrideList: [] }, + customFields?: Array, +): Array | undefined => { + if (!active) { + return undefined; + } + + if (overrideList && overrideList.length > 0) { + return overrideList; + } + + return customFields; +}; diff --git a/magento/utils/stringifySearchCriteria.ts b/magento/utils/stringifySearchCriteria.ts new file mode 100644 index 0000000..076edab --- /dev/null +++ b/magento/utils/stringifySearchCriteria.ts @@ -0,0 +1,62 @@ +/** + * Flatten a Magento REST `searchCriteria` object into a bracketed + * query-string key/value map. + * + * Magento's search-criteria payload is deeply nested (filterGroups → + * filters → field/value), but the REST API accepts it only as flat + * `searchCriteria[filterGroups][0][filters][0][field]=name` style + * query parameters. This helper walks the tree once and emits that + * shape. + * + * Ported verbatim from `deco-cx/apps/magento/utils/stringifySearchCriteria.ts` + * — the Fresh implementation is self-contained (no Deno-isms) and + * produces output that prod consumers already depend on. Behavior + * pinned by `__tests__/stringifySearchCriteria.test.ts`. + * + * @example + * stringifySearchCriteria({ + * filterGroups: [{ filters: [{ field: "sku", value: "ABC" }] }], + * }) + * // ⇒ { "searchCriteria[filterGroups][0][filters][0][field]": "sku", + * // "searchCriteria[filterGroups][0][filters][0][value]": "ABC" } + */ +interface Filter { + field: string; + value: string; +} + +interface FilterGroup { + [key: string]: Filter[]; +} + +interface SearchCriteria { + [key: string]: string | number | FilterGroup[]; +} + +type Path = string; +type TraverseObj = SearchCriteria | FilterGroup[]; + +function traverse(data: TraverseObj, result: Record, path: Path) { + if (Array.isArray(data)) { + data.forEach((item, index) => { + traverse(item as unknown as TraverseObj, result, `${path}[${index}]`); + }); + } else if (typeof data === "object" && data !== null) { + for (const key in data) { + if (Object.hasOwn(data, key)) { + // @ts-expect-error recursive function with heterogeneous values + traverse(data[key], result, `${path}[${key}]`); + } + } + } else { + result[path] = data; + } +} + +export default function stringifySearchCriteria( + searchCriteriaObj: SearchCriteria, +): Record { + const result: Record = {}; + traverse(searchCriteriaObj, result, "searchCriteria"); + return result; +} diff --git a/magento/utils/transform.ts b/magento/utils/transform.ts new file mode 100644 index 0000000..b5f9f75 --- /dev/null +++ b/magento/utils/transform.ts @@ -0,0 +1,283 @@ +/** + * Magento product transform helpers — maps the REST/GraphQL payloads + * into schema.org `Product` / `Offer` / `Seo` shapes that + * `@decocms/apps/commerce` consumers expect. + * + * Subset of `deco-cx/apps/magento/utils/transform.ts` — only the + * functions the PDP loader needs (toProduct, toOffer, toImages, toURL, + * toBreadcrumbList, toSeo). The GraphQL-side helpers (toProductGraphQL, + * toAggOfferGraphQL, toProductListingPageGraphQL, …) and the Granado- + * specific helpers (toReviewAmasty, toLiveloPoints) are intentionally + * excluded — they land in separate follow-up PRs alongside the loaders + * that consume them. + * + * Behavior is pinned by `__tests__/transform.test.ts`. Every change to + * this file should ship a regression test. + */ + +import type { + ImageObject, + ListItem, + Offer, + Product, + PropertyValue, + Seo, + UnitPriceSpecification, +} from "@decocms/apps/commerce/types"; +import type { CustomAttribute, MagentoCategory, MagentoProduct } from "./client/types"; +import { IN_STOCK, OUT_OF_STOCK } from "./constants"; + +// --------------------------------------------------------------------------- +// Product → schema.org Product +// --------------------------------------------------------------------------- + +export const toProduct = ({ + product, + options, +}: { + product: MagentoProduct; + options: { + currencyCode?: string; + imagesUrl?: string; + maxInstallments: number; + minInstallmentValue: number; + }; +}): Product => { + const offers = toOffer(product, options.minInstallmentValue, options.maxInstallments); + const sku = product.sku; + const productID = product.id.toString(); + const productPrice = product.price_info; + + const additionalProperty: PropertyValue[] = product.custom_attributes?.map((attr) => ({ + "@type": "PropertyValue", + name: attr.attribute_code, + value: String(attr.value), + })); + + return { + "@type": "Product", + productID, + sku, + url: product.url, + name: product.name, + gtin: sku, + isVariantOf: { + "@type": "ProductGroup", + productGroupID: productID, + url: product.url, + name: product.name, + model: "", + additionalProperty: additionalProperty, + hasVariant: [ + { + "@type": "Product", + productID, + sku, + url: product.url, + name: product.name, + gtin: sku, + offers: { + "@type": "AggregateOffer", + // biome-ignore lint/style/noNonNullAssertion: matches prod fallback to price + highPrice: productPrice?.max_price ?? product.price!, + // biome-ignore lint/style/noNonNullAssertion: matches prod fallback to price + lowPrice: productPrice?.minimal_price ?? product.price!, + offerCount: offers.length, + offers: offers, + }, + }, + ], + }, + additionalProperty: additionalProperty, + image: toImages(product, options.imagesUrl ?? ""), + offers: { + "@type": "AggregateOffer", + // biome-ignore lint/style/noNonNullAssertion: matches prod fallback to price + highPrice: productPrice?.max_price ?? product.price!, + // biome-ignore lint/style/noNonNullAssertion: matches prod fallback to price + lowPrice: productPrice?.minimal_price ?? product.price!, + offerCount: offers.length, + offers: offers, + }, + }; +}; + +// --------------------------------------------------------------------------- +// Product → Offer[] +// --------------------------------------------------------------------------- + +export const toOffer = ( + { price_info, extension_attributes, sku, currency_code }: MagentoProduct, + minInstallmentValue: number, + maxInstallments: number, +): Offer[] => { + if (!price_info) { + return []; + } + const { final_price, max_price, max_regular_price } = price_info; + const { stock_item } = extension_attributes; + const inStock = stock_item?.is_in_stock; + const qtyStock = stock_item?.qty ?? 0; + + return [ + { + "@type": "Offer", + availability: inStock ? IN_STOCK : OUT_OF_STOCK, + inventoryLevel: { + value: inStock ? qtyStock || 999 : 0, + }, + itemCondition: "https://schema.org/NewCondition", + price: final_price, + priceCurrency: currency_code, + priceSpecification: [ + { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/ListPrice", + price: max_price ?? max_regular_price, + }, + { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/SalePrice", + price: final_price, + }, + ...calculateInstallments(final_price, minInstallmentValue, maxInstallments), + ], + sku: sku, + }, + ]; +}; + +/** + * Build the installment ladder for a sale price. `À vista` is always + * the first entry, then 2x..Nx where N is bounded by + * `min(floor(finalPrice/minInstallmentValue), maxInstallments)`. + * Each entry is a `UnitPriceSpecification` so storefront UIs render + * "10x de R$ 12,50 sem juros" without further math. + */ +const calculateInstallments = ( + finalPrice: number, + minInstallmentValue: number, + maxInstallments: number, +): UnitPriceSpecification[] => { + const possibleInstallmentsCount = Math.floor(finalPrice / minInstallmentValue) || 1; + const actualInstallmentsCount = Array.from( + { length: Math.min(possibleInstallmentsCount, maxInstallments) }, + (_v, i) => +(finalPrice / (i + 1)).toFixed(2), + ); + + return actualInstallmentsCount.map((value, i) => { + const [description, billingIncrement] = !i + ? ["À vista", finalPrice] + : [`${i + 1}x sem juros`, value]; + return { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/SalePrice", + priceComponentType: "https://schema.org/Installment", + description, + billingDuration: i + 1, + billingIncrement, + price: finalPrice, + }; + }); +}; + +// --------------------------------------------------------------------------- +// Product → ImageObject[] +// --------------------------------------------------------------------------- + +export const toImages = (product: MagentoProduct, imageUrl: string): ImageObject[] | undefined => { + if (imageUrl) { + return product.media_gallery_entries?.map((img) => ({ + "@type": "ImageObject" as const, + encodingFormat: "image", + alternateName: `${img.file}`, + url: `${toURL(imageUrl)}${img.file}`, + disabled: img.disabled || false, + })); + } + + return product.images?.map((img) => ({ + "@type": "ImageObject" as const, + encodingFormat: "image", + alternateName: `${img.label}`, + disabled: img.disabled || false, + url: `${img.url}`, + })); +}; + +/** + * Protocol-relative URLs (`//cdn.magento.example/...`) come back from + * some Magento installations. Promote to https so the browser doesn't + * try to inherit a non-https scheme. + */ +export const toURL = (src: string): string => (src.startsWith("//") ? `https:${src}` : src); + +// --------------------------------------------------------------------------- +// Categories → ListItem[] (breadcrumb) +// --------------------------------------------------------------------------- + +export const toBreadcrumbList = ( + categories: (MagentoCategory | null)[], + isBreadcrumbProductName: boolean, + product: Product, + url: URL, +): ListItem[] => { + if (isBreadcrumbProductName && categories?.length === 0) { + return [ + { + "@type": "ListItem", + name: product.name, + position: 1, + item: new URL(`/${product.name}`, url).href, + }, + ]; + } + + const itemListElement = categories + .map((category) => { + if (!category || !category.name || !category.position) { + return null; + } + return { + "@type": "ListItem", + name: category.name, + position: category.position, + item: new URL(`/${category.name}`, url).href, + }; + }) + .filter(Boolean) as ListItem[]; + + return itemListElement; +}; + +// --------------------------------------------------------------------------- +// Custom attributes → Seo +// --------------------------------------------------------------------------- + +/** + * Build a `Seo` block from a product's custom_attributes. Magento + * exposes title/meta_title/meta_description as separate attribute_code + * entries; this maps them with explicit fallback (meta_title wins over + * title; description is meta_description only — there's no fallback + * field in the legacy code). + */ +export const toSeo = (customAttributes: CustomAttribute[], productURL: string): Seo => { + const findAttribute = (attrCode: string): string => { + const attribute = customAttributes.find((attr) => attr.attribute_code === attrCode); + if (!attribute) return ""; + if (Array.isArray(attribute.value)) { + return attribute.value.join(", "); + } + return attribute.value; + }; + + const title = findAttribute("title"); + const metaTitle = findAttribute("meta_title"); + const metaDescription = findAttribute("meta_description"); + + return { + title: metaTitle || title || "", + description: metaDescription || "", + canonical: productURL, + }; +}; diff --git a/magento/utils/user.ts b/magento/utils/user.ts new file mode 100644 index 0000000..cd7c1b1 --- /dev/null +++ b/magento/utils/user.ts @@ -0,0 +1,16 @@ +/** + * Reads the Magento PHP session cookie from a request's headers. + * Returns undefined when the cookie is absent (anonymous visitor). + * + * Mirrors `deco-cx/apps/magento/utils/user.ts` — the Fresh version + * used Deno's `std/http/cookie` getCookies; the port goes through + * `@decocms/start/sdk/cookie` so it works on Cloudflare Workers and + * Node alike. + */ +import { getCookies } from "@decocms/start/sdk/cookie"; +import { SESSION_COOKIE } from "./constants"; + +export const getUserCookie = (headers: Headers): string | undefined => { + const cookies = getCookies(headers); + return cookies[SESSION_COOKIE]; +}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 56d4a28..0000000 --- a/package-lock.json +++ /dev/null @@ -1,11311 +0,0 @@ -{ - "name": "@decocms/apps", - "version": "1.13.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@decocms/apps", - "version": "1.13.0", - "license": "MIT", - "devDependencies": { - "@biomejs/biome": "^2.4.7", - "@decocms/start": "5.3.0-rc.2", - "@semantic-release/exec": "^7.1.0", - "@tanstack/react-query": "^5.90.21", - "@types/react": "^19.0.0", - "@vitest/coverage-v8": "^4.1.0", - "happy-dom": "^20.9.0", - "knip": "^5.86.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tsx": "^4.21.0", - "typescript": "^5.9.3", - "vitest": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@decocms/start": ">=5.3.0-rc.2", - "@tanstack/react-query": ">=5", - "react": ">=18", - "react-dom": ">=18" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", - "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@biomejs/biome": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz", - "integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==", - "dev": true, - "license": "MIT OR Apache-2.0", - "bin": { - "biome": "bin/biome" - }, - "engines": { - "node": ">=14.21.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/biome" - }, - "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.4.15", - "@biomejs/cli-darwin-x64": "2.4.15", - "@biomejs/cli-linux-arm64": "2.4.15", - "@biomejs/cli-linux-arm64-musl": "2.4.15", - "@biomejs/cli-linux-x64": "2.4.15", - "@biomejs/cli-linux-x64-musl": "2.4.15", - "@biomejs/cli-win32-arm64": "2.4.15", - "@biomejs/cli-win32-x64": "2.4.15" - } - }, - "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz", - "integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz", - "integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz", - "integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz", - "integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz", - "integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz", - "integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz", - "integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-x64": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz", - "integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@deco-cx/warp-node": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@deco-cx/warp-node/-/warp-node-0.3.20.tgz", - "integrity": "sha512-rdRWrT5eMhu1zhAzliRkoQCUr2j6Dg9npUKoP4uP+rV9wIbYKSmXJbM2z/fOiy5FVvzQlpvY16ACNRIRz+UWqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici": "^6.21.0", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@decocms/start": { - "version": "5.3.0-rc.2", - "resolved": "https://registry.npmjs.org/@decocms/start/-/start-5.3.0-rc.2.tgz", - "integrity": "sha512-8fAvbCSqUmGiG5cSnuAKg4zKGnCv18oevoTfi5Ef1FYK7gQM/e/0yP0DcsJ8DT2+QM6E+SffjeZFMyavLNWDMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deco-cx/warp-node": "^0.3.16", - "@opentelemetry/api": "^1.9.1", - "clsx": "^2.1.1", - "fast-json-patch": "^3.1.0", - "tailwind-merge": "^3.3.1", - "tsx": "^4.19.0", - "ws": "^8.18.0" - }, - "bin": { - "deco-audit-observability": "scripts/audit-observability-config.ts", - "deco-cf-observability": "scripts/migrate-to-cf-observability.ts", - "deco-htmx-analyze": "scripts/htmx-analyze.ts", - "deco-migrate": "scripts/migrate.ts", - "deco-post-cleanup": "scripts/migrate-post-cleanup.ts" - }, - "peerDependencies": { - "@tanstack/react-query": ">=5.0.0", - "@tanstack/react-start": ">=1.0.0", - "@tanstack/store": ">=0.7.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "vite": ">=6.0.0 || >=7.0.0 || >=8.0.0" - } - }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@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.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "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/@octokit/auth-token": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", - "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/core": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", - "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/auth-token": "^6.0.0", - "@octokit/graphql": "^9.0.3", - "@octokit/request": "^10.0.6", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "before-after-hook": "^4.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/endpoint": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz", - "integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/graphql": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", - "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/request": "^10.0.6", - "@octokit/types": "^16.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", - "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.2.1.tgz", - "integrity": "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/types": "^15.0.1" - }, - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-26.0.0.tgz", - "integrity": "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-15.0.2.tgz", - "integrity": "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/openapi-types": "^26.0.0" - } - }, - "node_modules/@octokit/plugin-retry": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.1.0.tgz", - "integrity": "sha512-O1FZgXeiGb2sowEr/hYTr6YunGdSAFWnr2fyW39Ah85H8O33ELASQxcvOFF5LE6Tjekcyu2ms4qAzJVhSaJxTw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "bottleneck": "^2.15.3" - }, - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=7" - } - }, - "node_modules/@octokit/plugin-throttling": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.3.tgz", - "integrity": "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/types": "^16.0.0", - "bottleneck": "^2.15.3" - }, - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": "^7.0.0" - } - }, - "node_modules/@octokit/request": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.9.tgz", - "integrity": "sha512-o8Bi3f608eyM+7BmBiUWxFsdjLb3/ym1cQek5LZOv9KkZcxRrHCPhhRzm6xjO6HVZ85ItD6+sTsjxo821SVa/A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/endpoint": "^11.0.3", - "@octokit/request-error": "^7.0.2", - "@octokit/types": "^16.0.0", - "content-type": "^2.0.0", - "fast-content-type-parse": "^3.0.0", - "json-with-bigint": "^3.5.3", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/request-error": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", - "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/types": "^16.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/types": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", - "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/openapi-types": "^27.0.0" - } - }, - "node_modules/@oozcitak/dom": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", - "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oozcitak/infra": "^2.0.2", - "@oozcitak/url": "^3.0.0", - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@oozcitak/infra": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz", - "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@oozcitak/url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz", - "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oozcitak/infra": "^2.0.2", - "@oozcitak/util": "^10.0.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@oozcitak/util": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz", - "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.130.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", - "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@oxc-resolver/binding-android-arm-eabi": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.19.1.tgz", - "integrity": "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@oxc-resolver/binding-android-arm64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.19.1.tgz", - "integrity": "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.19.1.tgz", - "integrity": "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.19.1.tgz", - "integrity": "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.19.1.tgz", - "integrity": "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.19.1.tgz", - "integrity": "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.19.1.tgz", - "integrity": "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.19.1.tgz", - "integrity": "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.19.1.tgz", - "integrity": "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.19.1.tgz", - "integrity": "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.19.1.tgz", - "integrity": "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.19.1.tgz", - "integrity": "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.19.1.tgz", - "integrity": "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.19.1.tgz", - "integrity": "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.19.1.tgz", - "integrity": "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxc-resolver/binding-openharmony-arm64": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.19.1.tgz", - "integrity": "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.19.1.tgz", - "integrity": "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.19.1.tgz", - "integrity": "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@oxc-resolver/binding-win32-ia32-msvc": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.19.1.tgz", - "integrity": "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.19.1.tgz", - "integrity": "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "4.2.10" - }, - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/@pnpm/npm-conf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz", - "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz", - "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz", - "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz", - "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz", - "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz", - "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz", - "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz", - "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz", - "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz", - "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz", - "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz", - "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz", - "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz", - "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz", - "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz", - "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.40.tgz", - "integrity": "sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@sec-ant/readable-stream": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", - "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@semantic-release/commit-analyzer": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.1.tgz", - "integrity": "sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "conventional-changelog-angular": "^8.0.0", - "conventional-changelog-writer": "^8.0.0", - "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.0.0", - "debug": "^4.0.0", - "import-from-esm": "^2.0.0", - "lodash-es": "^4.17.21", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" - } - }, - "node_modules/@semantic-release/error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", - "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@semantic-release/exec": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@semantic-release/exec/-/exec-7.1.0.tgz", - "integrity": "sha512-4ycZ2atgEUutspPZ2hxO6z8JoQt4+y/kkHvfZ1cZxgl9WKJId1xPj+UadwInj+gMn2Gsv+fLnbrZ4s+6tK2TFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@semantic-release/error": "^4.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "execa": "^9.0.0", - "lodash-es": "^4.17.21", - "parse-json": "^8.0.0" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=24.1.0" - } - }, - "node_modules/@semantic-release/github": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.6.tgz", - "integrity": "sha512-ctDzdSMrT3H+pwKBPdyCPty6Y47X8dSrjd3aPZ5KKIKKWTwZBE9De8GtsH3TyAlw3Uyo2stegMx6rJMXKpJwJA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@octokit/core": "^7.0.0", - "@octokit/plugin-paginate-rest": "^13.0.0", - "@octokit/plugin-retry": "^8.0.0", - "@octokit/plugin-throttling": "^11.0.0", - "@semantic-release/error": "^4.0.0", - "aggregate-error": "^5.0.0", - "debug": "^4.3.4", - "dir-glob": "^3.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "issue-parser": "^7.0.0", - "lodash-es": "^4.17.21", - "mime": "^4.0.0", - "p-filter": "^4.0.0", - "tinyglobby": "^0.2.14", - "url-join": "^5.0.0" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=24.1.0" - } - }, - "node_modules/@semantic-release/github/node_modules/aggregate-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", - "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "clean-stack": "^5.2.0", - "indent-string": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/github/node_modules/clean-stack": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.3.0.tgz", - "integrity": "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "escape-string-regexp": "5.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/github/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/npm": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-12.0.2.tgz", - "integrity": "sha512-+M9/Lb35IgnlUO6OSJ40Ie+hUsZLuph2fqXC/qrKn0fMvUU/jiCjpoL6zEm69vzcmaZJ8yNKtMBEKHWN49WBbQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@semantic-release/error": "^4.0.0", - "aggregate-error": "^5.0.0", - "execa": "^9.0.0", - "fs-extra": "^11.0.0", - "lodash-es": "^4.17.21", - "nerf-dart": "^1.0.0", - "normalize-url": "^8.0.0", - "npm": "^10.9.3", - "rc": "^1.2.8", - "read-pkg": "^9.0.0", - "registry-auth-token": "^5.0.0", - "semver": "^7.1.2", - "tempy": "^3.0.0" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" - } - }, - "node_modules/@semantic-release/npm/node_modules/aggregate-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", - "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "clean-stack": "^5.2.0", - "indent-string": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/npm/node_modules/clean-stack": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.3.0.tgz", - "integrity": "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "escape-string-regexp": "5.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/npm/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/npm/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@semantic-release/release-notes-generator": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.1.1.tgz", - "integrity": "sha512-Pbd2e2XRMUD0OxehHpgd5/YghsE76cddkRHSoDvKLK+OCy4Ewxn49rWR631MEUU01lgwF/uyVXvbnVuu6+Z6VA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "conventional-changelog-angular": "^8.0.0", - "conventional-changelog-writer": "^8.0.0", - "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.0.0", - "debug": "^4.0.0", - "import-from-esm": "^2.0.0", - "lodash-es": "^4.17.21", - "read-package-up": "^11.0.0" - }, - "engines": { - "node": ">=20.8.1" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" - } - }, - "node_modules/@simple-libs/stream-utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", - "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://ko-fi.com/dangreen" - } - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tanstack/history": { - "version": "1.162.0", - "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.162.0.tgz", - "integrity": "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/query-core": { - "version": "5.100.11", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.11.tgz", - "integrity": "sha512-lmE0994apShXPj8CUxgx4ch5yUJhE9k/+tVwihBvPOyerACWdBocfFg24t8+0RhtlTd7tEgchDkhlCxNssvDxw==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.100.11", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.11.tgz", - "integrity": "sha512-J0f9s5x3LE1450nNNfYx+e/n0DMa0uOBdFJUy5r0RvmsXd4nB/n0rbHtHI1vYXhikNFan+wf51p6Tmp4c8ucrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.100.11" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, - "node_modules/@tanstack/react-router": { - "version": "1.170.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.4.tgz", - "integrity": "sha512-cusL4YCTuGGJhjfsXEBm6/SmOAs/G8wRVNadeyN3ofu4OZwX69KAybBEf217buxYzI+FohdJVoigEpJV+tGzIw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/history": "1.162.0", - "@tanstack/react-store": "^0.9.3", - "@tanstack/router-core": "1.171.2", - "isbot": "^5.1.22" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0" - } - }, - "node_modules/@tanstack/react-start": { - "version": "1.168.6", - "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.168.6.tgz", - "integrity": "sha512-0/vMhec98zdBvcagQB3NKuz4jZX3Z/djOXjpMLeQclYMRWqbj5XA0WBAFLCuA8p84eUoP8yiUkEDH1OUfIYf7A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/react-router": "1.170.4", - "@tanstack/react-start-client": "1.167.4", - "@tanstack/react-start-rsc": "0.1.6", - "@tanstack/react-start-server": "1.167.4", - "@tanstack/router-utils": "1.162.0", - "@tanstack/start-client-core": "1.169.4", - "@tanstack/start-plugin-core": "1.170.6", - "@tanstack/start-server-core": "1.168.4", - "pathe": "^2.0.3" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@rsbuild/core": "^2.0.0", - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0", - "vite": ">=7.0.0" - }, - "peerDependenciesMeta": { - "@rsbuild/core": { - "optional": true - }, - "@vitejs/plugin-rsc": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@tanstack/react-start-client": { - "version": "1.167.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-start-client/-/react-start-client-1.167.4.tgz", - "integrity": "sha512-HYr9kbEuXjoqEVhmkuIXK9ckfrx08nHCPQ+PQbZlwHd01wghljcBsdAe/8/xujiKnbihC05owBDmXQoE3v27bQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/react-router": "1.170.4", - "@tanstack/router-core": "1.171.2", - "@tanstack/start-client-core": "1.169.4" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0" - } - }, - "node_modules/@tanstack/react-start-rsc": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@tanstack/react-start-rsc/-/react-start-rsc-0.1.6.tgz", - "integrity": "sha512-EIP5Vnc4quTZm5rhhkHAqANHGaXRks+S3FomGMHcN7noTJ3OZviifJXc1nN8pYSFeP8NQ2Sqrkn1Kr/87iWXWA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/react-router": "1.170.4", - "@tanstack/react-start-server": "1.167.4", - "@tanstack/router-core": "1.171.2", - "@tanstack/router-utils": "1.162.0", - "@tanstack/start-client-core": "1.169.4", - "@tanstack/start-fn-stubs": "1.162.0", - "@tanstack/start-plugin-core": "1.170.6", - "@tanstack/start-server-core": "1.168.4", - "@tanstack/start-storage-context": "1.167.4", - "pathe": "^2.0.3" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@rspack/core": ">=2.0.0-0", - "@vitejs/plugin-rsc": ">=0.5.20", - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0", - "react-server-dom-rspack": ">=0.0.2" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "@vitejs/plugin-rsc": { - "optional": true - }, - "react-server-dom-rspack": { - "optional": true - } - } - }, - "node_modules/@tanstack/react-start-server": { - "version": "1.167.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-start-server/-/react-start-server-1.167.4.tgz", - "integrity": "sha512-FckuV/6uQQqycU8ufTtxyQiY4hL3bGn23kq/XFsJVXWtpflY6LAtfOi23CoRL4G8eTVvUa2+WGReZhivwNGZiw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/history": "1.162.0", - "@tanstack/react-router": "1.170.4", - "@tanstack/router-core": "1.171.2", - "@tanstack/start-client-core": "1.169.4", - "@tanstack/start-server-core": "1.168.4" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0" - } - }, - "node_modules/@tanstack/react-store": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.9.3.tgz", - "integrity": "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/store": "0.9.3", - "use-sync-external-store": "^1.6.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tanstack/react-store/node_modules/@tanstack/store": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", - "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/router-core": { - "version": "1.171.2", - "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.2.tgz", - "integrity": "sha512-sUd+BhGYkBF64LVhmOHnYsc1AutPNch/huohEXiXL4IUgmk17Gy+RkUazvjQhptVdYW5QT+qtATrUr2cQZNHFA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/history": "1.162.0", - "cookie-es": "^3.0.0", - "seroval": "^1.5.4", - "seroval-plugins": "^1.5.4" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/router-generator": { - "version": "1.167.5", - "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.5.tgz", - "integrity": "sha512-S7h9qs7WjwF1IlMiOxSv+xB/bSOQ6QS84NlApM9iWLVdkbOVUn7RzTaCqw2qdDa5cPrfSiZJ2wK2a6RFDmFubA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/types": "^7.28.5", - "@tanstack/router-core": "1.171.2", - "@tanstack/router-utils": "1.162.0", - "@tanstack/virtual-file-routes": "1.162.0", - "jiti": "^2.7.0", - "magic-string": "^0.30.21", - "prettier": "^3.5.0", - "zod": "^3.24.2" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/router-plugin": { - "version": "1.168.6", - "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.6.tgz", - "integrity": "sha512-u5CNtTWGyFvV8gGWKBt9LdwVGg+ISSBXG/aeeU1/d1YpEKPqlJHS6oN3tvNKOScubeV64HjpeV0tD6fqRfCpvw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.28.5", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@tanstack/router-core": "1.171.2", - "@tanstack/router-generator": "1.167.5", - "@tanstack/router-utils": "1.162.0", - "@tanstack/virtual-file-routes": "1.162.0", - "chokidar": "^3.6.0", - "unplugin": "^3.0.0", - "zod": "^3.24.2" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@rsbuild/core": ">=1.0.2 || ^2.0.0", - "@tanstack/react-router": "^1.170.4", - "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", - "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", - "webpack": ">=5.92.0" - }, - "peerDependenciesMeta": { - "@rsbuild/core": { - "optional": true - }, - "@tanstack/react-router": { - "optional": true - }, - "vite": { - "optional": true - }, - "vite-plugin-solid": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/@tanstack/router-utils": { - "version": "1.162.0", - "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.162.0.tgz", - "integrity": "sha512-c3GhqhBRCP636B41nf3TKvVz8EWzC5PTZ3I4J4LDH2tVjpxbyFNYsQKRtbNWiMFl+GTtgK4nCha346Wv7j4hcQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.28.5", - "@babel/generator": "^7.28.5", - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "ansis": "^4.1.0", - "babel-dead-code-elimination": "^1.0.12", - "diff": "^8.0.2", - "pathe": "^2.0.3", - "tinyglobby": "^0.2.15" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/start-client-core": { - "version": "1.169.4", - "resolved": "https://registry.npmjs.org/@tanstack/start-client-core/-/start-client-core-1.169.4.tgz", - "integrity": "sha512-2UZ1hLCY80eXkYjRLYASLiJqDXfmlCE3kUknNARgZr7232TMk4ADPDMCp2l506zLXTLKAnI+Wu4jXL2CEadUxQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/router-core": "1.171.2", - "@tanstack/start-fn-stubs": "1.162.0", - "@tanstack/start-storage-context": "1.167.4", - "seroval": "^1.5.4" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/start-fn-stubs": { - "version": "1.162.0", - "resolved": "https://registry.npmjs.org/@tanstack/start-fn-stubs/-/start-fn-stubs-1.162.0.tgz", - "integrity": "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/start-plugin-core": { - "version": "1.170.6", - "resolved": "https://registry.npmjs.org/@tanstack/start-plugin-core/-/start-plugin-core-1.170.6.tgz", - "integrity": "sha512-8XzrZwNvYODjTf6zByQhYd1286YU8O1iecZ2zMhchvkHLTLfvku8xJavjLTaz9MAMM08KiX/oqEwpRiP/aOalg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "7.27.1", - "@babel/core": "^7.28.5", - "@babel/types": "^7.28.5", - "@rolldown/pluginutils": "1.0.0-beta.40", - "@tanstack/router-core": "1.171.2", - "@tanstack/router-generator": "1.167.5", - "@tanstack/router-plugin": "1.168.6", - "@tanstack/router-utils": "1.162.0", - "@tanstack/start-client-core": "1.169.4", - "@tanstack/start-server-core": "1.168.4", - "cheerio": "^1.0.0", - "exsolve": "^1.0.7", - "lightningcss": "^1.32.0", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "seroval": "^1.5.4", - "source-map": "^0.7.6", - "srvx": "^0.11.9", - "tinyglobby": "^0.2.15", - "ufo": "^1.5.4", - "vitefu": "^1.1.1", - "xmlbuilder2": "^4.0.3", - "zod": "^3.24.2" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@rsbuild/core": "^2.0.0", - "vite": ">=7.0.0" - }, - "peerDependenciesMeta": { - "@rsbuild/core": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@tanstack/start-plugin-core/node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@tanstack/start-server-core": { - "version": "1.168.4", - "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.168.4.tgz", - "integrity": "sha512-YF9HRjIh8SyprQxOiAB1puXkGI4PqF2/StX00CXtmLOphFTfuShYOPvmQZXl2XZp6H9vt+qY+BNXucSuLzag9g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/history": "1.162.0", - "@tanstack/router-core": "1.171.2", - "@tanstack/start-client-core": "1.169.4", - "@tanstack/start-storage-context": "1.167.4", - "fetchdts": "^0.1.6", - "h3-v2": "npm:h3@2.0.1-rc.20", - "seroval": "^1.5.4" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/start-storage-context": { - "version": "1.167.4", - "resolved": "https://registry.npmjs.org/@tanstack/start-storage-context/-/start-storage-context-1.167.4.tgz", - "integrity": "sha512-hI93yABbvcaMWkCtewjxNAZOXcJIWhh7P8um7A76OHA2LmLFaR36Sm8eZ6OQHhPdFob4DMOkwDiCv9sckRvCow==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tanstack/router-core": "1.171.2" - }, - "engines": { - "node": ">=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/store": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.11.0.tgz", - "integrity": "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/virtual-file-routes": { - "version": "1.162.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.162.0.tgz", - "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz", - "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/whatwg-mimetype": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", - "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.6.tgz", - "integrity": "sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.6", - "ast-v8-to-istanbul": "^1.0.0", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.2", - "obug": "^2.1.1", - "std-env": "^4.0.0-rc.1", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.1.6", - "vitest": "4.1.6" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", - "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", - "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.6", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", - "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", - "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.6", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", - "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.6", - "@vitest/utils": "4.1.6", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", - "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", - "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.6", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "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", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ansis": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.0.tgz", - "integrity": "sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "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", - "peer": true - }, - "node_modules/argv-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", - "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-v8-to-istanbul": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", - "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-dead-code-elimination": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", - "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.31", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz", - "integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/before-after-hook": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", - "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "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/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "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", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", - "dev": true, - "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", - "peer": true - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/cheerio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", - "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.1", - "htmlparser2": "^10.1.0", - "parse5": "^7.3.0", - "parse5-htmlparser2-tree-adapter": "^7.1.0", - "parse5-parser-stream": "^7.1.2", - "undici": "^7.19.0", - "whatwg-mimetype": "^4.0.0" - }, - "engines": { - "node": ">=20.18.1" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cheerio/node_modules/undici": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", - "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-highlight": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", - "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "chalk": "^4.0.0", - "highlight.js": "^10.7.1", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^6.0.0", - "yargs": "^16.0.0" - }, - "bin": { - "highlight": "bin/highlight" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0" - } - }, - "node_modules/cli-highlight/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", - "peer": true, - "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/cli-highlight/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cli-highlight/node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cli-highlight/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cli-highlight/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "license": "MIT", - "peer": true, - "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==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/conventional-changelog-angular": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz", - "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/conventional-changelog-writer": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.4.0.tgz", - "integrity": "sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@simple-libs/stream-utils": "^1.2.0", - "conventional-commits-filter": "^5.0.0", - "handlebars": "^4.7.7", - "meow": "^13.0.0", - "semver": "^7.5.2" - }, - "bin": { - "conventional-changelog-writer": "dist/cli/index.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/conventional-changelog-writer/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-commits-filter": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", - "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/conventional-commits-parser": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", - "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@simple-libs/stream-utils": "^1.2.0", - "meow": "^13.0.0" - }, - "bin": { - "conventional-commits-parser": "dist/cli/index.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/convert-hrtime": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", - "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie-es": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", - "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cosmiconfig": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", - "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cosmiconfig/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.359", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.359.tgz", - "integrity": "sha512-8lPELWuYZIWk7NDvCNthtmMw/7Q5Wu25NpM4djFMHBmk8DubPAtL4YTOp7ou0e7HyJtwkVlWv8XMLURnrtgJQw==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/emojilib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", - "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/encoding-sniffer": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", - "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "iconv-lite": "^0.6.3", - "whatwg-encoding": "^3.1.1" - }, - "funding": { - "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-ci": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.2.0.tgz", - "integrity": "sha512-D5kWfzkmaOQDioPmiviWAVtKmpPT4/iJmMVQxWxMPJTFyTkdc5JQUfc5iXEeWxcOdsYTKSAiA/Age4NUOqKsRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "execa": "^8.0.0", - "java-properties": "^1.0.2" - }, - "engines": { - "node": "^18.17 || >=20.6.1" - } - }, - "node_modules/env-ci/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/env-ci/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/env-ci/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/env-ci/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/env-ci/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/env-ci/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/env-ci/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/execa": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", - "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.6", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.1", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.2.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.1.1" - }, - "engines": { - "node": "^18.19.0 || >=20.5.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/exsolve": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", - "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/fast-content-type-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", - "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "peer": true - }, - "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/fast-json-patch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", - "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-package-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz", - "integrity": "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "walk-up-path": "^4.0.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fetchdts": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.7.tgz", - "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/figures": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", - "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-unicode-supported": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/find-up-simple": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", - "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-versions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", - "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "semver-regex": "^4.0.5", - "super-regex": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/formatly": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/formatly/-/formatly-0.3.0.tgz", - "integrity": "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fd-package-json": "^2.0.0" - }, - "bin": { - "formatly": "bin/index.mjs" - }, - "engines": { - "node": ">=18.3.0" - } - }, - "node_modules/fs-extra": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", - "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-timeout": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", - "integrity": "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-stream": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", - "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sec-ant/readable-stream": "^0.4.1", - "is-stream": "^4.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/git-log-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", - "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "argv-formatter": "~1.0.0", - "spawn-error-forwarder": "~1.0.0", - "split2": "~1.0.0", - "stream-combiner2": "~1.1.1", - "through2": "~2.0.0", - "traverse": "0.6.8" - } - }, - "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/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", - "peer": true - }, - "node_modules/h3-v2": { - "name": "h3", - "version": "2.0.1-rc.20", - "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.20.tgz", - "integrity": "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "rou3": "^0.8.1", - "srvx": "^0.11.13" - }, - "bin": { - "h3": "bin/h3.mjs" - }, - "engines": { - "node": ">=20.11.1" - }, - "peerDependencies": { - "crossws": "^0.4.1" - }, - "peerDependenciesMeta": { - "crossws": { - "optional": true - } - } - }, - "node_modules/handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/happy-dom": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.9.0.tgz", - "integrity": "sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": ">=20.0.0", - "@types/whatwg-mimetype": "^3.0.2", - "@types/ws": "^8.18.1", - "entities": "^7.0.1", - "whatwg-mimetype": "^3.0.0", - "ws": "^8.18.3" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/happy-dom/node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/happy-dom/node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "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/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/hook-std": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-4.0.0.tgz", - "integrity": "sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/htmlparser2": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", - "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "entities": "^7.0.1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", - "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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", - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/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", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-from-esm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-2.0.0.tgz", - "integrity": "sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.3.4", - "import-meta-resolve": "^4.0.0" - }, - "engines": { - "node": ">=18.20" - } - }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/index-to-position": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", - "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "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-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-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/isbot": { - "version": "5.1.40", - "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.40.tgz", - "integrity": "sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==", - "dev": true, - "license": "Unlicense", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "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/issue-parser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.2.tgz", - "integrity": "sha512-7atWPjhGEIX3JEtMrOYd8TKzboYlq+5sNbdl9POiLYOI14G5HZiQbZP0Xj5EZdrufQVXfJlpTV0hys0CuxwxZw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "lodash.capitalize": "^4.2.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.uniqby": "^4.7.0" - }, - "engines": { - "node": "^18.17 || >=20.6.1" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/java-properties": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", - "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "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.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/json-with-bigint": { - "version": "3.5.8", - "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.8.tgz", - "integrity": "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/knip": { - "version": "5.88.1", - "resolved": "https://registry.npmjs.org/knip/-/knip-5.88.1.tgz", - "integrity": "sha512-tpy5o7zu1MjawVkLPuahymVJekYY3kYjvzcoInhIchgePxTlo+api90tBv2KfhAIe5uXh+mez1tAfmbv8/TiZg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/webpro" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/knip" - } - ], - "license": "ISC", - "dependencies": { - "@nodelib/fs.walk": "^1.2.3", - "fast-glob": "^3.3.3", - "formatly": "^0.3.0", - "jiti": "^2.6.0", - "minimist": "^1.2.8", - "oxc-resolver": "^11.19.1", - "picocolors": "^1.1.1", - "picomatch": "^4.0.1", - "smol-toml": "^1.5.2", - "strip-json-comments": "5.0.3", - "unbash": "^2.2.0", - "yaml": "^2.8.2", - "zod": "^4.1.11" - }, - "bin": { - "knip": "bin/knip.js", - "knip-bun": "bin/knip-bun.js" - }, - "engines": { - "node": ">=18.18.0" - }, - "peerDependencies": { - "@types/node": ">=18", - "typescript": ">=5.0.4 <7" - } - }, - "node_modules/knip/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "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-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "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.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "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/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash-es": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", - "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.capitalize": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", - "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.3", - "@babel/types": "^7.29.0", - "source-map-js": "^1.2.1" - } - }, - "node_modules/make-asynchronous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/make-asynchronous/-/make-asynchronous-1.1.0.tgz", - "integrity": "sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-event": "^6.0.0", - "type-fest": "^4.6.0", - "web-worker": "^1.5.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/marked": { - "version": "15.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", - "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/marked-terminal": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz", - "integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-escapes": "^7.0.0", - "ansi-regex": "^6.1.0", - "chalk": "^5.4.1", - "cli-highlight": "^2.1.11", - "cli-table3": "^0.6.5", - "node-emoji": "^2.2.0", - "supports-hyperlinks": "^3.1.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "marked": ">=1 <16" - } - }, - "node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT", - "peer": true - }, - "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/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", - "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa" - ], - "license": "MIT", - "peer": true, - "bin": { - "mime": "bin/cli.js" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/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/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "dev": true, - "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/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/nerf-dart": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", - "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/node-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", - "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@sindresorhus/is": "^4.6.0", - "char-regex": "^1.0.2", - "emojilib": "^2.4.0", - "skin-tone": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/node-releases": { - "version": "2.0.44", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", - "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/normalize-package-data": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", - "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", - "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm": { - "version": "10.9.8", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.9.8.tgz", - "integrity": "sha512-fYwb6ODSmHkqrJQQaCxY3M2lPf/mpgC7ik0HSzzIwG5CGtabRp4bNqikatvCoT42b5INQSqudVH0R7yVmC9hVg==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/promise-spawn", - "@npmcli/redact", - "@npmcli/run-script", - "@sigstore/tuf", - "abbrev", - "archy", - "cacache", - "chalk", - "ci-info", - "cli-columns", - "fastest-levenshtein", - "fs-minipass", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmhook", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minimatch", - "minipass", - "minipass-pipeline", - "ms", - "node-gyp", - "nopt", - "normalize-package-data", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "semver", - "spdx-expression-parse", - "ssri", - "supports-color", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which", - "write-file-atomic" - ], - "dev": true, - "license": "Artistic-2.0", - "peer": true, - "workspaces": [ - "docs", - "smoke-tests", - "mock-globals", - "mock-registry", - "workspaces/*" - ], - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^8.0.5", - "@npmcli/config": "^9.0.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^4.0.2", - "@npmcli/package-json": "^6.2.0", - "@npmcli/promise-spawn": "^8.0.3", - "@npmcli/redact": "^3.2.2", - "@npmcli/run-script": "^9.1.0", - "@sigstore/tuf": "^3.1.1", - "abbrev": "^3.0.1", - "archy": "~1.0.0", - "cacache": "^19.0.1", - "chalk": "^5.6.2", - "ci-info": "^4.4.0", - "cli-columns": "^4.0.0", - "fastest-levenshtein": "^1.0.16", - "fs-minipass": "^3.0.3", - "glob": "^10.5.0", - "graceful-fs": "^4.2.11", - "hosted-git-info": "^8.1.0", - "ini": "^5.0.0", - "init-package-json": "^7.0.2", - "is-cidr": "^5.1.1", - "json-parse-even-better-errors": "^4.0.0", - "libnpmaccess": "^9.0.0", - "libnpmdiff": "^7.0.5", - "libnpmexec": "^9.0.5", - "libnpmfund": "^6.0.5", - "libnpmhook": "^11.0.0", - "libnpmorg": "^7.0.0", - "libnpmpack": "^8.0.5", - "libnpmpublish": "^10.0.2", - "libnpmsearch": "^8.0.0", - "libnpmteam": "^7.0.0", - "libnpmversion": "^7.0.0", - "make-fetch-happen": "^14.0.3", - "minimatch": "^9.0.9", - "minipass": "^7.1.3", - "minipass-pipeline": "^1.2.4", - "ms": "^2.1.2", - "node-gyp": "^11.5.0", - "nopt": "^8.1.0", - "normalize-package-data": "^7.0.1", - "npm-audit-report": "^6.0.0", - "npm-install-checks": "^7.1.2", - "npm-package-arg": "^12.0.2", - "npm-pick-manifest": "^10.0.0", - "npm-profile": "^11.0.1", - "npm-registry-fetch": "^18.0.2", - "npm-user-validate": "^3.0.0", - "p-map": "^7.0.4", - "pacote": "^19.0.1", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "qrcode-terminal": "^0.12.0", - "read": "^4.1.0", - "semver": "^7.7.4", - "spdx-expression-parse": "^4.0.0", - "ssri": "^12.0.0", - "supports-color": "^9.4.0", - "tar": "^7.5.11", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^3.0.0", - "validate-npm-package-name": "^6.0.2", - "which": "^5.0.0", - "write-file-atomic": "^6.0.0" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/npm/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/@npmcli/agent": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "8.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/map-workspaces": "^4.0.1", - "@npmcli/metavuln-calculator": "^8.0.0", - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.1", - "@npmcli/query": "^4.0.0", - "@npmcli/redact": "^3.0.0", - "@npmcli/run-script": "^9.0.1", - "bin-links": "^5.0.0", - "cacache": "^19.0.1", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^8.0.0", - "json-parse-even-better-errors": "^4.0.0", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^10.2.2", - "minimatch": "^9.0.4", - "nopt": "^8.0.0", - "npm-install-checks": "^7.1.0", - "npm-package-arg": "^12.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.1", - "pacote": "^19.0.0", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "proggy": "^3.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^4.0.0", - "semver": "^7.3.7", - "ssri": "^12.0.0", - "treeverse": "^3.0.0", - "walk-up-path": "^3.0.1" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "9.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/map-workspaces": "^4.0.1", - "@npmcli/package-json": "^6.0.1", - "ci-info": "^4.0.0", - "ini": "^5.0.0", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "walk-up-path": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "6.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/promise-spawn": "^8.0.0", - "ini": "^5.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^10.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-bundled": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "4.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "glob": "^10.2.2", - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "8.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "cacache": "^19.0.0", - "json-parse-even-better-errors": "^4.0.0", - "pacote": "^20.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator/node_modules/pacote": { - "version": "20.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^6.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^9.0.0", - "cacache": "^19.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^12.0.0", - "npm-packlist": "^9.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^3.0.0", - "ssri": "^12.0.0", - "tar": "^7.5.10" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "6.2.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^6.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^8.0.0", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "8.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/query": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/redact": { - "version": "3.2.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "9.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "node-gyp": "^11.0.0", - "proc-log": "^5.0.0", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.4.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/core": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.4.3", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/sign": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0", - "make-fetch-happen": "^14.0.2", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/protobuf-specs": "^0.4.1", - "tuf-js": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/verify": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/agent-base": { - "version": "7.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "6.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/aproba": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/bin-links": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "cmd-shim": "^7.0.0", - "npm-normalize-package-bin": "^4.0.0", - "proc-log": "^5.0.0", - "read-cmd-shim": "^5.0.0", - "write-file-atomic": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "19.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/chalk": { - "version": "5.6.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/ci-info": { - "version": "4.4.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "4.1.3", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "ip-regex": "^5.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/cross-spawn": { - "version": "7.0.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/debug": { - "version": "4.4.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/diff": { - "version": "5.2.2", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/npm/node_modules/eastasianwidth": { - "version": "0.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/exponential-backoff": { - "version": "3.1.3", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.16", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/npm/node_modules/fdir": { - "version": "6.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/foreground-child": { - "version": "3.3.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/glob": { - "version": "10.5.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "8.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "7.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/npm/node_modules/ini": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/init-package-json": { - "version": "7.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/package-json": "^6.0.0", - "npm-package-arg": "^12.0.0", - "promzard": "^2.0.0", - "read": "^4.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/ip-address": { - "version": "10.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/is-cidr": { - "version": "5.1.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "cidr-regex": "^4.1.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/jackspeak": { - "version": "3.4.3", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/just-diff": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "5.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "9.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-package-arg": "^12.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "7.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^8.0.5", - "@npmcli/installed-package-contents": "^3.0.0", - "binary-extensions": "^2.3.0", - "diff": "^5.1.0", - "minimatch": "^9.0.4", - "npm-package-arg": "^12.0.0", - "pacote": "^19.0.0", - "tar": "^7.5.11" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "9.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^8.0.5", - "@npmcli/run-script": "^9.0.1", - "ci-info": "^4.0.0", - "npm-package-arg": "^12.0.0", - "pacote": "^19.0.0", - "proc-log": "^5.0.0", - "read": "^4.0.0", - "read-package-json-fast": "^4.0.0", - "semver": "^7.3.7", - "walk-up-path": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "6.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^8.0.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "11.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "8.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/arborist": "^8.0.5", - "@npmcli/run-script": "^9.0.1", - "npm-package-arg": "^12.0.0", - "pacote": "^19.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "10.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "ci-info": "^4.0.0", - "normalize-package-data": "^7.0.0", - "npm-package-arg": "^12.0.0", - "npm-registry-fetch": "^18.0.1", - "proc-log": "^5.0.0", - "semver": "^7.3.7", - "sigstore": "^3.0.0", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^6.0.1", - "@npmcli/run-script": "^9.0.1", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "10.4.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "14.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/minimatch": { - "version": "9.0.9", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/minipass": { - "version": "7.1.3", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/minizlib": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/negotiator": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "11.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "tinyglobby": "^0.2.12", - "which": "^5.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/nopt": { - "version": "8.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "abbrev": "^3.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "7.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "hosted-git-info": "^8.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "7.1.2", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "12.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "9.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "ignore-walk": "^7.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "10.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-install-checks": "^7.1.0", - "npm-normalize-package-bin": "^4.0.0", - "npm-package-arg": "^12.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-profile": { - "version": "11.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "18.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/redact": "^3.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^14.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^12.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/p-map": { - "version": "7.0.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/package-json-from-dist": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true - }, - "node_modules/npm/node_modules/pacote": { - "version": "19.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@npmcli/git": "^6.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^9.0.0", - "cacache": "^19.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^12.0.0", - "npm-packlist": "^9.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^3.0.0", - "ssri": "^12.0.0", - "tar": "^7.5.10" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/path-scurry": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/picomatch": { - "version": "4.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "7.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/proc-log": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/proggy": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "read": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "peer": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/npm/node_modules/read": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "mute-stream": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/npm/node_modules/semver": { - "version": "7.7.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/sigstore": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0", - "@sigstore/sign": "^3.1.0", - "@sigstore/tuf": "^3.1.0", - "@sigstore/verify": "^2.1.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks": { - "version": "2.8.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.2.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.5.0", - "dev": true, - "inBundle": true, - "license": "CC-BY-3.0", - "peer": true - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.23", - "dev": true, - "inBundle": true, - "license": "CC0-1.0", - "peer": true - }, - "node_modules/npm/node_modules/ssri": { - "version": "12.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/supports-color": { - "version": "9.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/npm/node_modules/tar": { - "version": "7.5.11", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/tinyglobby": { - "version": "0.2.15", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/npm/node_modules/treeverse": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/tuf-js": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tufjs/models": "3.0.1", - "debug": "^4.4.1", - "make-fetch-happen": "^14.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/tuf-js/node_modules/@tufjs/models": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/unique-filename": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "unique-slug": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/unique-slug": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true - }, - "node_modules/npm/node_modules/which": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/which/node_modules/isexe": { - "version": "3.1.5", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/wrap-ansi": { - "version": "8.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/yallist": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "BlueOak-1.0.0", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "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", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/oxc-resolver": { - "version": "11.19.1", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.19.1.tgz", - "integrity": "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxc-resolver/binding-android-arm-eabi": "11.19.1", - "@oxc-resolver/binding-android-arm64": "11.19.1", - "@oxc-resolver/binding-darwin-arm64": "11.19.1", - "@oxc-resolver/binding-darwin-x64": "11.19.1", - "@oxc-resolver/binding-freebsd-x64": "11.19.1", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", - "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", - "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", - "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", - "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", - "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", - "@oxc-resolver/binding-linux-x64-musl": "11.19.1", - "@oxc-resolver/binding-openharmony-arm64": "11.19.1", - "@oxc-resolver/binding-wasm32-wasi": "11.19.1", - "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", - "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", - "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" - } - }, - "node_modules/p-each-series": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", - "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-event": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", - "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-timeout": "^6.1.2" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-filter": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-4.1.0.tgz", - "integrity": "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-map": "^7.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-reduce": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", - "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-timeout": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", - "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "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", - "peer": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", - "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.1.0", - "type-fest": "^4.39.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", - "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "domhandler": "^5.0.3", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-parser-stream": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", - "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "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-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "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.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-ms": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true, - "license": "ISC", - "peer": true - }, - "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/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "peer": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", - "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", - "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.6" - } - }, - "node_modules/read-package-up": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", - "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "find-up-simple": "^1.0.0", - "read-pkg": "^9.0.0", - "type-fest": "^4.6.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", - "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.3", - "normalize-package-data": "^6.0.0", - "parse-json": "^8.0.0", - "type-fest": "^4.6.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/registry-auth-token": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz", - "integrity": "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@pnpm/npm-conf": "^3.0.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "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/rolldown": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz", - "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.130.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.1", - "@rolldown/binding-darwin-arm64": "1.0.1", - "@rolldown/binding-darwin-x64": "1.0.1", - "@rolldown/binding-freebsd-x64": "1.0.1", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.1", - "@rolldown/binding-linux-arm64-gnu": "1.0.1", - "@rolldown/binding-linux-arm64-musl": "1.0.1", - "@rolldown/binding-linux-ppc64-gnu": "1.0.1", - "@rolldown/binding-linux-s390x-gnu": "1.0.1", - "@rolldown/binding-linux-x64-gnu": "1.0.1", - "@rolldown/binding-linux-x64-musl": "1.0.1", - "@rolldown/binding-openharmony-arm64": "1.0.1", - "@rolldown/binding-wasm32-wasi": "1.0.1", - "@rolldown/binding-win32-arm64-msvc": "1.0.1", - "@rolldown/binding-win32-x64-msvc": "1.0.1" - } - }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/rou3": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz", - "integrity": "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "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-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/semantic-release": { - "version": "24.2.9", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz", - "integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@semantic-release/commit-analyzer": "^13.0.0-beta.1", - "@semantic-release/error": "^4.0.0", - "@semantic-release/github": "^11.0.0", - "@semantic-release/npm": "^12.0.2", - "@semantic-release/release-notes-generator": "^14.0.0-beta.1", - "aggregate-error": "^5.0.0", - "cosmiconfig": "^9.0.0", - "debug": "^4.0.0", - "env-ci": "^11.0.0", - "execa": "^9.0.0", - "figures": "^6.0.0", - "find-versions": "^6.0.0", - "get-stream": "^6.0.0", - "git-log-parser": "^1.2.0", - "hook-std": "^4.0.0", - "hosted-git-info": "^8.0.0", - "import-from-esm": "^2.0.0", - "lodash-es": "^4.17.21", - "marked": "^15.0.0", - "marked-terminal": "^7.3.0", - "micromatch": "^4.0.2", - "p-each-series": "^3.0.0", - "p-reduce": "^3.0.0", - "read-package-up": "^11.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.3.2", - "semver-diff": "^5.0.0", - "signale": "^1.2.1", - "yargs": "^17.5.1" - }, - "bin": { - "semantic-release": "bin/semantic-release.js" - }, - "engines": { - "node": ">=20.8.1" - } - }, - "node_modules/semantic-release/node_modules/aggregate-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", - "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "clean-stack": "^5.2.0", - "indent-string": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/clean-stack": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.3.0.tgz", - "integrity": "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "escape-string-regexp": "5.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-5.0.0.tgz", - "integrity": "sha512-0HbGtOm+S7T6NGQ/pxJSJipJvc4DK3FcRVMRkhsIwJDJ4Jcz5DQC1cPPzB5GhzyHjwttW878HaWQq46CkL3cqg==", - "deprecated": "Deprecated as the semver package now supports this built-in.", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/seroval": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", - "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/seroval-plugins": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.4.tgz", - "integrity": "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "seroval": "^1.0" - } - }, - "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/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/signale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", - "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "chalk": "^2.3.2", - "figures": "^2.0.0", - "pkg-conf": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/signale/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/signale/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/signale/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/signale/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/signale/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/signale/node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/signale/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/signale/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/skin-tone": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", - "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "unicode-emoji-modifier-base": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/smol-toml": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", - "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 18" - }, - "funding": { - "url": "https://github.com/sponsors/cyyynthia" - } - }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">= 12" - } - }, - "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==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-error-forwarder": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", - "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0", - "peer": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", - "dev": true, - "license": "CC0-1.0", - "peer": true - }, - "node_modules/split2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", - "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "through2": "~2.0.0" - } - }, - "node_modules/srvx": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.15.tgz", - "integrity": "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "srvx": "bin/srvx.mjs" - }, - "engines": { - "node": ">=20.16.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "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", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", - "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/super-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.1.0.tgz", - "integrity": "sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "function-timeout": "^1.0.1", - "make-asynchronous": "^1.0.1", - "time-span": "^5.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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-hyperlinks": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", - "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=14.18" - }, - "funding": { - "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" - } - }, - "node_modules/tailwind-merge": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", - "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/temp-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", - "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/tempy": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.2.0.tgz", - "integrity": "sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-stream": "^3.0.0", - "temp-dir": "^3.0.0", - "type-fest": "^2.12.2", - "unique-string": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/time-span": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", - "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "convert-hrtime": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", - "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "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/traverse": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", - "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "license": "0BSD", - "optional": true - }, - "node_modules/tsx": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz", - "integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unbash/-/unbash-2.2.0.tgz", - "integrity": "sha512-X2wH19RAPZE3+ldGicOkoj/SIA83OIxcJ6Cuaw23hf8Xc6fQpvZXY0SftE2JgS0QhYLUG4uwodSI3R53keyh7w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - } - }, - "node_modules/undici": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", - "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, - "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicode-emoji-modifier-base": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", - "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "crypto-random-string": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/universal-user-agent": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", - "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unplugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", - "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "picomatch": "^4.0.3", - "webpack-virtual-modules": "^0.6.2" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/url-join": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", - "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vite": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz", - "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "rolldown": "1.0.1", - "tinyglobby": "^0.2.16" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vitefu": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", - "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", - "dev": true, - "license": "MIT", - "peer": true, - "workspaces": [ - "tests/deps/*", - "tests/projects/*", - "tests/projects/workspace/packages/*" - ], - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", - "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.1.6", - "@vitest/mocker": "4.1.6", - "@vitest/pretty-format": "4.1.6", - "@vitest/runner": "4.1.6", - "@vitest/snapshot": "4.1.6", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.6", - "@vitest/browser-preview": "4.1.6", - "@vitest/browser-webdriverio": "4.1.6", - "@vitest/coverage-istanbul": "4.1.6", - "@vitest/coverage-v8": "4.1.6", - "@vitest/ui": "4.1.6", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/walk-up-path": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", - "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/web-worker": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", - "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", - "dev": true, - "license": "Apache-2.0", - "peer": true - }, - "node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "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/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlbuilder2": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz", - "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oozcitak/dom": "^2.0.2", - "@oozcitak/infra": "^2.0.2", - "@oozcitak/util": "^10.0.0", - "js-yaml": "^4.1.1" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/package.json b/package.json index 618a5c8..d96a4af 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,22 @@ "./shopify/actions/cart/*": "./shopify/actions/cart/*.ts", "./shopify/actions/user/*": "./shopify/actions/user/*.ts", "./shopify/utils/*": "./shopify/utils/*.ts", + "./magento": "./magento/index.ts", + "./magento/client": "./magento/client.ts", + "./magento/types": "./magento/types.ts", + "./magento/middleware": "./magento/middleware.ts", + "./magento/loaders/*": "./magento/loaders/*.ts", + "./magento/actions/*": "./magento/actions/*.ts", + "./magento/utils/*": "./magento/utils/*.ts", + "./magento/hooks/*": "./magento/hooks/*.ts", + "./algolia": "./algolia/index.ts", + "./algolia/client": "./algolia/client.ts", + "./algolia/types": "./algolia/types.ts", + "./algolia/loaders/*": "./algolia/loaders/*.ts", + "./salesforce": "./salesforce/index.ts", + "./salesforce/types": "./salesforce/types.ts", + "./salesforce/utils/*": "./salesforce/utils/*.ts", + "./salesforce/loaders/products/*": "./salesforce/loaders/products/*.ts", "./vtex": "./vtex/index.ts", "./vtex/commerceLoaders": "./vtex/commerceLoaders.ts", "./vtex/mod": "./vtex/mod.ts", @@ -63,7 +79,13 @@ "./website/flags/multivariate/*": "./website/flags/multivariate/*.ts", "./website/utils/*": "./website/utils/*.ts", "./website/sections/*": "./website/sections/*.tsx", - "./website/sections/Seo/*": "./website/sections/Seo/*.tsx" + "./website/sections/Seo/*": "./website/sections/Seo/*.tsx", + "./blog": "./blog/index.ts", + "./blog/mod": "./blog/mod.ts", + "./blog/types": "./blog/types.ts", + "./blog/commerceLoaders": "./blog/commerceLoaders.ts", + "./blog/loaders/*": "./blog/loaders/*.ts", + "./blog/core/*": "./blog/core/*.ts" }, "scripts": { "generate:manifests": "tsx scripts/generate-manifests.ts", @@ -92,7 +114,11 @@ "url": "https://github.com/decocms/apps-start.git" }, "files": [ + "blog/", "commerce/", + "magento/", + "algolia/", + "salesforce/", "shopify/", "vtex/", "resend/", @@ -109,18 +135,26 @@ "access": "public" }, "peerDependencies": { - "@decocms/start": ">=5.3.0-rc.2", + "@decocms/start": ">=5.3.0", "@tanstack/react-query": ">=5", + "@tanstack/react-start": ">=1", + "algoliasearch": "^5", "react": ">=18", "react-dom": ">=18" }, + "peerDependenciesMeta": { + "algoliasearch": { + "optional": true + } + }, "devDependencies": { "@biomejs/biome": "^2.4.7", - "@decocms/start": "5.3.0-rc.2", + "@decocms/start": "5.3.0", "@semantic-release/exec": "^7.1.0", "@tanstack/react-query": "^5.90.21", "@types/react": "^19.0.0", "@vitest/coverage-v8": "^4.1.0", + "algoliasearch": "^5.53.0", "happy-dom": "^20.9.0", "knip": "^5.86.0", "react": "^19.0.0", diff --git a/registry.ts b/registry.ts index 891ee5a..424a5d2 100644 --- a/registry.ts +++ b/registry.ts @@ -53,6 +53,13 @@ export const APP_REGISTRY: AppRegistry = [ category: "email", description: "Transactional email via Resend", }, + { + blockKey: "deco-blog", + module: () => import("./blog/mod"), + displayName: "Blog", + category: "content", + description: "Blog posts, categories, and authors from CMS collections", + }, ]; export default APP_REGISTRY; diff --git a/resend/client.ts b/resend/client.ts index 2df8ffa..1a11cab 100644 --- a/resend/client.ts +++ b/resend/client.ts @@ -15,6 +15,15 @@ let _config: ResendConfig | null = null; * subject: "Contact form submission", * }); * ``` + * + * TODO(secrets-decrypt): Add an `initResendFromBlocks(blocks, blockKey?)` + * helper that mirrors magento/algolia/vtex. The Deco CMS Resend block + * stores `apiKey` as an encrypted Secret reference (`{ encrypted, name }`) + * — sites currently have to call `configureResend()` with a manually + * resolved env var, missing the AES-CBC decrypt path via + * `@decocms/start/sdk/crypto#resolveSecret`. Until that ships, sites + * keep passing a string they obtain from `process.env` or a custom + * resolver. */ export function configureResend(config: ResendConfig) { _config = config; diff --git a/salesforce/README.md b/salesforce/README.md new file mode 100644 index 0000000..975d336 --- /dev/null +++ b/salesforce/README.md @@ -0,0 +1,122 @@ +# Salesforce Marketing Cloud Personalization app + +Ports the Salesforce Marketing Cloud Personalization (formerly Evergage) +campaign API from `deco-cx/apps/salesforce` (Fresh/Deno) to +`@decocms/apps/salesforce` (TanStack Start/Node), following the same +shape as `algolia/` and `magento/`. + +## Status + +**Initial scaffold** — covers the campaign personalization read path +(homepage shelves, PDP recommendations, cart cross-sell). No write +actions yet; the legacy `apps/salesforce/actions/*` aren't ported. + +## What's here + +- `types.ts` — `SalesforceProduct` (open-ended via index signature so + dataset-specific columns survive), `PersonalizationBody`, + `PersonalizationResponse`, `CampaignResponse`, `ParsedUserCookie`. +- `utils/parseUserCookie.ts` — decode Evergage's URL-encoded JSON cookie + to `{ encryptedId | anonymousId }`. Falls back to + `{ anonymousId: "anonymous" }` so first-visit requests still hit the + default campaign instead of erroring. +- `utils/httpClient.ts` — runtime-agnostic Proxy client supporting the + legacy indexed-route syntax (`client["POST /api2/event/:dataset"]`). + Compatible with Cloudflare Workers / Bun / Deno / modern Node — only + requires the global `fetch`. +- `utils/transform.ts` — `createProductTransformer({ propertyMapper? })` + factory that converts an Evergage product into a schema.org `Product`. + Sites pass a `propertyMapper` to project their dataset's custom + columns (e.g. `Marca`, `Volume`, `Linha`) into `PropertyValue[]`. +- `loaders/products/list.ts` — campaign personalization shelf (homepage). +- `loaders/products/listRecomended.ts` — related-product recommendations + (PDP / PDC). +- `loaders/products/listCart.ts` — cart-aware cross-sell. + +## Why no `configureSalesforce` + +Unlike Magento / VTEX / Algolia (one global SDK client per site), the +Salesforce loaders here are stateless — every call is a plain `fetch` +POST to `/api2/event/:dataset`, and a single site might run multiple +datasets (homepage uses dataset A, PDP uses dataset B). Passing +`baseUrl` / `dataset` / `campaignId` / `cookieName` via loader props +keeps the package free of hidden global state and lets the CMS block +remain the single source of truth. + +## Wiring in a site + +```ts +// src/packs/salesforce/products/list.ts (site-side wrapper) +import salesforceList from "@decocms/apps/salesforce/loaders/products/list"; +import { granadoPropertyMapper } from "../attributeMapper"; + +interface SiteProps { + baseUrl: string; + dataset: string; + campaignId: string; + cookieName: string; +} + +export default function loader(props: SiteProps) { + return salesforceList({ + ...props, + currencyCode: "BRL", + propertyMapper: granadoPropertyMapper, + }); +} +``` + +```ts +// src/packs/salesforce/attributeMapper.ts (site-specific) +import type { PropertyMapper } from "@decocms/apps/salesforce"; + +export const granadoPropertyMapper: PropertyMapper = (product) => { + const props: { "@type": "PropertyValue"; name: string; value: unknown }[] = []; + if (product.Marca) props.push({ "@type": "PropertyValue", name: "marca", value: product.Marca }); + if (product.Volume) props.push({ "@type": "PropertyValue", name: "volume", value: product.Volume }); + if (product.Linha) props.push({ "@type": "PropertyValue", name: "linha", value: product.Linha }); + if (product.tag) props.push({ "@type": "PropertyValue", name: "tag__phebo", value: product.tag }); + if (product.freeShipping) { + props.push({ "@type": "PropertyValue", name: "free_shipping__phebo", value: product.freeShipping }); + } + if (product.SubCategoria) { + props.push({ "@type": "PropertyValue", name: "subCategory", value: product.SubCategoria }); + } + return props; +}; +``` + +## Cookie reading and the framework gap + +The campaign API expects a user identifier on every request. Evergage +drops `_evga_` on the browser, encoded as JSON. The loaders +read this cookie via `getCookies()` from `@tanstack/react-start/server` +— which reads the in-flight request out of `AsyncLocalStorage` rather +than from an explicit `req` argument. + +Why ALS instead of a `req` parameter? In `@decocms/start`, the +`commerceLoader(resolvedProps)` resolver path doesn't forward the +request object to the loader (see `commerce/resolve.ts`), so loaders +that need cookies have to recover them from the framework's stored +context. This matches what the in-tree Magento loaders already do. + +Sites that aren't using `@decocms/start` (raw TanStack Start, tests, +etc.) can call the loader from inside a server function — the same +`getCookies()` resolution works as long as the call is inside a +TanStack Start request boundary. + +## Error handling + +Each loader wraps its POST in a try/catch that logs to `console.error` +under `[salesforce/products/...]` and returns `null`. The legacy Deno +loaders returned silent `null` on error; we keep the same return shape +(callers don't need to handle rejections) but surface the error so API +outages and CORS regressions don't hide behind an empty shelf. + +## Tests + +```bash +bun run test salesforce +``` + +The unit tests mock `fetch` directly — no Evergage credentials needed. diff --git a/salesforce/__tests__/httpClient.test.ts b/salesforce/__tests__/httpClient.test.ts new file mode 100644 index 0000000..23f0138 --- /dev/null +++ b/salesforce/__tests__/httpClient.test.ts @@ -0,0 +1,201 @@ +/** + * Tests for utils/httpClient.ts. + * + * The legacy `apps/utils/http.ts` indexed-route Proxy is what every + * Deno-era loader called into, so this test file pins the call shapes + * existing site code still uses: + * - `client["POST /api2/event/:dataset"]({ dataset }, { body })` + * - `client.get(path)` / `client.post(path, body)` convenience methods + * - `:name` placeholder substitution and `*name` legacy Deno-era syntax + * - default `x-requested-with` header propagation + * - `{ json, ok, status, headers }` response shape + * + * `fetch` is mocked so we never touch the network. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createHttpClient } from "../utils/httpClient"; + +interface CallRecord { + url: string; + init: { + method?: string; + body?: string; + headers: Record; + }; +} + +type MockedFetch = typeof fetch & { + mock: { calls: [string, CallRecord["init"]][] }; +}; + +function makeFetch( + jsonBody: unknown = { ok: true }, + init: { status?: number; headers?: Record } = {}, +): MockedFetch { + return vi.fn(async () => ({ + json: async () => jsonBody, + ok: (init.status ?? 200) < 400, + status: init.status ?? 200, + headers: new Headers(init.headers ?? {}), + })) as unknown as MockedFetch; +} + +function callAt(fetcher: MockedFetch, idx: number): CallRecord { + const call = fetcher.mock.calls[idx]; + return { url: call[0], init: call[1] }; +} + +describe("createHttpClient", () => { + let originalFetch: typeof fetch; + + beforeEach(() => { + originalFetch = globalThis.fetch; + }); + + afterEach(() => { + globalThis.fetch = originalFetch; + }); + + it("strips trailing slash from base URL", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com/", fetcher }); + await client.get("/health"); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/health"); + }); + + it("uses global fetch when no fetcher is provided", async () => { + globalThis.fetch = makeFetch({ ok: true }); + const client = createHttpClient({ base: "https://api.example.com" }); + const result = await client.get("/health"); + expect(result).toEqual({ ok: true }); + expect(globalThis.fetch).toHaveBeenCalledOnce(); + }); + + describe(".get / .post convenience methods", () => { + it(".get returns parsed JSON directly", async () => { + const fetcher = makeFetch({ items: [1, 2, 3] }); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + const result = await client.get("/things"); + expect(result).toEqual({ items: [1, 2, 3] }); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/things"); + }); + + it(".post sends JSON body with Content-Type header", async () => { + const fetcher = makeFetch({ created: true }); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client.post("/things", { name: "thing" }); + const { init } = callAt(fetcher, 0); + expect(init.method).toBe("POST"); + expect(init.body).toBe(JSON.stringify({ name: "thing" })); + expect(init.headers["Content-Type"]).toBe("application/json"); + }); + + it("merges default headers from options into request", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ + base: "https://api.example.com", + fetcher, + headers: { "x-requested-with": "XMLHttpRequest" }, + }); + await client.post("/things", { name: "x" }); + const { init } = callAt(fetcher, 0); + expect(init.headers["x-requested-with"]).toBe("XMLHttpRequest"); + }); + + it("accepts a Headers object for default headers", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ + base: "https://api.example.com", + fetcher, + headers: new Headers({ "x-token": "abc" }), + }); + await client.get("/things"); + const { init } = callAt(fetcher, 0); + expect(init.headers["x-token"]).toBe("abc"); + }); + }); + + describe("indexed-route Proxy syntax", () => { + it("replaces `:name` path placeholders with the matching param", async () => { + const fetcher = makeFetch({ campaignResponses: [] }); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["POST /api2/event/:dataset"]({ dataset: "production" }, { body: { foo: 1 } }); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/api2/event/production"); + }); + + it("url-encodes placeholder values", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["GET /catalog/:slug"]({ slug: "shoes & boots" }); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/catalog/shoes%20%26%20boots"); + }); + + it("removes leftover `*name` placeholders when no value is provided", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["GET /catalog/*path"]({}); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/catalog"); + }); + + it("substitutes `*name` placeholders when value is present", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["GET /catalog/*path"]({ path: "shoes/boots" }); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/catalog/shoes/boots"); + }); + + it("serialises remaining params as the body on non-GET requests", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["POST /api2/event/:dataset"]({ + dataset: "production", + extraField: "value", + }); + const { init } = callAt(fetcher, 0); + expect(JSON.parse(init.body ?? "")).toEqual({ extraField: "value" }); + }); + + it("prefers explicit { body } over remaining params", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["POST /api2/event/:dataset"]( + { dataset: "production", ignored: "yes" }, + { body: { real: "body" } }, + ); + const { init } = callAt(fetcher, 0); + expect(JSON.parse(init.body ?? "")).toEqual({ real: "body" }); + }); + + it("encodes remaining params as querystring on GET", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["GET /search"]({ q: "shoes", limit: 12 }); + const call = callAt(fetcher, 0); + expect(call.url).toBe("https://api.example.com/search?q=shoes&limit=12"); + expect(call.init.body).toBeUndefined(); + }); + + it("returns { json, ok, status, headers } from indexed routes", async () => { + const fetcher = makeFetch({ result: 1 }, { status: 201, headers: { etag: "abc" } }); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + const response = await client["POST /things"]({ name: "x" }); + expect(response.status).toBe(201); + expect(response.ok).toBe(true); + expect(response.headers.get("etag")).toBe("abc"); + expect(await response.json()).toEqual({ result: 1 }); + }); + + it("appends query when no params remain but route already has `?`", async () => { + const fetcher = makeFetch(); + const client = createHttpClient({ base: "https://api.example.com", fetcher }); + await client["GET /search?fixed=1"]({ q: "shoes" }); + expect(callAt(fetcher, 0).url).toBe("https://api.example.com/search?fixed=1&q=shoes"); + }); + + it("returns undefined for unknown property accesses", () => { + const client = createHttpClient({ base: "https://api.example.com" }); + // biome-ignore lint/suspicious/noExplicitAny: type-erased access for test + expect((client as any).somethingMadeUp).toBeUndefined(); + }); + }); +}); diff --git a/salesforce/__tests__/parseUserCookie.test.ts b/salesforce/__tests__/parseUserCookie.test.ts new file mode 100644 index 0000000..b43bd33 --- /dev/null +++ b/salesforce/__tests__/parseUserCookie.test.ts @@ -0,0 +1,89 @@ +/** + * Tests for utils/parseUserCookie.ts. + * + * Locks the contract that downstream loaders depend on: + * - puid wins over uuid (signed-in identity > anonymous device id) + * - uuid is used when puid is missing + * - empty / missing / malformed cookies fall back to "anonymous" + * + * The fallback is load-bearing — Evergage rejects requests with a + * missing user identifier, so an unparseable cookie must not surface + * as `{}`. + */ +import { describe, expect, it } from "vitest"; +import { parseUserCookie } from "../utils/parseUserCookie"; + +const encode = (obj: unknown) => encodeURIComponent(JSON.stringify(obj)); + +describe("parseUserCookie", () => { + it("returns anonymous fallback when cookie is undefined", () => { + expect(parseUserCookie(undefined)).toEqual({ anonymousId: "anonymous" }); + }); + + it("returns anonymous fallback when cookie is null", () => { + expect(parseUserCookie(null)).toEqual({ anonymousId: "anonymous" }); + }); + + it("returns anonymous fallback when cookie is empty string", () => { + expect(parseUserCookie("")).toEqual({ anonymousId: "anonymous" }); + }); + + it("returns anonymous fallback when cookie is whitespace only", () => { + expect(parseUserCookie(" ")).toEqual({ anonymousId: "anonymous" }); + }); + + it("returns anonymous fallback when cookie is not valid JSON", () => { + expect(parseUserCookie("not-json")).toEqual({ anonymousId: "anonymous" }); + }); + + it("returns anonymous fallback when JSON value is not an object", () => { + expect(parseUserCookie(encode("string-value"))).toEqual({ anonymousId: "anonymous" }); + expect(parseUserCookie(encode(42))).toEqual({ anonymousId: "anonymous" }); + expect(parseUserCookie(encode(null))).toEqual({ anonymousId: "anonymous" }); + }); + + it("maps puid to encryptedId", () => { + expect(parseUserCookie(encode({ puid: "user-123" }))).toEqual({ + encryptedId: "user-123", + }); + }); + + it("maps uuid to anonymousId", () => { + expect(parseUserCookie(encode({ uuid: "device-abc" }))).toEqual({ + anonymousId: "device-abc", + }); + }); + + it("prefers puid over uuid when both are present", () => { + expect(parseUserCookie(encode({ puid: "user-123", uuid: "device-abc" }))).toEqual({ + encryptedId: "user-123", + }); + }); + + it("returns anonymous fallback when puid is empty string", () => { + expect(parseUserCookie(encode({ puid: "", uuid: "device-abc" }))).toEqual({ + anonymousId: "device-abc", + }); + }); + + it("returns anonymous fallback when both puid and uuid are empty/missing", () => { + expect(parseUserCookie(encode({}))).toEqual({ anonymousId: "anonymous" }); + expect(parseUserCookie(encode({ puid: "", uuid: "" }))).toEqual({ + anonymousId: "anonymous", + }); + }); + + it("returns anonymous fallback when puid/uuid are non-string types", () => { + expect(parseUserCookie(encode({ puid: 42, uuid: true }))).toEqual({ + anonymousId: "anonymous", + }); + }); + + it("decodes URL-encoded values", () => { + // Evergage encodes the JSON with encodeURIComponent — make sure + // embedded special chars (e.g. = / : in base64 ids) round-trip. + const puid = "abc=def+ghi/jkl"; + const cookie = encodeURIComponent(JSON.stringify({ puid })); + expect(parseUserCookie(cookie)).toEqual({ encryptedId: puid }); + }); +}); diff --git a/salesforce/__tests__/transform.test.ts b/salesforce/__tests__/transform.test.ts new file mode 100644 index 0000000..e4ad57f --- /dev/null +++ b/salesforce/__tests__/transform.test.ts @@ -0,0 +1,227 @@ +/** + * Tests for utils/transform.ts. + * + * The Salesforce transformer is the only spot in the upstream package + * where consumer-specific behavior (the dataset's custom column shape) + * shows through, via the `propertyMapper` hook. The tests here lock: + * + * - default mapper outputs the always-present Evergage columns + * (itemType, categories) without dragging in dataset-specific + * fields, + * - a custom propertyMapper sees the raw Evergage product (including + * custom columns via the index signature), + * - schema.org shape is stable (productID precedence, AggregateOffer + * surface, isVariantOf hasVariant). + * + * These match the regressions the legacy `apps/salesforce/utils/ + * transform.ts` watched for over its lifetime. + */ +import { describe, expect, it } from "vitest"; +import type { SalesforceProduct } from "../types"; +import { + createProductTransformer, + type PropertyMapper, + toImages, + toOffer, +} from "../utils/transform"; + +const baseProduct = (overrides: Partial = {}): SalesforceProduct => ({ + id: "SKU-42", + name: "Test Product", + price: 100, + salePrice: 80, + inventoryCount: 7, + imageUrls: ["https://cdn.example.com/p/42.jpg"], + url: "https://loja.example.com/p/test", + currency: "BRL", + itemType: "simple", + categories: ["category-a", "category-b"], + ...overrides, +}); + +describe("toOffer", () => { + it("emits InStock when inventoryCount > 0", () => { + const [offer] = toOffer({ product: baseProduct(), currencyCode: "BRL" }); + expect(offer.availability).toBe("https://schema.org/InStock"); + expect(offer.inventoryLevel?.value).toBe(7); + }); + + it("emits OutOfStock when inventoryCount is 0", () => { + const [offer] = toOffer({ + product: baseProduct({ inventoryCount: 0 }), + currencyCode: "BRL", + }); + expect(offer.availability).toBe("https://schema.org/OutOfStock"); + }); + + it("falls back to price when salePrice is missing", () => { + const [offer] = toOffer({ + product: baseProduct({ salePrice: undefined }), + currencyCode: "BRL", + }); + expect(offer.price).toBe(100); + }); + + it("uses salePrice as the primary price when present", () => { + const [offer] = toOffer({ product: baseProduct(), currencyCode: "BRL" }); + expect(offer.price).toBe(80); + }); + + it("threads currencyCode into priceCurrency", () => { + const [offer] = toOffer({ product: baseProduct(), currencyCode: "USD" }); + expect(offer.priceCurrency).toBe("USD"); + }); + + it("emits ListPrice + SalePrice priceSpecification entries", () => { + const [offer] = toOffer({ product: baseProduct(), currencyCode: "BRL" }); + expect(offer.priceSpecification).toEqual([ + { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/ListPrice", + price: 100, + }, + { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/SalePrice", + price: 80, + }, + ]); + }); +}); + +describe("toImages", () => { + it("maps each imageUrl to a schema.org ImageObject", () => { + const images = toImages( + baseProduct({ + imageUrls: ["https://cdn.example.com/a.jpg", "https://cdn.example.com/b.jpg"], + }), + ); + expect(images).toEqual([ + { + "@type": "ImageObject", + encodingFormat: "image", + alternateName: "https://cdn.example.com/a.jpg", + url: "https://cdn.example.com/a.jpg", + }, + { + "@type": "ImageObject", + encodingFormat: "image", + alternateName: "https://cdn.example.com/b.jpg", + url: "https://cdn.example.com/b.jpg", + }, + ]); + }); + + it("returns an empty array when imageUrls is empty", () => { + expect(toImages(baseProduct({ imageUrls: [] }))).toEqual([]); + }); +}); + +describe("createProductTransformer", () => { + it("uses default mapper when no propertyMapper is passed", () => { + const transform = createProductTransformer(); + const out = transform({ product: baseProduct(), options: { currencyCode: "BRL" } }); + expect(out.additionalProperty).toEqual([ + { "@type": "PropertyValue", name: "itemType", value: "simple" }, + { "@type": "PropertyValue", name: "category", value: "category-a, category-b" }, + ]); + }); + + it("default mapper skips itemType when absent", () => { + const transform = createProductTransformer(); + const out = transform({ + product: baseProduct({ itemType: undefined }), + options: { currencyCode: "BRL" }, + }); + expect(out.additionalProperty).toEqual([ + { "@type": "PropertyValue", name: "category", value: "category-a, category-b" }, + ]); + }); + + it("default mapper skips categories when empty", () => { + const transform = createProductTransformer(); + const out = transform({ + product: baseProduct({ categories: [] }), + options: { currencyCode: "BRL" }, + }); + expect(out.additionalProperty).toEqual([ + { "@type": "PropertyValue", name: "itemType", value: "simple" }, + ]); + }); + + it("custom propertyMapper sees site-specific extras via index signature", () => { + const granadoMapper: PropertyMapper = (product) => [ + { "@type": "PropertyValue", name: "marca", value: String(product.Marca ?? "") }, + { "@type": "PropertyValue", name: "volume", value: String(product.Volume ?? "") }, + ]; + const transform = createProductTransformer({ propertyMapper: granadoMapper }); + const out = transform({ + product: baseProduct({ Marca: "Granado", Volume: "200ml" }), + options: { currencyCode: "BRL" }, + }); + expect(out.additionalProperty).toEqual([ + { "@type": "PropertyValue", name: "marca", value: "Granado" }, + { "@type": "PropertyValue", name: "volume", value: "200ml" }, + ]); + }); + + it("prefers idMagento over id for productID when present", () => { + const transform = createProductTransformer(); + const out = transform({ + product: baseProduct({ idMagento: "9999" }), + options: { currencyCode: "BRL" }, + }); + expect(out.productID).toBe("9999"); + expect(out.sku).toBe("SKU-42"); + }); + + it("uses id for productID when idMagento is missing", () => { + const transform = createProductTransformer(); + const out = transform({ product: baseProduct(), options: { currencyCode: "BRL" } }); + expect(out.productID).toBe("SKU-42"); + }); + + it("trims whitespace from name", () => { + const transform = createProductTransformer(); + const out = transform({ + product: baseProduct({ name: " Padded Name " }), + options: { currencyCode: "BRL" }, + }); + expect(out.name).toBe("Padded Name"); + expect(out.isVariantOf?.name).toBe("Padded Name"); + }); + + it("falls back to product.currency when options.currencyCode is omitted", () => { + const transform = createProductTransformer(); + const out = transform({ + product: baseProduct({ currency: "EUR" }), + options: {}, + }); + const firstOffer = out.offers?.offers[0]; + expect(firstOffer?.priceCurrency).toBe("EUR"); + }); + + it("places one variant under isVariantOf.hasVariant", () => { + const transform = createProductTransformer(); + const out = transform({ product: baseProduct(), options: { currencyCode: "BRL" } }); + expect(out.isVariantOf?.hasVariant).toHaveLength(1); + expect(out.isVariantOf?.hasVariant?.[0].sku).toBe("SKU-42"); + }); + + it("AggregateOffer surfaces high/low correctly when on sale", () => { + const transform = createProductTransformer(); + const out = transform({ product: baseProduct(), options: { currencyCode: "BRL" } }); + expect(out.offers?.highPrice).toBe(100); + expect(out.offers?.lowPrice).toBe(80); + }); + + it("AggregateOffer high === low when no salePrice is set", () => { + const transform = createProductTransformer(); + const out = transform({ + product: baseProduct({ salePrice: undefined }), + options: { currencyCode: "BRL" }, + }); + expect(out.offers?.highPrice).toBe(100); + expect(out.offers?.lowPrice).toBe(100); + }); +}); diff --git a/salesforce/index.ts b/salesforce/index.ts new file mode 100644 index 0000000..370389b --- /dev/null +++ b/salesforce/index.ts @@ -0,0 +1,33 @@ +/** + * Salesforce Marketing Cloud Personalization (Evergage) app entry. + * + * Unlike `magento` / `algolia`, the Salesforce loaders here are + * stateless — every loader takes its `baseUrl` / `dataset` / + * `campaignId` / `cookieName` via props so the same package can power + * multiple Evergage datasets in a single worker without a global + * configure step. Sites just import the loader(s) they need. + * + * For loaders, use sub-path imports: + * import list from "@decocms/apps/salesforce/loaders/products/list" + * import listRecomended from "@decocms/apps/salesforce/loaders/products/listRecomended" + * import listCart from "@decocms/apps/salesforce/loaders/products/listCart" + * + * For the transformer (sites typically build their own `propertyMapper` + * over a dataset's custom columns): + * import { createProductTransformer } from "@decocms/apps/salesforce/utils/transform" + */ +export type { + CampaignResponse, + ParsedUserCookie, + PersonalizationBody, + PersonalizationLineItem, + PersonalizationResponse, + SalesforceProduct, +} from "./types"; +export { createHttpClient, type HttpClientOptions } from "./utils/httpClient"; +export { parseUserCookie } from "./utils/parseUserCookie"; +export { + createProductTransformer, + type ProductTransformerOptions, + type PropertyMapper, +} from "./utils/transform"; diff --git a/salesforce/loaders/products/list.ts b/salesforce/loaders/products/list.ts new file mode 100644 index 0000000..caaf239 --- /dev/null +++ b/salesforce/loaders/products/list.ts @@ -0,0 +1,139 @@ +/** + * Salesforce Marketing Cloud Personalization — campaign list loader. + * + * Hits `POST {baseUrl}/api2/event/:dataset` with the user identifier + * extracted from the Evergage cookie and returns the products attached + * to the matching campaign payload. When no cookie exists (first visit + * / parity bot / SSR), `parseUserCookie` falls back to the literal + * `anonymous` so Evergage still responds with a default campaign + * instead of erroring. + * + * Cookies are read via `getCookies()` from `@tanstack/react-start/server` + * — the request object isn't propagated through the framework's + * `commerceLoader(resolvedProps)` call, so we rely on AsyncLocalStorage + * to recover the original request from inside the deferred section + * server function context. + */ +import type { Product } from "../../../commerce/types/commerce"; +import type { + CampaignResponse, + PersonalizationBody, + PersonalizationResponse, + SalesforceProduct, +} from "../../types"; +import { createHttpClient } from "../../utils/httpClient"; +import { parseUserCookie } from "../../utils/parseUserCookie"; +import { createProductTransformer, type PropertyMapper } from "../../utils/transform"; + +export interface SalesforceListLoaderProps { + /** + * @title Personalization Base URL + * @description e.g. `https://.us-5.evergage.com` + */ + baseUrl: string; + /** @title Personalization Dataset */ + dataset: string; + /** @title Campaign Id */ + campaignId: string; + /** + * @title Cookie Name + * @description Cookie name Evergage drops on the browser + * (e.g. `_evga_`) + */ + cookieName: string; + /** @title Currency Code (ISO 4217) */ + currencyCode?: string; + /** Custom property mapper passed by site wrappers. */ + propertyMapper?: PropertyMapper; +} + +export interface SalesforceListResult { + "@type": "ProductList"; + list: Product[]; + additionalData: { + title?: string; + campaignId: string; + experienceId?: string; + userGroup?: string; + }; +} + +/** + * Read the named cookie from the in-flight request. Imported lazily so + * the loader stays runtime-agnostic for unit tests (a manual cookie + * value can be passed via `__testCookieOverride`). + */ +async function readCookie(cookieName: string): Promise { + try { + const { getCookies } = await import("@tanstack/react-start/server"); + const cookies = getCookies(); + return cookies?.[cookieName]; + } catch { + return undefined; + } +} + +export default async function salesforceListLoader( + props: SalesforceListLoaderProps, + _req?: Request, +): Promise { + const { baseUrl, dataset, campaignId, cookieName, currencyCode, propertyMapper } = props; + + try { + const rawCookie = await readCookie(cookieName); + const userData = parseUserCookie(rawCookie); + + const client = createHttpClient({ + base: baseUrl, + headers: { "x-requested-with": "XMLHttpRequest" }, + }); + + const requestBody: PersonalizationBody = { + source: { channel: "WebServer", url: `mcp_campaign=${campaignId}` }, + interaction: { name: "Personalization Campaigns" }, + user: userData, + flags: { nonInteractive: true, doNotTrack: false }, + pageView: false, + }; + + const response = (await client["POST /api2/event/:dataset"]( + { dataset }, + { body: requestBody }, + ).then((res: { json: () => Promise }) => + res.json(), + )) as PersonalizationResponse; + + const payload = + response.campaignResponses?.find((item: CampaignResponse) => item.campaignId === campaignId) + ?.payload ?? response.campaignResponses?.[0]?.payload; + + if (!payload?.products?.length) { + return null; + } + + const transform = createProductTransformer({ propertyMapper }); + + return { + "@type": "ProductList", + list: payload.products.map((product: SalesforceProduct) => + transform({ + product, + options: { currencyCode: currencyCode ?? product.currency }, + }), + ), + additionalData: { + title: payload.headerText, + campaignId, + experienceId: payload.experience, + userGroup: payload.userGroup, + }, + }; + } catch (err) { + // The legacy Deno loader swallowed errors and returned null. We + // keep the same return shape (so consumers don't have to handle + // rejections) but log the failure — silent null hides API outages + // and CORS regressions during parity validation. + console.error("[salesforce/products/list] failed:", (err as Error)?.message); + return null; + } +} diff --git a/salesforce/loaders/products/listCart.ts b/salesforce/loaders/products/listCart.ts new file mode 100644 index 0000000..c1bac19 --- /dev/null +++ b/salesforce/loaders/products/listCart.ts @@ -0,0 +1,151 @@ +/** + * Salesforce Marketing Cloud Personalization — cart-aware recommendations. + * + * Same wire format as `list.ts`, but the interaction name is + * `"Replace Cart"` and the request body carries the current cart's line + * items so Evergage can seed cross-sell / "frequently bought together" + * campaigns from the items already in the basket. + * + * Sites typically call this loader from a "cart drawer" / "cart side panel" + * section. The cart state itself isn't read from cookies here — sites + * resolve their own cart (Magento, Shopify, custom) and pass `items` as + * a flat array. When `items` is empty, the loader short-circuits and + * returns `null` (no cart → no cross-sell). + */ +import type { Product } from "../../../commerce/types/commerce"; +import type { + CampaignResponse, + PersonalizationBody, + PersonalizationResponse, + SalesforceProduct, +} from "../../types"; +import { createHttpClient } from "../../utils/httpClient"; +import { parseUserCookie } from "../../utils/parseUserCookie"; +import { createProductTransformer, type PropertyMapper } from "../../utils/transform"; + +export interface SalesforceListCartItem { + sku: string; + qty: number; + price: number; +} + +export interface SalesforceListCartProps { + /** + * @title Cart Items + * @description Items currently in the user's cart. Site loaders resolve + * this from their commerce backend (Magento, Shopify, etc.) and pass + * it through. + */ + items: SalesforceListCartItem[]; + /** @title Personalization Base URL */ + baseUrl: string; + /** @title Personalization Dataset */ + dataset: string; + /** @title Campaign Id */ + campaignId: string; + /** @title Cookie Name */ + cookieName: string; + /** @title Currency Code (ISO 4217) */ + currencyCode?: string; + /** + * @title Fallback Title + * @description Shown when the campaign payload has no `headerText` + * (e.g. Granado uses the configured `label` from the CMS block). + */ + title?: string; + /** Custom property mapper. */ + propertyMapper?: PropertyMapper; +} + +export interface SalesforceListCartResult { + "@type": "ProductList"; + list: Product[]; + additionalData: { + title?: string; + campaignId: string; + experienceId?: string; + userGroup?: string; + }; +} + +async function readCookie(cookieName: string): Promise { + try { + const { getCookies } = await import("@tanstack/react-start/server"); + const cookies = getCookies(); + return cookies?.[cookieName]; + } catch { + return undefined; + } +} + +export default async function salesforceListCartLoader( + props: SalesforceListCartProps, + _req?: Request, +): Promise { + const { items, baseUrl, dataset, campaignId, cookieName, currencyCode, title, propertyMapper } = + props; + + if (!items?.length) return null; + + try { + const rawCookie = await readCookie(cookieName); + const userData = parseUserCookie(rawCookie); + + const client = createHttpClient({ + base: baseUrl, + headers: { "x-requested-with": "XMLHttpRequest" }, + }); + + const requestBody: PersonalizationBody = { + source: { channel: "WebServer", url: `mcp_campaign=${campaignId}` }, + interaction: { + name: "Replace Cart", + lineItems: items.map(({ sku, qty, price }) => ({ + catalogObjectType: "Product", + catalogObjectId: sku, + quantity: qty, + price, + })), + }, + user: userData, + flags: { nonInteractive: true, doNotTrack: false }, + pageView: false, + }; + + const response = (await client["POST /api2/event/:dataset"]( + { dataset }, + { body: requestBody }, + ).then((res: { json: () => Promise }) => + res.json(), + )) as PersonalizationResponse; + + const payload = + response.campaignResponses?.find((item: CampaignResponse) => item.campaignId === campaignId) + ?.payload ?? response.campaignResponses?.[0]?.payload; + + if (!payload?.products?.length) { + return null; + } + + const transform = createProductTransformer({ propertyMapper }); + + return { + "@type": "ProductList", + list: payload.products.map((product: SalesforceProduct) => + transform({ + product, + options: { currencyCode: currencyCode ?? product.currency }, + }), + ), + additionalData: { + title: payload.headerText || title, + campaignId, + experienceId: payload.experience, + userGroup: payload.userGroup, + }, + }; + } catch (err) { + console.error("[salesforce/products/listCart] failed:", (err as Error)?.message); + return null; + } +} diff --git a/salesforce/loaders/products/listRecomended.ts b/salesforce/loaders/products/listRecomended.ts new file mode 100644 index 0000000..f45a9a6 --- /dev/null +++ b/salesforce/loaders/products/listRecomended.ts @@ -0,0 +1,121 @@ +/** + * Salesforce Marketing Cloud Personalization — recommendations loader. + * + * Same wire format as `list.ts`, but the campaign Evergage runs is the + * "related products" one and the request body includes the + * `viewedProductId` attribute so Evergage can use the in-context PDP + * to seed its recommendation model. + * + * Used on PDP / PDC pages; the upstream site passes the resolved + * `ProductDetailsPage` so we can read `product.sku`. When no product + * context is available the loader still sends the campaign request — + * Evergage will return its default fallback list. + */ +import type { Product, ProductDetailsPage } from "../../../commerce/types/commerce"; +import type { CampaignResponse, PersonalizationResponse, SalesforceProduct } from "../../types"; +import { createHttpClient } from "../../utils/httpClient"; +import { parseUserCookie } from "../../utils/parseUserCookie"; +import { createProductTransformer, type PropertyMapper } from "../../utils/transform"; + +export interface SalesforceListRecommendedProps { + /** @title Product Id (resolved PDP) */ + productId: ProductDetailsPage | null; + /** @title Personalization Base URL */ + baseUrl: string; + /** @title Personalization Dataset */ + dataset: string; + /** @title Campaign Id */ + campaignId: string; + /** @title Cookie Name */ + cookieName: string; + /** @title Currency Code (ISO 4217) */ + currencyCode?: string; + /** Custom property mapper. */ + propertyMapper?: PropertyMapper; +} + +export interface SalesforceListRecommendedResult { + "@type": "ProductList"; + list: Product[]; + additionalData: { + title?: string; + campaignId: string; + experienceId?: string; + userGroup?: string; + }; +} + +async function readCookie(cookieName: string): Promise { + try { + const { getCookies } = await import("@tanstack/react-start/server"); + const cookies = getCookies(); + return cookies?.[cookieName]; + } catch { + return undefined; + } +} + +export default async function salesforceListRecommendedLoader( + props: SalesforceListRecommendedProps, + _req?: Request, +): Promise { + const { baseUrl, dataset, productId, cookieName, campaignId, currencyCode, propertyMapper } = + props; + + try { + const rawCookie = await readCookie(cookieName); + const userData = parseUserCookie(rawCookie); + + const client = createHttpClient({ + base: baseUrl, + headers: { "x-requested-with": "XMLHttpRequest" }, + }); + + const requestBody = { + source: { channel: "WebServer", url: `mcp_campaign=${campaignId}` }, + interaction: { name: "Personalization Campaigns" }, + user: { + ...userData, + attributes: { viewedProductId: productId?.product?.sku ?? "" }, + }, + flags: { nonInteractive: true, doNotTrack: false }, + pageView: false, + }; + + const response = (await client["POST /api2/event/:dataset"]( + { dataset }, + { body: requestBody }, + ).then((res: { json: () => Promise }) => + res.json(), + )) as PersonalizationResponse; + + const payload = + response.campaignResponses?.find((item: CampaignResponse) => item.campaignId === campaignId) + ?.payload ?? response.campaignResponses?.[0]?.payload; + + if (!payload?.products?.length) { + return null; + } + + const transform = createProductTransformer({ propertyMapper }); + + return { + "@type": "ProductList", + list: payload.products.map((product: SalesforceProduct) => + transform({ + product, + options: { currencyCode: currencyCode ?? product.currency }, + }), + ), + additionalData: { + title: payload.headerText, + campaignId, + experienceId: payload.experience, + userGroup: payload.userGroup, + }, + }; + } catch (err) { + console.error("[salesforce/products/listRecomended] failed:", (err as Error)?.message); + return null; + } +} diff --git a/salesforce/types.ts b/salesforce/types.ts new file mode 100644 index 0000000..2fe7762 --- /dev/null +++ b/salesforce/types.ts @@ -0,0 +1,108 @@ +/** + * Salesforce Marketing Cloud Personalization (Evergage) — request/response + * shapes for the campaign personalization API. + * + * The Evergage product schema is configurable per dataset (each customer + * chooses which fields to expose), so `SalesforceProduct` keeps a minimal + * required surface and accepts arbitrary extras via index signature. + * Site-level transformers can downcast to their own product shape to + * read store-specific custom fields (e.g. `marca`, `linha`, brand-tags). + */ + +export interface SalesforceProduct { + /** Internal Evergage id (string token, often a SKU or catalog id). */ + id: string; + /** Display name. */ + name: string; + /** Base price (list). */ + price: number; + /** Discounted price; falls back to `price` when no promotion is active. */ + salePrice?: number; + /** Stock count from Evergage's catalog feed. */ + inventoryCount: number; + /** Pre-built absolute URLs of product images. */ + imageUrls: string[]; + /** Canonical product URL (full origin + path). */ + url: string; + /** ISO 4217 currency code (e.g. "BRL"). */ + currency: string; + /** Common Evergage column — short product description. */ + description?: string; + /** Optional cross-system identifier (e.g. Magento `entity_id`). */ + idMagento?: string; + /** Item type tag (e.g. "configurable", "simple"). */ + itemType?: string; + /** Generic category trail (Evergage stores these as arrays). */ + categories?: string[]; + /** Site-specific extras — Evergage exposes whatever the dataset schema + * defines (e.g. `Marca`, `Volume`, `Linha`, `freeShipping`). The + * product transformer can read these via the attributeMapper hook. */ + [customField: string]: unknown; +} + +/** + * Single line item in a cart-interaction request body. Evergage uses + * these to seed cart-aware recommendations ("people who bought X also + * bought Y") and abandoned-cart campaigns. + */ +export interface PersonalizationLineItem { + catalogObjectType: string; + catalogObjectId: string; + quantity: number; + price: number; +} + +/** + * Body sent to `POST {baseUrl}/api2/event/:dataset`. The Evergage API is + * "interaction"-based — every request describes an interaction the user + * had, and the response contains the campaigns triggered by that + * interaction (recommendations, popups, etc.). + * + * `interaction.lineItems` is only used by cart-aware campaigns; PDP / + * homepage requests omit it. `user.attributes` carries page-context + * hints (e.g. `viewedProductId` for related-product campaigns). + */ +export interface PersonalizationBody { + source: { + channel: string; + url: string; + }; + interaction: { + name: string; + lineItems?: PersonalizationLineItem[]; + }; + user: { + anonymousId?: string; + encryptedId?: string; + attributes?: Record; + }; + flags: { + nonInteractive: boolean; + doNotTrack: boolean; + }; + pageView: boolean; +} + +export interface CampaignResponse { + campaignId: string; + payload: { + experience?: string; + headerText?: string; + products?: SalesforceProduct[]; + userGroup?: string; + }; +} + +export interface PersonalizationResponse { + campaignResponses?: CampaignResponse[]; +} + +/** + * Cookie shape Evergage drops on the browser (`puid` = persistent user + * id after sign-in, `uuid` = anonymous device id). The site loaders + * read this cookie to send the right user identifier on each request. + */ +export interface ParsedUserCookie { + encryptedId?: string; + anonymousId?: string; +} diff --git a/salesforce/utils/httpClient.ts b/salesforce/utils/httpClient.ts new file mode 100644 index 0000000..c1a6c94 --- /dev/null +++ b/salesforce/utils/httpClient.ts @@ -0,0 +1,154 @@ +/** + * Typed HTTP client compatible with deco-cx/apps' `createHttpClient` + * signature. Accepts both the simple `.get(path)` / `.post(path, body)` + * shape and the indexed-route shape used by legacy Deno loaders: + * + * ```ts + * const client = createHttpClient({ base: "https://api.example.com" }); + * await client["POST /api2/event/:dataset"]({ dataset: "prod" }, { body }); + * await client.get("/healthcheck"); + * ``` + * + * Runtime-agnostic: only requires the global `fetch`. Works on + * Cloudflare Workers, Bun, Deno, and modern Node — no `node:http` + * dependency. Returns `{ json, ok, status, headers }` from indexed + * routes (mirrors the legacy `apps/utils/http.ts` shape so existing + * loaders that call `.then(res => res.json())` keep working). + */ + +export interface HttpClientOptions { + base: string; + headers?: Record | Headers; + fetcher?: typeof fetch; +} + +interface IndexedRouteResponse { + json: () => Promise; + ok: boolean; + status: number; + headers: Headers; +} + +export function createHttpClient<_Routes = unknown>(options: HttpClientOptions) { + const base = options.base.replace(/\/$/, ""); + const fetchImpl = options.fetcher ?? fetch; + const defaultHeaders: Record = + options.headers instanceof Headers + ? Object.fromEntries(options.headers.entries()) + : (options.headers ?? {}); + + const handler: ProxyHandler> = { + get(_target, prop) { + if (prop === "get") { + return async (path: string, init?: RequestInit): Promise => { + const res = await fetchImpl(`${base}${path}`, { + ...init, + headers: { + ...defaultHeaders, + ...((init?.headers as Record) ?? {}), + }, + }); + return res.json() as Promise; + }; + } + if (prop === "post") { + return async (path: string, body: unknown, init?: RequestInit): Promise => { + const res = await fetchImpl(`${base}${path}`, { + method: "POST", + ...init, + headers: { + "Content-Type": "application/json", + ...defaultHeaders, + ...((init?.headers as Record) ?? {}), + }, + body: JSON.stringify(body), + }); + return res.json() as Promise; + }; + } + if (typeof prop === "string" && /^(GET|POST|PUT|PATCH|DELETE)\s+/.test(prop)) { + const spaceIdx = prop.indexOf(" "); + const method = prop.slice(0, spaceIdx); + let apiPath = prop.slice(spaceIdx + 1); + + return async ( + params: Record = {}, + init?: RequestInit & { body?: unknown }, + ): Promise => { + const cleanParams = { ...params }; + + // `:name` path placeholders — replaced with the matching + // param value, then removed from the body/query object. + for (const [key, value] of Object.entries(cleanParams)) { + const placeholder = `:${key}`; + if (apiPath.includes(placeholder) && value != null) { + apiPath = apiPath.replace(placeholder, encodeURIComponent(String(value))); + delete cleanParams[key]; + } + } + + // Legacy `*name` placeholders (Deno-era convention). + const starMatch = apiPath.match(/\*(\w+)/); + if (starMatch) { + const paramName = starMatch[1]; + if (cleanParams[paramName] != null) { + apiPath = apiPath.replace(`*${paramName}`, String(cleanParams[paramName])); + delete cleanParams[paramName]; + } else { + apiPath = apiPath.replace(/\/\*\w+/, ""); + } + } + + let url = `${base}${apiPath}`; + + if (method === "GET") { + const sp = new URLSearchParams(); + for (const [k, v] of Object.entries(cleanParams)) { + if (v !== undefined && v !== null) sp.set(k, String(v)); + } + const qs = sp.toString(); + if (qs) url += (url.includes("?") ? "&" : "?") + qs; + } + + // Indexed-route callers can either embed the body in the + // remaining params (legacy style) OR pass `{ body }` in the + // second arg (newer call sites). The `body` key in init + // takes precedence when present. + const explicitBody = init && "body" in init ? init.body : undefined; + const fetchBody = + method === "GET" + ? undefined + : explicitBody !== undefined + ? JSON.stringify(explicitBody) + : Object.keys(cleanParams).length > 0 + ? JSON.stringify(cleanParams) + : undefined; + + const fetchInit: RequestInit = { + method, + ...(init ?? {}), + headers: { + "Content-Type": "application/json", + ...defaultHeaders, + ...(init?.headers instanceof Headers + ? Object.fromEntries(init.headers.entries()) + : ((init?.headers as Record) ?? {})), + }, + ...(fetchBody !== undefined ? { body: fetchBody } : {}), + }; + + const res = await fetchImpl(url, fetchInit); + return { + json: () => res.json() as Promise, + ok: res.ok, + status: res.status, + headers: res.headers, + }; + }; + } + return undefined; + }, + }; + + return new Proxy({} as Record, handler) as Record; +} diff --git a/salesforce/utils/parseUserCookie.ts b/salesforce/utils/parseUserCookie.ts new file mode 100644 index 0000000..904c890 --- /dev/null +++ b/salesforce/utils/parseUserCookie.ts @@ -0,0 +1,41 @@ +/** + * Decode the JSON-encoded user identifier cookie set by Salesforce + * Marketing Cloud Personalization (Evergage) on the browser. + * + * Evergage stores `{ puid?: string, uuid?: string }` URL-encoded: + * - `puid` (persistent user id) is present after the user signs in + * - `uuid` (anonymous device id) is dropped on first visit + * + * The personalization API expects EITHER `encryptedId` (mapped from + * `puid`) OR `anonymousId` (mapped from `uuid`). When the cookie is + * missing or malformed, we fall back to the literal "anonymous" so + * the API still returns a default campaign instead of erroring. + */ +import type { ParsedUserCookie } from "../types"; + +const ANONYMOUS_FALLBACK: ParsedUserCookie = { anonymousId: "anonymous" }; + +export function parseUserCookie(rawCookie: string | undefined | null): ParsedUserCookie { + if (!rawCookie?.trim()) return ANONYMOUS_FALLBACK; + + try { + const decoded = decodeURIComponent(rawCookie); + const parsed: unknown = JSON.parse(decoded); + if (typeof parsed !== "object" || parsed === null) return ANONYMOUS_FALLBACK; + + const { puid, uuid } = parsed as { puid?: unknown; uuid?: unknown }; + + // puid wins over uuid when both are present — once a user signs in, + // every request should be attributed to their persistent identity + // so cross-device personalization works. + if (typeof puid === "string" && puid.length > 0) { + return { encryptedId: puid }; + } + if (typeof uuid === "string" && uuid.length > 0) { + return { anonymousId: uuid }; + } + return ANONYMOUS_FALLBACK; + } catch { + return ANONYMOUS_FALLBACK; + } +} diff --git a/salesforce/utils/transform.ts b/salesforce/utils/transform.ts new file mode 100644 index 0000000..9b48db4 --- /dev/null +++ b/salesforce/utils/transform.ts @@ -0,0 +1,156 @@ +/** + * Map a Salesforce Personalization product into a schema.org `Product` + * suitable for ProductShelf / ProductCard / PDP components. + * + * Most fields (id, name, price, images, currency) are common to every + * Evergage dataset. The `additionalProperty` list, however, is fully + * dataset-specific — each customer chooses which catalog columns are + * exposed by Evergage (`Marca`, `Volume`, `Linha`, `freeShipping` etc.). + * Sites pass a `propertyMapper` to project their custom columns into + * `schema.org/PropertyValue[]`; the default mapper produces the + * standard fields that exist on every Evergage product (`itemType`, + * `categories`). + */ +import type { Offer, Product, PropertyValue } from "../../commerce/types/commerce"; +import type { SalesforceProduct } from "../types"; + +const IN_STOCK = "https://schema.org/InStock"; +const OUT_OF_STOCK = "https://schema.org/OutOfStock"; + +export type PropertyMapper = (product: SalesforceProduct) => PropertyValue[]; + +export interface ProductTransformerOptions { + /** + * Project dataset-specific Evergage columns into schema.org + * `PropertyValue[]`. Receives the raw Evergage product (including + * any custom fields via the index signature). Returns an empty + * array by default — sites that want brand / volume / line tags on + * their cards pass a mapper. + */ + propertyMapper?: PropertyMapper; +} + +const DEFAULT_PROPERTY_MAPPER: PropertyMapper = (product) => { + const out: PropertyValue[] = []; + if (product.itemType) { + out.push({ "@type": "PropertyValue", name: "itemType", value: product.itemType }); + } + if (product.categories?.length) { + out.push({ + "@type": "PropertyValue", + name: "category", + value: product.categories.join(", "), + }); + } + return out; +}; + +export function toOffer({ + product, + currencyCode, +}: { + product: SalesforceProduct; + currencyCode?: string; +}): Offer[] { + const productPrice = product.price; + const productSalePrice = product.salePrice || productPrice; + return [ + { + "@type": "Offer", + availability: product.inventoryCount > 0 ? IN_STOCK : OUT_OF_STOCK, + inventoryLevel: { value: product.inventoryCount }, + itemCondition: "https://schema.org/NewCondition", + price: productSalePrice, + priceCurrency: currencyCode, + priceSpecification: [ + { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/ListPrice", + price: productPrice, + }, + { + "@type": "UnitPriceSpecification", + priceType: "https://schema.org/SalePrice", + price: productSalePrice, + }, + ], + sku: product.id, + }, + ]; +} + +export function toImages(product: SalesforceProduct) { + return product.imageUrls.map((url) => ({ + "@type": "ImageObject" as const, + encodingFormat: "image", + alternateName: url, + url, + })); +} + +/** + * Returns a `toProduct` function bound to the dataset's property + * mapper. Sites typically construct one transformer at module level + * and reuse it across loaders. + */ +export function createProductTransformer( + options: ProductTransformerOptions = {}, +): (input: { product: SalesforceProduct; options: { currencyCode?: string } }) => Product { + const mapProperties = options.propertyMapper ?? DEFAULT_PROPERTY_MAPPER; + + return ({ product, options: opts }) => { + const offers = toOffer({ product, currencyCode: opts.currencyCode ?? product.currency }); + const sku = product.id; + // `idMagento` (cross-system identifier) wins when present — + // downstream code keys product detail pages off `productID`. + const productID = (product.idMagento as string | undefined) ?? sku; + const productPrice = product.price; + const productSalePrice = product.salePrice || productPrice; + const productUrl = product.url; + const additionalProperty = mapProperties(product); + + const variantTemplate: Product = { + "@type": "Product", + productID, + sku, + url: productUrl, + name: product.name.trim(), + gtin: sku, + offers: { + "@type": "AggregateOffer", + highPrice: productPrice, + lowPrice: productSalePrice, + offerCount: offers.length, + offers, + }, + }; + + return { + "@type": "Product", + productID, + sku, + url: productUrl, + name: product.name.trim(), + gtin: sku, + aggregateRating: { "@type": "AggregateRating", reviewCount: undefined }, + isVariantOf: { + "@type": "ProductGroup", + productGroupID: productID, + url: productUrl, + name: product.name.trim(), + model: "", + additionalProperty, + hasVariant: [variantTemplate], + }, + additionalProperty, + image: toImages(product), + offers: { + "@type": "AggregateOffer", + highPrice: productPrice, + lowPrice: productSalePrice, + offerCount: offers.length, + offers, + }, + }; + }; +} diff --git a/vtex/__tests__/client-segment-cookie.test.ts b/vtex/__tests__/client-segment-cookie.test.ts index f0de476..80a69f4 100644 --- a/vtex/__tests__/client-segment-cookie.test.ts +++ b/vtex/__tests__/client-segment-cookie.test.ts @@ -7,7 +7,14 @@ import { RequestContext } from "@decocms/start/sdk/requestContext"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { configureVtex, setVtexFetch, vtexFetchResponse } from "../client"; +import { + configureVtex, + intelligentSearch, + setVtexFetch, + vtexCachedFetch, + vtexFetchResponse, +} from "../client"; +import { clearFetchCache } from "../utils/fetchCache"; function mockResponse(body: unknown = {}, status = 200): Response { return { @@ -43,6 +50,25 @@ function mockResponse(body: unknown = {}, status = 200): Response { * `vi.spyOn`. The spy is restored after `fn` resolves to keep tests * isolated. Nothing here depends on undici or ALS internals. */ +/** + * Read a header from an init in a shape-agnostic way. After the + * `mergeHeaders` refactor, `init.headers` is always a `Headers` + * instance — but the helper handles legacy shapes too so the tests + * stay robust if someone changes the merge implementation again. + */ +function headerValue(init: RequestInit | undefined, name: string): string | undefined { + const headers = init?.headers; + if (!headers) return undefined; + if (headers instanceof Headers) return headers.get(name) ?? undefined; + if (Array.isArray(headers)) { + const found = headers.find(([k]) => k.toLowerCase() === name.toLowerCase()); + return found?.[1]; + } + const rec = headers as Record; + const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase()); + return key ? rec[key] : undefined; +} + function withRequest(cookieHeader: string | null, fn: () => Promise): Promise { const headers = new Headers(); if (cookieHeader) headers.set("cookie", cookieHeader); @@ -79,8 +105,7 @@ describe("vtexFetchResponse — vtex_segment cookie forwarding", () => { await withRequest("vtex_segment=abc123; other=foo", async () => { await vtexFetchResponse("/api/catalog_system/pub/products/x"); }); - const headers = lastInit?.headers as Record; - expect(headers.cookie).toBe("vtex_segment=abc123"); + expect(headerValue(lastInit, "cookie")).toBe("vtex_segment=abc123"); }); it("does not overwrite a caller-supplied cookie header", async () => { @@ -89,8 +114,7 @@ describe("vtexFetchResponse — vtex_segment cookie forwarding", () => { headers: { cookie: "custom=zzz" }, }); }); - const headers = lastInit?.headers as Record; - expect(headers.cookie).toBe("custom=zzz"); + expect(headerValue(lastInit, "cookie")).toBe("custom=zzz"); }); it("does not overwrite a caller-supplied Cookie header (case-insensitive)", async () => { @@ -99,34 +123,26 @@ describe("vtexFetchResponse — vtex_segment cookie forwarding", () => { headers: { Cookie: "custom=zzz" }, }); }); - const headers = lastInit?.headers as Record; - // The merged headers may contain both keys; the caller's value should win. - const lowered = Object.fromEntries( - Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]), - ); - expect(lowered.cookie).toBe("custom=zzz"); + expect(headerValue(lastInit, "cookie")).toBe("custom=zzz"); }); it("is a no-op when there is no incoming cookie header", async () => { await withRequest(null, async () => { await vtexFetchResponse("/api/x"); }); - const headers = lastInit?.headers as Record; - expect(headers.cookie).toBeUndefined(); + expect(headerValue(lastInit, "cookie")).toBeUndefined(); }); it("is a no-op when there is a cookie header but no vtex_segment", async () => { await withRequest("other=foo; another=bar", async () => { await vtexFetchResponse("/api/x"); }); - const headers = lastInit?.headers as Record; - expect(headers.cookie).toBeUndefined(); + expect(headerValue(lastInit, "cookie")).toBeUndefined(); }); it("does not crash when called outside a RequestContext", async () => { await vtexFetchResponse("/api/x"); - const headers = lastInit?.headers as Record; - expect(headers.cookie).toBeUndefined(); + expect(headerValue(lastInit, "cookie")).toBeUndefined(); }); it("preserves auth headers alongside the forwarded cookie", async () => { @@ -134,9 +150,106 @@ describe("vtexFetchResponse — vtex_segment cookie forwarding", () => { await withRequest("vtex_segment=abc123", async () => { await vtexFetchResponse("/api/x"); }); - const headers = lastInit?.headers as Record; - expect(headers["X-VTEX-API-AppKey"]).toBe("k"); - expect(headers["X-VTEX-API-AppToken"]).toBe("t"); - expect(headers.cookie).toBe("vtex_segment=abc123"); + expect(headerValue(lastInit, "X-VTEX-API-AppKey")).toBe("k"); + expect(headerValue(lastInit, "X-VTEX-API-AppToken")).toBe("t"); + expect(headerValue(lastInit, "cookie")).toBe("vtex_segment=abc123"); + }); + + // Regression: when init.headers is a Headers object (as + // `createVtexCheckoutProxy` passes through `getVtexFetch()`), the + // existing cookie must survive verbatim. The naive + // `{ ...authHeaders, ...init?.headers }` spread collapses a Headers + // instance to `{}` (Headers has no own enumerable entries), which + // silently wipes the browser's full Cookie header — including the + // orderForm cookie any checkout flow depends on. + it("preserves an existing Cookie header when init.headers is a Headers instance", async () => { + await withRequest("vtex_segment=abc123", async () => { + const proxyInit: RequestInit = { + headers: new Headers({ + cookie: "checkout.vtex.com=__ofid=xyz; vtex_segment=originalseg; foo=bar", + }), + }; + await vtexFetchResponse("/api/checkout/pub/orderForm", proxyInit); + }); + expect(headerValue(lastInit, "cookie")).toContain("checkout.vtex.com=__ofid=xyz"); + }); +}); + +// Module-level counter for cache-busting test URLs. `Date.now()` collides +// when two tests run within the same millisecond and the SWR cache in +// fetchWithCache short-circuits the second one — `_fetch` never runs and +// `lastInit` stays `undefined`. Per-test ids are deterministic and +// collision-free. +let testUrlCounter = 0; +const uniqPath = (prefix: string) => `${prefix}/${++testUrlCounter}`; + +describe("vtexCachedFetch — vtex_segment cookie forwarding", () => { + let lastInit: RequestInit | undefined; + + beforeEach(() => { + clearFetchCache(); + configureVtex({ account: "testaccount" }); + lastInit = undefined; + setVtexFetch(((_url: string, init?: RequestInit) => { + lastInit = init; + return Promise.resolve(mockResponse({ ok: true })); + }) as typeof fetch); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("forwards vtex_segment on cached GETs", async () => { + await withRequest("vtex_segment=abc123", async () => { + await vtexCachedFetch(uniqPath("/api/catalog_system/pub/products")); + }); + expect(headerValue(lastInit, "cookie")).toBe("vtex_segment=abc123"); + }); + + it("does not overwrite a caller-supplied cookie header", async () => { + await withRequest("vtex_segment=abc123", async () => { + await vtexCachedFetch(uniqPath("/api/x"), { + headers: { cookie: "custom=zzz" }, + }); + }); + expect(headerValue(lastInit, "cookie")).toBe("custom=zzz"); + }); +}); + +describe("intelligentSearch — vtex_segment cookie forwarding", () => { + let lastInit: RequestInit | undefined; + + beforeEach(() => { + // Reset the SWR cache: otherwise the second test in this block + // can serve the first test's cached body without invoking the + // stub _fetch, leaving lastInit undefined. + clearFetchCache(); + configureVtex({ account: "testaccount" }); + lastInit = undefined; + setVtexFetch(((_url: string, init?: RequestInit) => { + lastInit = init; + return Promise.resolve(mockResponse({ products: [] })); + }) as typeof fetch); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("forwards vtex_segment when caller didn't pass cookieHeader", async () => { + await withRequest("vtex_segment=abc123; other=foo", async () => { + await intelligentSearch(uniqPath("/product_search")); + }); + expect(headerValue(lastInit, "cookie")).toBe("vtex_segment=abc123"); + }); + + it("respects an explicit cookieHeader override", async () => { + await withRequest("vtex_segment=abc123", async () => { + await intelligentSearch(uniqPath("/product_search"), undefined, { + cookieHeader: "custom=zzz", + }); + }); + expect(headerValue(lastInit, "cookie")).toBe("custom=zzz"); }); }); diff --git a/vtex/__tests__/client-set-cookie-forward.test.ts b/vtex/__tests__/client-set-cookie-forward.test.ts new file mode 100644 index 0000000..1242e24 --- /dev/null +++ b/vtex/__tests__/client-set-cookie-forward.test.ts @@ -0,0 +1,257 @@ +/** + * Regression tests for the Set-Cookie propagation chain through + * `vtexFetchWithCookies`. Without this chain, VTEX's `checkout.vtex.com` + * and `CheckoutOrderFormOwnership` cookies never reach the browser via + * `createServerFn` actions, the storefront's local `__orderFormId` + * drifts away from VTEX's server-side orderForm, and the user lands + * on `/checkout` with an empty cart. + * + * Two failure modes covered here: + * + * (1) Inbound capture — VTEX `Set-Cookie` headers must be appended + * to `RequestContext.responseHeaders`, skipping the two IS + * cookies that the middleware owns (`vtex_is_session`, + * `vtex_is_anonymous`), and the `domain=` attribute must be + * stripped so the browser scopes the cookie to the storefront. + * + * (2) Outbound merge — when the caller passes `init.headers` as a + * `Headers` instance (the `createVtexCheckoutProxy` factory does + * this through `getVtexFetch()`), spreading it as a plain object + * collapses to `{}` and silently wipes every other header the + * caller set. The Headers-aware merge in `vtexFetchWithCookies` + * keeps the bug from sneaking back in. + */ + +import { RequestContext } from "@decocms/start/sdk/requestContext"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { configureVtex, setVtexFetch, vtexFetchWithCookies } from "../client"; + +function mockResponse(opts?: { body?: unknown; status?: number; setCookies?: string[] }): Response { + const status = opts?.status ?? 200; + const headers = new Headers(); + for (const c of opts?.setCookies ?? []) headers.append("set-cookie", c); + return { + ok: status >= 200 && status < 300, + status, + statusText: status === 200 ? "OK" : "Error", + headers, + json: () => Promise.resolve(opts?.body ?? {}), + } as Response; +} + +function headerValue(init: RequestInit | undefined, name: string): string | undefined { + const headers = init?.headers; + if (!headers) return undefined; + if (headers instanceof Headers) return headers.get(name) ?? undefined; + if (Array.isArray(headers)) { + const found = headers.find(([k]) => k.toLowerCase() === name.toLowerCase()); + return found?.[1]; + } + const rec = headers as Record; + const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase()); + return key ? rec[key] : undefined; +} + +function withRequest( + cookieHeader: string | null, + fn: (ctx: { responseHeaders: Headers }) => Promise, + requestUrl = "https://store.example.com/api/checkout/pub/orderForm", +): Promise { + const reqHeaders = new Headers(); + if (cookieHeader) reqHeaders.set("cookie", cookieHeader); + const responseHeaders = new Headers(); + const fakeCtx = { + request: { headers: reqHeaders, url: requestUrl } as unknown as Request, + signal: new AbortController().signal, + responseHeaders, + bag: new Map(), + startedAt: Date.now(), + }; + const spy = vi + .spyOn(RequestContext, "current", "get") + .mockReturnValue(fakeCtx as unknown as ReturnType); + return fn({ responseHeaders }).finally(() => spy.mockRestore()); +} + +describe("vtexFetchWithCookies — inbound Set-Cookie capture", () => { + let lastInit: RequestInit | undefined; + + beforeEach(() => { + configureVtex({ account: "testaccount" }); + lastInit = undefined; + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("captures upstream Set-Cookie into RequestContext.responseHeaders", async () => { + setVtexFetch(((_url: string, init?: RequestInit) => { + lastInit = init; + return Promise.resolve( + mockResponse({ + setCookies: [ + "checkout.vtex.com=__ofid=abc123; Path=/; HttpOnly; Secure", + "CheckoutOrderFormOwnership=def456; Path=/; HttpOnly", + ], + }), + ); + }) as typeof fetch); + + const captured = await withRequest("vtex_segment=seg1", async ({ responseHeaders }) => { + await vtexFetchWithCookies("/api/checkout/pub/orderForm"); + return responseHeaders.getSetCookie(); + }); + + expect(captured).toHaveLength(2); + expect(captured.some((c) => c.startsWith("checkout.vtex.com="))).toBe(true); + expect(captured.some((c) => c.startsWith("CheckoutOrderFormOwnership="))).toBe(true); + }); + + // The cart server-fn cookie MUST land at the same scope as the checkout + // proxy (domain-scoped to the storefront host) and native VTEX + // (`domain=`). Stripping the Domain (host-only) creates a second, + // distinct cookie that drifts from the proxy's and causes the + // nondeterministic empty-cart bug. So we rewrite Domain, not strip it. + it("rewrites the Domain= attribute to the storefront host (matches the proxy)", async () => { + setVtexFetch((() => + Promise.resolve( + mockResponse({ + setCookies: [ + "checkout.vtex.com=__ofid=abc; Domain=.vtexcommercestable.com.br; Path=/; HttpOnly", + ], + }), + )) as typeof fetch); + + const captured = await withRequest( + "foo=bar", + async ({ responseHeaders }) => { + await vtexFetchWithCookies("/api/checkout/pub/orderForm"); + return responseHeaders.getSetCookie(); + }, + "https://www.casaevideo.com.br/api/checkout/pub/orderForm", + ); + + // domain-scoped to the storefront host, NOT the original VTEX domain + expect(captured[0]).toMatch(/Domain=www\.casaevideo\.com\.br/); + expect(captured[0]).not.toMatch(/vtexcommercestable/i); + expect(captured[0]).toContain("checkout.vtex.com=__ofid=abc"); + }); + + it("rewrites only the Domain attribute, not a domain= substring in the cookie value", async () => { + setVtexFetch((() => + Promise.resolve( + mockResponse({ + // Pathological value embedding `domain=` before the first `;`. + setCookies: [ + "checkout.vtex.com=__ofid=domain=keep; Domain=.vtexcommercestable.com.br; Path=/", + ], + }), + )) as typeof fetch); + + const captured = await withRequest( + "foo=bar", + async ({ responseHeaders }) => { + await vtexFetchWithCookies("/api/checkout/pub/orderForm"); + return responseHeaders.getSetCookie(); + }, + "https://www.casaevideo.com.br/api/checkout/pub/orderForm", + ); + + // the value's `domain=keep` is untouched; the attribute is rewritten + expect(captured[0]).toContain("__ofid=domain=keep"); + expect(captured[0]).toMatch(/;\s*Domain=www\.casaevideo\.com\.br/); + expect(captured[0]).not.toMatch(/vtexcommercestable/i); + }); + + it("falls back to stripping Domain when there is no request scope (module init)", async () => { + setVtexFetch((() => + Promise.resolve( + mockResponse({ + setCookies: ["checkout.vtex.com=__ofid=abc; Domain=.vtexcommercestable.com.br; Path=/"], + }), + )) as typeof fetch); + // No withRequest wrapper → RequestContext.current is null. + await expect(vtexFetchWithCookies("/api/checkout/pub/orderForm")).resolves.toBeDefined(); + }); + + it("skips Intelligent Search cookies (managed by middleware, not actions)", async () => { + setVtexFetch((() => + Promise.resolve( + mockResponse({ + setCookies: [ + "checkout.vtex.com=__ofid=abc; Path=/", + "vtex_is_session=ignore-me; Path=/", + "vtex_is_anonymous=ignore-me-too; Path=/", + "CheckoutOrderFormOwnership=def; Path=/", + ], + }), + )) as typeof fetch); + + const captured = await withRequest("foo=bar", async ({ responseHeaders }) => { + await vtexFetchWithCookies("/api/checkout/pub/orderForm"); + return responseHeaders.getSetCookie(); + }); + + expect(captured.some((c) => c.startsWith("checkout.vtex.com="))).toBe(true); + expect(captured.some((c) => c.startsWith("CheckoutOrderFormOwnership="))).toBe(true); + expect(captured.some((c) => c.startsWith("vtex_is_session="))).toBe(false); + expect(captured.some((c) => c.startsWith("vtex_is_anonymous="))).toBe(false); + }); + + it("does not crash when called outside a RequestContext", async () => { + setVtexFetch((() => + Promise.resolve( + mockResponse({ + setCookies: ["checkout.vtex.com=__ofid=abc; Path=/"], + }), + )) as typeof fetch); + await expect(vtexFetchWithCookies("/api/checkout/pub/orderForm")).resolves.toBeDefined(); + }); + + // Regression for Hole B: when init.headers is a Headers instance, + // the previous Record-cast + spread collapsed it to `{}`, wiping + // every other header (auth, content-type) the caller set. After + // the fix, the Headers-aware merge preserves all of them. + it("preserves other caller headers when init.headers is a Headers instance", async () => { + setVtexFetch(((_url: string, init?: RequestInit) => { + lastInit = init; + return Promise.resolve(mockResponse()); + }) as typeof fetch); + + await withRequest("vtex_segment=abc; foo=bar", async () => { + await vtexFetchWithCookies("/api/checkout/pub/orderForm", { + headers: new Headers({ + "X-Custom-Trace": "trace-id", + "X-VTEX-Operation": "test-op", + }), + }); + }); + + expect(headerValue(lastInit, "x-custom-trace")).toBe("trace-id"); + expect(headerValue(lastInit, "x-vtex-operation")).toBe("test-op"); + // Caller didn't pass a Cookie — auto-injection picks up the + // request's cookie and forwards it without dropping the + // other headers. + expect(headerValue(lastInit, "cookie")).toBeDefined(); + }); + + it("preserves an existing Cookie header passed via Headers and sanitises it in place", async () => { + setVtexFetch(((_url: string, init?: RequestInit) => { + lastInit = init; + return Promise.resolve(mockResponse()); + }) as typeof fetch); + + await withRequest("vtex_segment=abc", async () => { + await vtexFetchWithCookies("/api/checkout/pub/orderForm", { + headers: new Headers({ + "X-Custom": "keep-me", + cookie: "checkout.vtex.com=__ofid=xyz; vtex_segment=mine", + }), + }); + }); + + expect(headerValue(lastInit, "x-custom")).toBe("keep-me"); + expect(headerValue(lastInit, "cookie")).toContain("checkout.vtex.com=__ofid=xyz"); + }); +}); diff --git a/vtex/actions/checkout.ts b/vtex/actions/checkout.ts index 384f1d8..5aeadbe 100644 --- a/vtex/actions/checkout.ts +++ b/vtex/actions/checkout.ts @@ -7,7 +7,7 @@ * @see https://developers.vtex.com/docs/api-reference/checkout-api */ -import { getVtexConfig, vtexFetch, vtexFetchWithCookies } from "../client"; +import { getVtexConfig, vtexFetchWithCookies } from "../client"; import type { OrderForm } from "../types"; export const DEFAULT_EXPECTED_SECTIONS = [ @@ -179,7 +179,12 @@ export async function simulateCart(props: SimulateCartProps) { const { items, postalCode, country, RnbBehavior = 1 } = props; const config = getVtexConfig(); const params = appendSc(new URLSearchParams({ RnbBehavior: String(RnbBehavior) })); - return vtexFetch(`/api/checkout/pub/orderForms/simulation?${params}`, { + // Uses vtexFetchWithCookies so any Set-Cookie VTEX returns on the + // orderForm-scoped simulation reaches the browser via RequestContext. + // Without this, the segment/ownership cookies VTEX may rotate during + // simulation are dropped, and the storefront's local orderFormId + // drifts away from VTEX's checkout.vtex.com server cookie. + return vtexFetchWithCookies(`/api/checkout/pub/orderForms/simulation?${params}`, { method: "POST", body: JSON.stringify({ items, @@ -352,7 +357,7 @@ export interface UpdateItemPriceProps { export async function updateItemPrice(props: UpdateItemPriceProps): Promise { const { orderFormId, itemIndex, price } = props; - return vtexFetch( + return vtexFetchWithCookies( `/api/checkout/pub/orderForm/${orderFormId}/items/${itemIndex}/price`, { method: "PUT", body: JSON.stringify({ price }) }, ); @@ -403,7 +408,9 @@ export async function getInstallments(props: GetInstallmentsProps) { const { orderFormId, paymentSystem } = props; const params = new URLSearchParams({ paymentSystem: String(paymentSystem) }); appendSc(params); - return vtexFetch(`/api/checkout/pub/orderForm/${orderFormId}/installments?${params}`); + return vtexFetchWithCookies( + `/api/checkout/pub/orderForm/${orderFormId}/installments?${params}`, + ); } // --------------------------------------------------------------------------- @@ -434,7 +441,9 @@ export interface ChangeToAnonymousUserProps { export async function changeToAnonymousUser(props: ChangeToAnonymousUserProps): Promise { const { orderFormId } = props; - return vtexFetch(`/api/checkout/changeToAnonymousUser/${orderFormId}`); + // This endpoint rotates the orderForm ownership cookies — must use + // vtexFetchWithCookies so the new cookies reach the browser. + return vtexFetchWithCookies(`/api/checkout/changeToAnonymousUser/${orderFormId}`); } export interface ClearOrderFormMessagesProps { @@ -445,10 +454,13 @@ export async function clearOrderFormMessages( props: ClearOrderFormMessagesProps, ): Promise { const { orderFormId } = props; - return vtexFetch(`/api/checkout/pub/orderForm/${orderFormId}/messages/clear`, { - method: "POST", - body: JSON.stringify({}), - }); + return vtexFetchWithCookies( + `/api/checkout/pub/orderForm/${orderFormId}/messages/clear`, + { + method: "POST", + body: JSON.stringify({}), + }, + ); } // --------------------------------------------------------------------------- @@ -477,7 +489,7 @@ export async function getSellersByRegion( const params = new URLSearchParams({ country: "BRA", postalCode }); const sc = salesChannel ?? getVtexConfig().salesChannel; if (sc) params.set("sc", sc); - const resp = await vtexFetch(`/api/checkout/pub/regions/?${params}`); + const resp = await vtexFetchWithCookies(`/api/checkout/pub/regions/?${params}`); return resp[0]?.sellers?.length > 0 ? resp[0] : null; } @@ -490,12 +502,19 @@ export interface SetShippingPostalCodeProps { export async function setShippingPostalCode(props: SetShippingPostalCodeProps): Promise { const { orderFormId, postalCode, country = "BRA" } = props; try { - await vtexFetch(`/api/checkout/pub/orderForm/${orderFormId}/attachments/shippingData`, { - method: "POST", - body: JSON.stringify({ - selectedAddresses: [{ postalCode, country }], - }), - }); + // VTEX docs note that /attachments/shippingData can rotate the + // CheckoutOrderFormOwnership cookie. vtexFetchWithCookies ensures + // any such Set-Cookie reaches the browser via RequestContext, + // keeping the storefront and VTEX bound to the same orderForm. + await vtexFetchWithCookies( + `/api/checkout/pub/orderForm/${orderFormId}/attachments/shippingData`, + { + method: "POST", + body: JSON.stringify({ + selectedAddresses: [{ postalCode, country }], + }), + }, + ); return true; } catch { return false; diff --git a/vtex/client.ts b/vtex/client.ts index 0c2e9b3..e127b93 100644 --- a/vtex/client.ts +++ b/vtex/client.ts @@ -25,6 +25,53 @@ function getResponseHeaders(): Headers | null { return ctx ? ctx.responseHeaders : null; } +/** + * Hostname of the active storefront request, or `null` outside a request + * scope. Used to rewrite the `Domain` attribute of VTEX `Set-Cookie` + * headers so server-function cookies are scoped identically to the ones + * `createVtexCheckoutProxy` emits (`rewriteSetCookieDomain` → `url.hostname`) + * and to what VTEX itself sets natively (`domain=`). + */ +function getRequestHost(): string | null { + const ctx = RequestContext.current; + if (!ctx) return null; + try { + return new URL(ctx.request.url).hostname; + } catch { + return null; + } +} + +/** + * Normalize a VTEX `Set-Cookie` so the browser accepts it on the storefront + * host AND so it lands at the SAME cookie scope as the checkout proxy. + * + * VTEX sets `checkout.vtex.com` / `CheckoutOrderFormOwnership` with + * `domain=` (e.g. `casaevideonewio.vtexcommercestable.com.br`), + * which the browser would reject on the storefront host. There are two ways + * to make it acceptable: + * + * - strip the `Domain` attribute → host-only cookie + * - rewrite `Domain` to `` → domain-scoped cookie + * + * The checkout proxy does the latter. If this path does the former, the + * cart's cookie (host-only) and the proxy's cookie (domain-scoped) become + * TWO DISTINCT cookies in the browser: they don't overwrite each other, can + * drift to different orderForm ids, and VTEX reads whichever is sent last + * (RFC 6265 §5.4 orders by creation time) — a nondeterministic empty-cart + * bug. Rewriting (instead of stripping) keeps both writers on the same key + * so the newest write always wins. When the host is unknown (only at module + * init, never inside a real request) we fall back to stripping. + */ +function rewriteCookieDomain(cookie: string, host: string | null): string { + // Anchor to an attribute boundary (`; `) so we never touch a `domain=` + // substring that happens to live inside the cookie value (before the + // first `;`). + return host + ? cookie.replace(/(;\s*)domain=[^;]*/i, `$1Domain=${host}`) + : cookie.replace(/;\s*domain=[^;]*/gi, ""); +} + // --------------------------------------------------------------------------- // URL sanitization (ported from deco-cx/apps vtex/utils/fetchVTEX.ts) // --------------------------------------------------------------------------- @@ -223,6 +270,40 @@ function hasCookieHeader(headers: HeadersInit | undefined): boolean { return Object.keys(headers).some((k) => k.toLowerCase() === "cookie"); } +/** + * Read the cookie header value from any HeadersInit shape. + * Returns undefined when no cookie header is set. + */ +function readCookieHeader(headers: HeadersInit | undefined): string | undefined { + if (!headers) return undefined; + if (headers instanceof Headers) return headers.get("cookie") ?? undefined; + if (Array.isArray(headers)) { + const found = headers.find(([k]) => k.toLowerCase() === "cookie"); + return found?.[1]; + } + const rec = headers as Record; + const key = Object.keys(rec).find((k) => k.toLowerCase() === "cookie"); + return key ? rec[key] : undefined; +} + +/** + * Return a new Headers instance that copies `headers` and replaces the + * `cookie` value with `cookieValue` (or removes it when undefined). + * Centralises the "merge cookie into existing init.headers" operation so + * we never spread a Headers instance as a plain object — that collapses + * to {} because Headers has no own enumerable entries, and silently + * wipes every other header the caller set. See PR #53. + */ +function withCookieHeader( + headers: HeadersInit | undefined, + cookieValue: string | undefined, +): Headers { + const next = new Headers(headers ?? {}); + if (cookieValue) next.set("cookie", cookieValue); + else next.delete("cookie"); + return next; +} + export async function vtexFetchResponse( path: string, init?: InstrumentedFetchInit, @@ -241,11 +322,7 @@ export async function vtexFetchResponse( const response = await _fetch(url, { ...init, - headers: { - ...authHeaders(), - ...(segmentCookie ? { cookie: segmentCookie } : {}), - ...init?.headers, - }, + headers: mergeHeaders(authHeaders(), segmentCookie, init?.headers), }); if (!response.ok) { throw new Error(`VTEX API error: ${response.status} ${response.statusText} - ${url}`); @@ -253,6 +330,37 @@ export async function vtexFetchResponse( return response; } +/** + * Combine framework headers + optional segment cookie + caller headers, + * preserving the precedence "caller wins" regardless of whether the + * caller passed `Headers`, `string[][]`, or `Record`. + * + * Why a helper: the naive `{ ...authHeaders, ...init?.headers }` spread + * silently collapses a `Headers` instance to `{}` (Headers has no own + * enumerable entries), which means any cookies the caller put on a + * Headers object are lost on the wire. The `createVtexCheckoutProxy` + * factory passes init with Headers, which makes this the failure mode + * for every forwarder that relies on browser-supplied cookies reaching + * VTEX. Funneling all merges through the `Headers` constructor (which + * correctly absorbs every HeadersInit shape) keeps the bug from + * sneaking back in. + */ +function mergeHeaders( + auth: Record, + segmentCookie: string | null, + callerHeaders: HeadersInit | undefined, +): Headers { + const merged = new Headers(auth); + if (segmentCookie) merged.set("cookie", segmentCookie); + if (callerHeaders) { + const incoming = new Headers(callerHeaders); + incoming.forEach((value, key) => { + merged.set(key, value); + }); + } + return merged; +} + export async function vtexFetch(path: string, init?: InstrumentedFetchInit): Promise { const response = await vtexFetchResponse(path, init); return response.json(); @@ -282,12 +390,22 @@ export async function vtexCachedFetch( ? { ttl: cacheOpts.cacheTTL } : undefined; + // Mirrors vtexFetchResponse: Legacy Catalog and several other GET + // endpoints gate regional seller availability on the `vtex_segment` + // cookie. Cached GETs (PDP / shelf product lookups) must see the same + // regionalization the rest of the stack does — otherwise sites have + // to wrap _fetch themselves to forward the cookie, which is easy to + // get subtly wrong (especially around HeadersInit shapes). Inline + // here keeps the surface small; if a third callsite appears we + // extract a shared helper. + const segmentCookie = !hasCookieHeader(init?.headers) ? getSegmentCookieHeader() : null; + return fetchWithCache( url, () => _fetch(url, { ...init, - headers: { ...authHeaders(), ...init?.headers }, + headers: mergeHeaders(authHeaders(), segmentCookie, init?.headers), }), opts, ); @@ -317,22 +435,29 @@ export async function vtexFetchWithCookies( // otherwise poison every checkout call for the affected user. The drop // report is emitted via warnDroppedCookies() so we have observability the // next time a tag misbehaves. - const existingHeaders = init?.headers as Record | undefined; - if (!existingHeaders?.cookie) { + // + // Headers normalisation: callers pass either Headers, [name,value][], + // or Record. We must NEVER spread a Headers instance as + // a plain object — it collapses to {} and silently drops every other + // header the caller set (auth, content-type, etc.). withCookieHeader() + // funnels every shape through the Headers constructor and is the only + // safe way to rewrite the cookie value. + const callerCookie = readCookieHeader(init?.headers); + if (!callerCookie) { const ctx = RequestContext.current; const raw = ctx?.request.headers.get("cookie"); if (raw) { const { cookies, dropped } = sanitizeOutboundCookieHeader(raw); if (dropped.length) warnDroppedCookies(dropped, vtexHost()); if (cookies) { - init = { ...init, headers: { ...existingHeaders, cookie: cookies } }; + init = { ...init, headers: withCookieHeader(init?.headers, cookies) }; } } } else { // Caller passed an explicit cookie — sanitize it too. - const { cookies, dropped } = sanitizeOutboundCookieHeader(existingHeaders.cookie); + const { cookies, dropped } = sanitizeOutboundCookieHeader(callerCookie); if (dropped.length) warnDroppedCookies(dropped, vtexHost()); - init = { ...init, headers: { ...existingHeaders, cookie: cookies } }; + init = { ...init, headers: withCookieHeader(init?.headers, cookies) }; } const response = await vtexFetchResponse(path, init); @@ -342,14 +467,14 @@ export async function vtexFetchWithCookies( // but skip VTEX internal IS cookies (managed server-side by the middleware). const responseHeaders = getResponseHeaders(); if (responseHeaders) { + const host = getRequestHost(); const setCookies = typeof response.headers.getSetCookie === "function" ? response.headers.getSetCookie() : []; for (const cookie of setCookies) { if (cookie.startsWith(`${SESSION_COOKIE}=`) || cookie.startsWith(`${ANONYMOUS_COOKIE}=`)) { continue; } - const stripped = cookie.replace(/;\s*domain=[^;]*/gi, ""); - responseHeaders.append("set-cookie", stripped); + responseHeaders.append("set-cookie", rewriteCookieDomain(cookie, host)); } } @@ -383,6 +508,14 @@ export async function intelligentSearch( const headers: Record = { ...authHeaders() }; if (opts?.cookieHeader) { headers.cookie = opts.cookieHeader; + } else { + // IS already gets regionId on the query string above, but some + // internal IS flows (and downstream services it consults) still + // honor the `vtex_segment` cookie — forward it when the caller + // didn't pass an explicit one. See vtexCachedFetch for the same + // rationale. + const segmentCookie = getSegmentCookieHeader(); + if (segmentCookie) headers.cookie = segmentCookie; } const fullUrl = url.toString(); diff --git a/vtex/inline-loaders/productDetailsPage.ts b/vtex/inline-loaders/productDetailsPage.ts index e2952d9..7f8ee7b 100644 --- a/vtex/inline-loaders/productDetailsPage.ts +++ b/vtex/inline-loaders/productDetailsPage.ts @@ -17,14 +17,31 @@ export interface PDPProps { indexingSkus?: boolean; /** Use product.description instead of metaTagDescription for SEO */ preferDescription?: boolean; - /** Use lean variant transform (no images/video) for hasVariant[]. Defaults to true. */ + /** + * Use lean variant transform for hasVariant[]. Defaults to false on PDPs: + * variant selectors need image[] and real inventoryLevel to render thumbnails + * and per-SKU stock state, so a full toProduct(level=1) is the safe default. + * Opt-in only if payload size becomes a problem. + */ leanVariants?: boolean; + /** When leanVariants is true, still include image[0] on each variant. Default true. */ + variantIncludeImage?: boolean; + /** When leanVariants is true, still include inventoryLevel on each variant. Default true. */ + variantIncludeInventory?: boolean; } export default async function vtexProductDetailsPage( props: PDPProps, ): Promise { - const { slug, skuId, indexingSkus, preferDescription, leanVariants = true } = props; + const { + slug, + skuId, + indexingSkus, + preferDescription, + leanVariants = false, + variantIncludeImage = true, + variantIncludeInventory = true, + } = props; if (!slug) return null; try { @@ -56,6 +73,8 @@ export default async function vtexProductDetailsPage( baseUrl, priceCurrency: "BRL", leanVariants, + variantIncludeImage, + variantIncludeInventory, }); return { diff --git a/vtex/invoke.ts b/vtex/invoke.ts new file mode 100644 index 0000000..1712e12 --- /dev/null +++ b/vtex/invoke.ts @@ -0,0 +1,181 @@ +/** + * Typed `invoke.vtex.actions.*` object — generator contract. + * + * This file is the source of truth that `@decocms/start/scripts/generate-invoke.ts` + * scans to emit the site-local `src/server/invoke.gen.ts`. The generator: + * + * 1. parses the imports in this file to learn which action lives where, + * 2. walks `invoke.vtex.actions.*` and extracts each entry's: + * - validated input type (the arrow function's first parameter), + * - imported action function (matched against the import map by name), + * - output type (the outermost `as` cast's `Promise<...>` payload), + * 3. emits a top-level `createServerFn` per action so TanStack Start's + * compiler can transform `.handler()` into client RPC stubs (the + * compiler only walks top-level decls, not factory-returned ones). + * + * Every action gets a `forwardResponseCookies()` call in the generated + * handler — that bridges `Set-Cookie` headers captured by + * `vtexFetchWithCookies` into TanStack Start's HTTP response. Without it, + * `checkout.vtex.com` and `CheckoutOrderFormOwnership` never reach the + * browser, and the storefront's mini-cart drifts away from VTEX's + * server-side orderForm. + * + * To add a new action: + * 1. Add an entry below with the input/output types and the action call, + * 2. From a site repo: `npm run generate:invoke`. + */ +import { createInvokeFn } from "@decocms/start/sdk/createInvoke"; +import { + addCouponToCart, + addItemsToCart, + getOrCreateCart, + getSellersByRegion, + type RegionResult, + type SimulationItem, + setShippingPostalCode, + simulateCart, + updateCartItems, + updateOrderFormAttachment, +} from "./actions/checkout"; +import { + type CreateDocumentResult, + createDocument, + getDocument, + patchDocument, + searchDocuments, + type UploadAttachmentOpts, + uploadAttachment, +} from "./actions/masterData"; +import { type NotifyMeProps, notifyMe } from "./actions/misc"; +import { type SubscribeProps, subscribe } from "./actions/newsletter"; +import { createSession, editSession, type SessionData } from "./actions/session"; +import type { OrderForm } from "./types"; + +// --------------------------------------------------------------------------- +// invoke.vtex.actions — typed server functions callable from client +// +// Action bodies receive the validated input object directly and pass it +// straight to the action function (which expects a single `props` object). +// The arrow function body is what the generator parses for "which action +// is this entry calling" — keep the call site shaped as `actionName(data)` +// so the matcher in `generate-invoke.ts` picks the right importedFn. +// --------------------------------------------------------------------------- + +export const invoke = { + vtex: { + actions: { + // -- Cart (OrderForm CRUD) -------------------------------------------- + + getOrCreateCart: createInvokeFn((data: { orderFormId?: string }) => + getOrCreateCart(data), + ) as unknown as (ctx: { data: { orderFormId?: string } }) => Promise, + + addItemsToCart: createInvokeFn( + (data: { + orderFormId: string; + orderItems: Array<{ + id: string; + seller: string; + quantity: number; + }>; + }) => addItemsToCart(data), + ) as unknown as (ctx: { + data: { + orderFormId: string; + orderItems: Array<{ + id: string; + seller: string; + quantity: number; + }>; + }; + }) => Promise, + + updateCartItems: createInvokeFn( + (data: { orderFormId: string; orderItems: Array<{ index: number; quantity: number }> }) => + updateCartItems(data), + ) as unknown as (ctx: { + data: { orderFormId: string; orderItems: Array<{ index: number; quantity: number }> }; + }) => Promise, + + addCouponToCart: createInvokeFn((data: { orderFormId: string; text: string }) => + addCouponToCart(data), + ) as unknown as (ctx: { data: { orderFormId: string; text: string } }) => Promise, + + simulateCart: createInvokeFn( + (data: { items: SimulationItem[]; postalCode: string; country?: string }) => + simulateCart(data), + ), + + // -- Shipping / Region ------------------------------------------------ + + getSellersByRegion: createInvokeFn((data: { postalCode: string; salesChannel?: string }) => + getSellersByRegion(data), + ) as unknown as (ctx: { + data: { postalCode: string; salesChannel?: string }; + }) => Promise, + + setShippingPostalCode: createInvokeFn( + (data: { orderFormId: string; postalCode: string; country?: string }) => + setShippingPostalCode(data), + ) as unknown as (ctx: { + data: { orderFormId: string; postalCode: string; country?: string }; + }) => Promise, + + updateOrderFormAttachment: createInvokeFn( + (data: { orderFormId: string; attachment: string; body: Record }) => + updateOrderFormAttachment(data), + ) as unknown as (ctx: { + data: { orderFormId: string; attachment: string; body: Record }; + }) => Promise, + + // -- Session ---------------------------------------------------------- + + createSession: createInvokeFn((data: Record) => createSession({ data })), + + editSession: createInvokeFn((data: { public: Record }) => + editSession(data), + ) as unknown as (ctx: { + data: { public: Record }; + }) => Promise, + + // -- MasterData ------------------------------------------------------- + + createDocument: createInvokeFn((data: { entity: string; data: Record }) => + createDocument(data), + ) as unknown as (ctx: { + data: { entity: string; data: Record }; + }) => Promise, + + getDocument: createInvokeFn((data: { entity: string; documentId: string }) => + getDocument(data), + ), + + patchDocument: createInvokeFn( + (data: { entity: string; documentId: string; data: Record }) => + patchDocument(data), + ) as unknown as (ctx: { + data: { entity: string; documentId: string; data: Record }; + }) => Promise, + + searchDocuments: createInvokeFn((data: { entity: string; filter: string }) => + searchDocuments(data), + ), + + uploadAttachment: createInvokeFn((data: UploadAttachmentOpts) => + uploadAttachment(data), + ) as unknown as (ctx: { data: UploadAttachmentOpts }) => Promise<{ ok: true }>, + + // -- Newsletter ------------------------------------------------------- + + subscribe: createInvokeFn((data: SubscribeProps) => subscribe(data)) as unknown as (ctx: { + data: SubscribeProps; + }) => Promise, + + // -- Misc ------------------------------------------------------------- + + notifyMe: createInvokeFn((data: NotifyMeProps) => notifyMe(data)) as unknown as (ctx: { + data: NotifyMeProps; + }) => Promise, + }, + }, +} as const; diff --git a/vtex/utils/__tests__/fetchCache.test.ts b/vtex/utils/__tests__/fetchCache.test.ts index 386e27c..be989e1 100644 --- a/vtex/utils/__tests__/fetchCache.test.ts +++ b/vtex/utils/__tests__/fetchCache.test.ts @@ -82,4 +82,31 @@ describe("fetchWithCache", () => { clearFetchCache(); expect(getFetchCacheStats()).toEqual({ entries: 0, inflight: 0 }); }); + + it("evicts the inflight slot when the fetch never settles", async () => { + vi.useFakeTimers(); + try { + // `doFetch` returns a Promise that never resolves — simulates a hung + // VTEX subrequest (TCP open, no FIN, no response). Without the + // timeout guard, the inflight Map entry would leak forever and + // subsequent callers would `await` a zombie Promise — the prod + // memory-leak this fix addresses. + const doFetch = vi.fn(() => new Promise(() => {})); + + const pending = fetchWithCache("hung-key", doFetch); + // Swallow the eventual rejection so the unhandled rejection doesn't + // fail the test runner. + pending.catch(() => {}); + + expect(getFetchCacheStats().inflight).toBe(1); + + // Fast-forward past the 10s fetch timeout. + await vi.advanceTimersByTimeAsync(11_000); + + await expect(pending).rejects.toThrow(/timed out/); + expect(getFetchCacheStats().inflight).toBe(0); + } finally { + vi.useRealTimers(); + } + }); }); diff --git a/vtex/utils/__tests__/transform.test.ts b/vtex/utils/__tests__/transform.test.ts index ffc3b99..a9f0554 100644 --- a/vtex/utils/__tests__/transform.test.ts +++ b/vtex/utils/__tests__/transform.test.ts @@ -586,12 +586,11 @@ describe("toProductVariant", () => { expect(result.inProductGroupWithID).toBe("PROD1"); }); - it("drops images, description, video, brand, gtin, releaseDate", () => { + it("drops description, video, brand, gtin, releaseDate, isVariantOf", () => { const product = makeISProduct({ items: [makeISSku()] }); const sku = makeISSku(); const result = toProductVariant(product, sku, baseOptions); - expect(result.image).toBeUndefined(); expect(result.video).toBeUndefined(); expect(result.description).toBeUndefined(); expect(result.brand).toBeUndefined(); @@ -603,6 +602,51 @@ describe("toProductVariant", () => { expect(result.category).toBeUndefined(); }); + it("includes image[0] by default — selectors render thumbnails from it", () => { + const product = makeISProduct({ items: [makeISSku()] }); + const sku = makeISSku(); + const result = toProductVariant(product, sku, baseOptions); + + expect(result.image).toHaveLength(1); + expect(result.image?.[0]).toMatchObject({ + "@type": "ImageObject", + url: "https://img.com/1.jpg", + encodingFormat: "image", + }); + }); + + it("includes real inventoryLevel by default — selectors gate stock state on it", () => { + const product = makeISProduct({ items: [makeISSku()] }); + const sku = makeISSku(); + const result = toProductVariant(product, sku, baseOptions); + + const offer = result.offers!.offers[0]; + expect(offer.inventoryLevel?.value).toBe(10); + }); + + it("drops image when variantIncludeImage: false", () => { + const product = makeISProduct({ items: [makeISSku()] }); + const sku = makeISSku(); + const result = toProductVariant(product, sku, { + ...baseOptions, + variantIncludeImage: false, + }); + + expect(result.image).toBeUndefined(); + }); + + it("zeros inventoryLevel when variantIncludeInventory: false (legacy lean behavior)", () => { + const product = makeISProduct({ items: [makeISSku()] }); + const sku = makeISSku(); + const result = toProductVariant(product, sku, { + ...baseOptions, + variantIncludeInventory: false, + }); + + const offer = result.offers!.offers[0]; + expect(offer.inventoryLevel?.value).toBe(0); + }); + it("filters additionalProperty to variant-differentiating names only", () => { const product = makeISProduct({ items: [makeISSku()] }); const sku = makeISSku(); diff --git a/vtex/utils/fetchCache.ts b/vtex/utils/fetchCache.ts index edf1f21..40ba52a 100644 --- a/vtex/utils/fetchCache.ts +++ b/vtex/utils/fetchCache.ts @@ -10,6 +10,12 @@ const DEFAULT_MAX_ENTRIES = 500; const MAX_RETRIES = 2; const RETRY_DELAYS = [200, 400]; +// Per-attempt timeout. Bounds how long a single hung `fetch()` can hold an +// inflight entry alive. Without this, a VTEX subrequest that never settles +// leaks the inflight Map slot forever and every subsequent request for the +// same cache key joins the zombie Promise, pinning memory until +// `exceededMemory` (observed in prod: 514 hard crashes / 24h on a PLP route). +const FETCH_TIMEOUT_MS = 10_000; interface CacheEntry { body: unknown; @@ -49,6 +55,24 @@ function isRetryable(response: Response): boolean { return response.status >= 500 || response.status === 429; } +/** + * Race a Promise against a timeout so callers' `.finally()` always runs. + * Critical for evicting the inflight Map entry when a `fetch()` hangs — + * without this, a never-settling Promise leaks the Map slot forever and + * every subsequent request for the same key joins the zombie Promise. + */ +function withTimeout(work: Promise, ms: number, label: string): Promise { + let timer: ReturnType | undefined; + const timeout = new Promise((_, reject) => { + timer = setTimeout(() => { + reject(new Error(`${label} timed out after ${ms}ms`)); + }, ms); + }); + return Promise.race([work, timeout]).finally(() => { + clearTimeout(timer); + }); +} + async function executeFetch( url: string, doFetch: () => Promise, @@ -131,8 +155,14 @@ export function fetchWithCache( if (isStale && !entry.refreshing) { entry.refreshing = true; - // Background refresh: no retry — stale data is already being served - executeFetch(cacheKey, doFetch, false) + // Background refresh: no retry — stale data is already being served. + // Timeout guards against a hung VTEX response leaving `refreshing` + // stuck true forever (which would silently disable revalidation). + withTimeout( + executeFetch(cacheKey, doFetch, false), + FETCH_TIMEOUT_MS, + `fetchCache stale-refresh ${cacheKey}`, + ) .then((fresh) => { const ttl = opts?.ttl ?? ttlForStatus(fresh.status); const existingWasSuccess = entry.status >= 200 && entry.status < 300; @@ -156,7 +186,15 @@ export function fetchWithCache( const existing = inflight.get(cacheKey); if (existing) return existing.then((e) => e.body as T | null); - const promise = executeFetch(cacheKey, doFetch) + // Wrap with a timeout so the `.finally()` below always runs and evicts + // the inflight slot — even if `executeFetch` never settles. See the + // FETCH_TIMEOUT_MS comment at the top of this file for the leak this + // guards against. + const promise = withTimeout( + executeFetch(cacheKey, doFetch), + FETCH_TIMEOUT_MS, + `fetchCache ${cacheKey}`, + ) .then((fresh) => { const ttl = opts?.ttl ?? ttlForStatus(fresh.status); if (ttl > 0) { diff --git a/vtex/utils/transform.ts b/vtex/utils/transform.ts index 3c8d553..77acca9 100644 --- a/vtex/utils/transform.ts +++ b/vtex/utils/transform.ts @@ -109,6 +109,10 @@ interface ProductOptions { leanVariants?: boolean; /** Property names to keep on lean variant additionalProperty. Defaults to VARIANT_PROPERTY_NAMES. */ variantPropertyNames?: Set; + /** When leanVariants is true, still include image[0] on each variant entry. Default true. */ + variantIncludeImage?: boolean; + /** When leanVariants is true, still include inventoryLevel on each variant offer. Default true. */ + variantIncludeInventory?: boolean; } /** Returns first available sku */ @@ -670,16 +674,18 @@ const VARIANT_PROPERTY_NAMES = new Set(["Cor", "Voltagem", "Tamanho"]); /** * Build a minimal offer for variant display. Keeps only availability and seller. - * No priceSpecification, no inventoryLevel, no teasers. + * No priceSpecification, no teasers. inventoryLevel is preserved from the real + * offer unless `includeInventory` is false (variant selectors rely on it to + * decide stock state per SKU — dropping it hard-zeroes every variant). */ -const buildOfferVariant = (offer: Offer): Offer => ({ +const buildOfferVariant = (offer: Offer, includeInventory: boolean): Offer => ({ "@type": "Offer", identifier: offer.identifier, price: offer.price, seller: offer.seller, availability: offer.availability, priceSpecification: [], - inventoryLevel: { value: 0 }, + inventoryLevel: includeInventory ? offer.inventoryLevel : { value: 0 }, }); /** @@ -688,9 +694,11 @@ const buildOfferVariant = (offer: Offer): Offer => ({ * Keeps only what variant selectors need: * - url, productID, sku, name, inProductGroupWithID * - additionalProperty filtered to variant-differentiating props (Cor, Voltagem, Tamanho) - * - offers with availability + seller only (no price specs) + * - image[0] (when variantIncludeImage is not false) — selectors render thumbnails + * - offers with availability + seller + real inventoryLevel (when variantIncludeInventory + * is not false) — selectors decide stock state per SKU from inventoryLevel.value * - * Drops: images, description, video, brand, category, gtin, releaseDate, + * Drops: description, video, brand, category, gtin, releaseDate, * alternateName, isAccessoryOrSparePartFor, isVariantOf */ export const toProductVariant =

( @@ -699,9 +707,11 @@ export const toProductVariant =

( options: ProductOptions, ): Product => { const { baseUrl, priceCurrency } = options; - const { productId } = product; + const { productId, items } = product; const { name, itemId: skuId } = sku; const variantProps = options.variantPropertyNames ?? VARIANT_PROPERTY_NAMES; + const includeImage = options.variantIncludeImage !== false; + const includeInventory = options.variantIncludeInventory !== false; // additionalProperty: only variant-differentiating specs const specificationsAdditionalProperty = isLegacySku(sku) @@ -711,11 +721,34 @@ export const toProductVariant =

( variantProps.has(prop.name ?? ""), ); - // Offers: all sellers but lean (availability + seller only) + // Offers: best seller, lean (availability + seller; optional inventoryLevel) const offerConverter = isLegacyProduct(product) ? toOfferLegacy : toOffer; const allOffers = (sku.sellers ?? []).map(offerConverter).sort(bestOfferFirst); const bestOffer = allOffers[0]; - const leanOffers = bestOffer ? [buildOfferVariant(bestOffer)] : []; + const leanOffers = bestOffer ? [buildOfferVariant(bestOffer, includeInventory)] : []; + + // image[0] only — selectors render a single thumbnail. Reuse the same + // imagesByKey lookup toProduct uses so URLs stay consistent across variants. + const imagesByKey = + options.imagesByKey ?? + items + .flatMap((i) => i.images) + .reduce((map, img) => { + img?.imageUrl && map.set(getImageKey(img.imageUrl), img.imageUrl); + return map; + }, new Map()); + + const image = includeImage + ? nonEmptyArray(sku.images) + ?.slice(0, 1) + .map(({ imageUrl, imageText, imageLabel }) => ({ + "@type": "ImageObject" as const, + alternateName: imageText || imageLabel || "", + url: imagesByKey.get(getImageKey(imageUrl)) ?? imageUrl, + name: imageLabel || "", + encodingFormat: "image", + })) + : undefined; return { "@type": "Product", @@ -725,6 +758,7 @@ export const toProductVariant =

( url: getProductURL(baseUrl, product, sku.itemId).href, inProductGroupWithID: productId, additionalProperty, + ...(image ? { image } : {}), offers: aggregateOffers(leanOffers, priceCurrency), }; };