From c1e46726f188969efd3e65d356595b622e632237 Mon Sep 17 00:00:00 2001 From: Himanshu Gupta Date: Thu, 20 Aug 2026 20:34:00 +0530 Subject: [PATCH 1/2] Add Polar Builder billing --- docs/api-reference/openapi.json | 63 +- docs/internals/endpoints.mdx | 3 +- docs/internals/overview.mdx | 2 +- platform/.dev.vars.example | 7 +- platform/migrations/0014_polar_billing.sql | 22 + platform/package-lock.json | 4515 +++++++++++------- platform/package.json | 7 +- platform/src/lib/auth.ts | 28 + platform/src/lib/billing.ts | 385 +- platform/src/lib/entitlements.ts | 62 +- platform/src/openapi-audience.ts | 6 +- platform/src/openapi.ts | 60 +- platform/src/routes/public/public.index.ts | 6 - platform/src/routes/session/session.index.ts | 9 +- platform/src/secrets.d.ts | 5 +- platform/src/types.ts | 2 +- platform/test/auth-config.test.ts | 64 + platform/test/billing.integration.test.ts | 168 + platform/test/credits.integration.test.ts | 116 + platform/test/entitlements.test.ts | 41 +- platform/test/openapi-docs.test.ts | 2 +- platform/test/openapi.test.ts | 2 +- platform/vitest.auth.config.ts | 6 +- platform/vitest.config.ts | 6 +- platform/worker-configuration.d.ts | 27 +- platform/wrangler.jsonc | 18 +- reference/engineering/IMPLEMENTATION.md | 14 +- web/app/_directions/craft-pricing.tsx | 2 +- web/app/dashboard/WorkspaceClient.tsx | 92 +- web/lib/auth-client.ts | 3 +- web/lib/dashboard-data.test.ts | 5 +- web/lib/dashboard-data.ts | 20 +- web/package-lock.json | 182 +- web/package.json | 5 +- 34 files changed, 4073 insertions(+), 1882 deletions(-) create mode 100644 platform/migrations/0014_polar_billing.sql create mode 100644 platform/test/billing.integration.test.ts create mode 100644 platform/test/credits.integration.test.ts diff --git a/docs/api-reference/openapi.json b/docs/api-reference/openapi.json index 8699810..fc0f7b5 100644 --- a/docs/api-reference/openapi.json +++ b/docs/api-reference/openapi.json @@ -63,7 +63,7 @@ }, { "name": "Billing", - "description": "Checkout, usage, and Stripe webhook handling." + "description": "Plan, credit, and subscription status." }, { "name": "Account", @@ -3418,12 +3418,6 @@ "in": "header", "name": "X-Demo-User", "description": "Local development only. Any stable value selects an isolated demo account. Rejected in production." - }, - "stripeSignature": { - "type": "apiKey", - "in": "header", - "name": "stripe-signature", - "description": "Stripe-generated signature over the exact raw request body." } }, "headers": { @@ -6172,8 +6166,8 @@ "plan": { "type": "string", "enum": [ - "free", - "pro" + "starter", + "builder" ] }, "includedCredits": { @@ -6183,13 +6177,62 @@ "type": "string", "enum": [ "onboarding", - "monthly" + "billing-cycle" ] }, "creditBalance": { "type": "integer" } } + }, + "BillingSummary": { + "type": "object", + "required": [ + "plan", + "status", + "creditBalance", + "includedCredits", + "cancelAtPeriodEnd", + "currentPeriodStart", + "currentPeriodEnd", + "canManageBilling" + ], + "properties": { + "plan": { + "type": "string", + "enum": [ + "starter", + "builder" + ] + }, + "status": { + "type": "string" + }, + "creditBalance": { + "type": "integer" + }, + "includedCredits": { + "type": "integer" + }, + "cancelAtPeriodEnd": { + "type": "boolean" + }, + "currentPeriodStart": { + "type": [ + "integer", + "null" + ] + }, + "currentPeriodEnd": { + "type": [ + "integer", + "null" + ] + }, + "canManageBilling": { + "type": "boolean" + } + } } } } diff --git a/docs/internals/endpoints.mdx b/docs/internals/endpoints.mdx index 625ded2..87bc12c 100644 --- a/docs/internals/endpoints.mdx +++ b/docs/internals/endpoints.mdx @@ -26,7 +26,7 @@ Called by the video2ctx web application or an explicit signed-in account action. | `POST` | `/api/auth/sign-in/social` | `signInWithSocialProvider` | Start Google sign-in | Public or protocol-signed | Starts an interactive browser sign-in; do not call it with API-key credentials. | | `POST` | `/api/auth/sign-out` | `signOut` | Revoke the current browser or CLI session | `sessionCookie` or `cliSession` | Revokes the presented session; invoke it only for an explicit logout action and clear the matching local credential after success. | | `DELETE` | `/v1/account` | `deleteAccount` | Permanently delete the current account | `sessionCookie` or `demoUser` | Destructive account operation; require deliberate confirmation and never automate it for a user. | -| `POST` | `/v1/billing/checkout` | `createBillingCheckout` | Create a Stripe Checkout session | `sessionCookie` or `demoUser` | Starts an external checkout session; the user must review and complete payment with Stripe. | +| `GET` | `/v1/billing` | `getBilling` | Get the signed-in account billing status | `sessionCookie` | Returns subscription state for the current browser account; do not expose another customer’s provider identifiers. | | `POST` | `/v1/demo/youtube/inspect` | `inspectLandingYouTubeVideo` | Inspect a YouTube video from the landing page | Public or protocol-signed | Public, rate-limited demo route; do not use it as a credentialed bulk-data API. | | `POST` | `/v1/notification-preferences/confirm-email` | `confirmNotificationEmail` | Confirm monitor email alerts from the signed-in dashboard | `sessionCookie` or `cliSession` or `bearerApiKey` or `apiKey` or `demoUser` | Enables email delivery only for the signed-in account after validating the confirmation token. | | `DELETE` | `/v1/oauth/youtube` | `disconnectYouTube` | Disconnect the YouTube account | `sessionCookie` or `demoUser` | Mutates the account connection state; require an explicit user action. | @@ -40,7 +40,6 @@ Called by an external provider or through a signed link with protocol-specific s | Method | Path | Operation ID | Summary | Declared access | Safety notes | | --- | --- | --- | --- | --- | --- | -| `POST` | `/v1/billing/webhook` | `handleStripeWebhook` | Handle a Stripe webhook | `stripeSignature` | Accept only Stripe-signed requests and preserve idempotent event handling. | | `GET` | `/v1/email/unsubscribe` | `unsubscribeEmail` | Unsubscribe from email digests | Public or protocol-signed | A signed link changes email preferences; do not expose or reuse its token. | | `POST` | `/v1/email/unsubscribe` | `unsubscribeEmailPost` | Unsubscribe from email digests | Public or protocol-signed | Changes email preferences; validate the signed request and avoid logging its token. | | `GET` | `/v1/oauth/youtube/callback` | `completeYouTubeOAuth` | Complete YouTube OAuth | Public or protocol-signed | OAuth callback; validate state and consume authorization codes only once. | diff --git a/docs/internals/overview.mdx b/docs/internals/overview.mdx index 5075c51..4c3f0fc 100644 --- a/docs/internals/overview.mdx +++ b/docs/internals/overview.mdx @@ -8,7 +8,7 @@ This section documents every operation that should not be treated as a normal ex | Audience | Intended caller | | --- | --- | | First-party | The video2ctx web application or an explicit account action | -| Callback | A signed provider link, OAuth provider, email recipient, or Stripe | +| Callback | A signed provider link, OAuth provider, email recipient, or Polar | | Operator | Authorized video2ctx platform administration | diff --git a/platform/.dev.vars.example b/platform/.dev.vars.example index 5705e0e..7174a01 100644 --- a/platform/.dev.vars.example +++ b/platform/.dev.vars.example @@ -4,9 +4,10 @@ GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= YOUTUBE_OAUTH_ENCRYPTION_KEY=base64-encoded-32-byte-key TURNSTILE_SECRET= -STRIPE_SECRET_KEY= -STRIPE_WEBHOOK_SECRET= -STRIPE_PRO_PRICE_ID= +POLAR_ACCESS_TOKEN= +POLAR_WEBHOOK_SECRET= +POLAR_ENVIRONMENT=sandbox +POLAR_BUILDER_PRODUCT_ID= # Required in production for the anonymous landing-page inspection quota. LANDING_DEMO_RATE_LIMIT_MODE=disabled UPSTASH_REDIS_REST_URL= diff --git a/platform/migrations/0014_polar_billing.sql b/platform/migrations/0014_polar_billing.sql new file mode 100644 index 0000000..3f18987 --- /dev/null +++ b/platform/migrations/0014_polar_billing.sql @@ -0,0 +1,22 @@ +PRAGMA foreign_keys = ON; + +-- Application-owned projection of billing state. Polar remains the payment +-- system of record; this table is the local state used for authorization and UI. +CREATE TABLE billing_accounts ( + user_id TEXT PRIMARY KEY REFERENCES user(id) ON DELETE CASCADE, + provider TEXT NOT NULL DEFAULT 'polar' CHECK(provider IN ('polar')), + provider_customer_id TEXT UNIQUE, + provider_subscription_id TEXT UNIQUE, + provider_product_id TEXT, + plan TEXT NOT NULL DEFAULT 'starter' CHECK(plan IN ('starter', 'builder')), + status TEXT NOT NULL DEFAULT 'inactive', + cancel_at_period_end INTEGER NOT NULL DEFAULT 0 CHECK(cancel_at_period_end IN (0, 1)), + current_period_start INTEGER, + current_period_end INTEGER, + provider_updated_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL +); + +CREATE INDEX billing_accounts_subscription_idx + ON billing_accounts(provider, provider_subscription_id); + diff --git a/platform/package-lock.json b/platform/package-lock.json index aa40568..34bc26d 100644 --- a/platform/package-lock.json +++ b/platform/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@better-auth/api-key": "1.6.26", "@cloudflare/containers": "0.3.7", + "@polar-sh/better-auth": "1.8.4", + "@polar-sh/sdk": "0.47.1", "@scalar/hono-api-reference": "^0.11.12", "@upstash/redis": "^1.38.2", "all-things-youtube": "0.2.2", @@ -19,8 +21,8 @@ "hono": "^4.13.1", "react": "19.2.8", "react-email": "6.9.2", - "stripe": "^18.5.0", - "striptags": "^3.2.0" + "striptags": "^3.2.0", + "zod": "4.4.3" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.21.3", @@ -49,12 +51,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/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==", - "license": "MIT" - }, "node_modules/@babel/generator": { "version": "7.29.8", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", @@ -542,6 +538,13 @@ "node": ">=12" } }, + "node_modules/@drizzle-team/brocli": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", + "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==", + "license": "Apache-2.0", + "optional": true + }, "node_modules/@emnapi/runtime": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", @@ -553,26 +556,22 @@ "tslib": "^2.4.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], + "node_modules/@esbuild-kit/core-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "deprecated": "Merged into tsx: https://tsx.hirok.io", "license": "MIT", "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "esbuild": "~0.18.20", + "source-map-support": "^0.5.21" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -582,13 +581,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -598,13 +597,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -614,13 +613,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -630,13 +629,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -646,13 +645,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -662,13 +661,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -678,13 +677,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -694,13 +693,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -710,13 +709,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -726,13 +725,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -742,13 +741,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -758,13 +757,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -774,13 +773,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -790,13 +789,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -806,13 +805,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -822,15 +821,15 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, @@ -838,542 +837,569 @@ "netbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "netbsd" + "openbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, "os": [ - "openbsd" + "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ - "x64" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "openbsd" + "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ - "arm64" + "ia32" ], "license": "MIT", "optional": true, "os": [ - "openharmony" + "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "sunos" + "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/win32-arm64": { + "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "deprecated": "Merged into tsx: https://tsx.hirok.io", + "license": "MIT", + "optional": true, + "dependencies": { + "@esbuild-kit/core-utils": "^3.3.2", + "get-tsconfig": "^4.7.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ - "arm64" + "ppc64" ], "license": "MIT", "optional": true, "os": [ - "win32" + "aix" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-ia32": { + "node_modules/@esbuild/android-arm": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ - "ia32" + "arm" ], "license": "MIT", "optional": true, "os": [ - "win32" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-x64": { + "node_modules/@esbuild/android-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ - "x64" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "win32" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "dev": true, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { "node": ">=18" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.2.tgz", - "integrity": "sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.2.tgz", - "integrity": "sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.1" - } - }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.2.tgz", - "integrity": "sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "dependencies": { - "@img/sharp-wasm32": "0.35.2" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-freebsd-wasm32/node_modules/@img/sharp-wasm32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.2.tgz", - "integrity": "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==", - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.1.tgz", - "integrity": "sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.1.tgz", - "integrity": "sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.1.tgz", - "integrity": "sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==", + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.1.tgz", - "integrity": "sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.1.tgz", - "integrity": "sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ - "ppc64" + "ia32" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.1.tgz", - "integrity": "sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ - "riscv64" + "loong64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.1.tgz", - "integrity": "sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ - "s390x" + "mips64el" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.1.tgz", - "integrity": "sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ - "x64" + "ppc64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.1.tgz", - "integrity": "sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ - "arm64" + "riscv64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.1.tgz", - "integrity": "sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ - "x64" + "s390x" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ "linux" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.2.tgz", - "integrity": "sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==", + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ - "arm" + "x64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.2.tgz", - "integrity": "sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "netbsd" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.2.tgz", - "integrity": "sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ - "ppc64" + "x64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "netbsd" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.2.tgz", - "integrity": "sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ - "riscv64" + "arm64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.2.tgz", - "integrity": "sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ - "s390x" + "x64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.2.tgz", - "integrity": "sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], - "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "sunos" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.1" + "node": ">=18" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.2.tgz", - "integrity": "sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.2.tgz", + "integrity": "sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==", "cpu": [ "arm64" ], @@ -1381,7 +1407,7 @@ "license": "Apache-2.0", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { "node": ">=20.9.0" @@ -1390,13 +1416,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.1" + "@img/sharp-libvips-darwin-arm64": "1.3.1" } }, - "node_modules/@img/sharp-linuxmusl-x64": { + "node_modules/@img/sharp-darwin-x64": { "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.2.tgz", - "integrity": "sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.2.tgz", + "integrity": "sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==", "cpu": [ "x64" ], @@ -1404,7 +1430,7 @@ "license": "Apache-2.0", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { "node": ">=20.9.0" @@ -1413,19 +1439,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.1" + "@img/sharp-libvips-darwin-x64": "1.3.1" } }, - "node_modules/@img/sharp-webcontainers-wasm32": { + "node_modules/@img/sharp-freebsd-wasm32": { "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.2.tgz", - "integrity": "sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==", - "cpu": [ - "wasm32" - ], + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.2.tgz", + "integrity": "sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==", "dev": true, "license": "Apache-2.0", "optional": true, + "os": [ + "freebsd" + ], "dependencies": { "@img/sharp-wasm32": "0.35.2" }, @@ -1436,7 +1462,7 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-webcontainers-wasm32/node_modules/@img/sharp-wasm32": { + "node_modules/@img/sharp-freebsd-wasm32/node_modules/@img/sharp-wasm32": { "version": "0.35.2", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.2.tgz", "integrity": "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==", @@ -1453,1367 +1479,2755 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.2.tgz", - "integrity": "sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==", + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.1.tgz", + "integrity": "sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==", "cpu": [ "arm64" ], "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "darwin" ], - "engines": { - "node": ">=20.9.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.2.tgz", - "integrity": "sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==", + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.1.tgz", + "integrity": "sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==", "cpu": [ - "ia32" + "x64" ], "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "darwin" ], - "engines": { - "node": "^20.9.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.2.tgz", - "integrity": "sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.1.tgz", + "integrity": "sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==", "cpu": [ - "x64" + "arm" ], "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "linux" ], - "engines": { - "node": ">=20.9.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, - "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==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/gen-mapping/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==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "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==", - "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==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.1.tgz", + "integrity": "sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@noble/ciphers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", - "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", - "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.144.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.144.0.tgz", - "integrity": "sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==", - "devOptional": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@playwright/test": { - "version": "1.62.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", - "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright": "1.62.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@poppinss/colors": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", - "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^4.1.5" - } - }, - "node_modules/@poppinss/dumper": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", - "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@poppinss/colors": "^4.1.5", - "@sindresorhus/is": "^7.0.2", - "supports-color": "^10.0.0" - } - }, - "node_modules/@poppinss/exception": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", - "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@react-email/render": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-email/render/-/render-2.1.0.tgz", - "integrity": "sha512-F+zE3O6d6sW6Aj2UjvZAA17R7tJKM7kcq2mgV6k4HCT8jeLLFaVP2txMtH1lgqYFRMZ0Gxsd37q2PRyiXLXXxA==", - "license": "MIT", - "dependencies": { - "entities": "^4.5.0", - "html-to-text": "^9.0.5", - "html5parser": "^3.0.0", - "prettier": "^3.5.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.4.tgz", - "integrity": "sha512-jHC2cnyKz5xU2fhECtFl8OZ83cYNt13GZQD+0uMJ/X3o+ijmd56okHhTUwxVSHPx1IRVIJEZ1/1pPzeLCU6XKA==", + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.1.tgz", + "integrity": "sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==", "cpu": [ - "arm64" + "ppc64" ], "dev": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "android" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-Dc5mPD8F5F/FS8i01syd7FTF6yB2fVthH/TRkjwJkzUK6EpoxHtqvZQP5Zwq80/5z19TWYHIg1KOHboCgVx/aQ==", + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.1.tgz", + "integrity": "sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==", "cpu": [ - "arm64" + "riscv64" ], "dev": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "darwin" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.4.tgz", - "integrity": "sha512-fpDm4oBo6SqLvWUYCmFhdde3U9KH2fRNNMeAnAPAIwxRL345xutL0EtEUcuoxsoazdJGv/MuDBQHlCDrtbvqOg==", + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.1.tgz", + "integrity": "sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==", "cpu": [ - "x64" + "s390x" ], "dev": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "darwin" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.4.tgz", - "integrity": "sha512-rSJoreDE/HoIzoaib6MTp5jQtCTdMHKIvItAKT/ImS6Y6Ww76oUaeMyp4Vc/fAgd/ehji068IxetHXAnqUwN9A==", + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.1.tgz", + "integrity": "sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "freebsd" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.4.tgz", - "integrity": "sha512-/jm8OGHgn7oGaJu3i/qZI9spUGcJ+y/lk43ttQ/iO1tOd9NissG6o97bighBCiL+BKRngmcDuR6ikfwYdJmVuQ==", + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.1.tgz", + "integrity": "sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==", "cpu": [ - "arm" + "arm64" ], "dev": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.4.tgz", - "integrity": "sha512-tIP06BeD9EqvECBrPZ+sqdPlYrT+aYaAiu1wYziVx5elRK/ftm33JxVDy2bXGbr6J0CrtirCkR87/X5a2euEng==", + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.1.tgz", + "integrity": "sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.4.tgz", - "integrity": "sha512-Ql1Q0EQqVThvn9VAVlwNzsUvbSFtCMGjLpRRi4pk5i7NZZ4n5ISiLMjHYtus4VQ2PvkSw24zyaCVsiS+sXPj1w==", + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.2.tgz", + "integrity": "sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==", "cpu": [ - "arm64" + "arm" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.1" } }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.4.tgz", - "integrity": "sha512-GjbjXD4XXfN19D0LZNbmiCBUoDiRACsYHr0yaIbbn8aFsXjHZifcYqu/W5Er5X2X990WjHXFrxarn5chzItorQ==", + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.2.tgz", + "integrity": "sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.1" } }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.4.tgz", - "integrity": "sha512-p5WR0NOwaRmJ/B1b6IjEFLLivwEsf3PrdBIhRbhTCQisbo2SvHHpG4ELB/+FgQNnB88LTOF86upmJmbvZdQ2lw==", + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.2.tgz", + "integrity": "sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==", "cpu": [ - "s390x" + "ppc64" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.1" } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.4.tgz", - "integrity": "sha512-4/GyVjmhR+Tc6HLJvwc1sOhPqAZtySiSMesOZyX6JQ5XBxoTDEMKQzvo07NIK6nTon/SivlZqvhzvuVBNQhObQ==", + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.2.tgz", + "integrity": "sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==", "cpu": [ - "x64" + "riscv64" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.1" } }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.4.tgz", - "integrity": "sha512-l9eeLsCNvPpmSXUej0etw/J1eqV0Jj1D5G/xG6YTijmE6dkv6E2QezgWbTfQk63v952DPqrjOCoiqxq7Bw0YUQ==", + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.2.tgz", + "integrity": "sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==", "cpu": [ - "x64" + "s390x" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.1" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.4.tgz", - "integrity": "sha512-e0F355MSTMm3+UOqtV3L24gFUp2N5m1f8L/7d56deik6va+AXdrt9F8LbzGpeWGWRbZEDq4m8NVnJDeBtf9DZg==", + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.2.tgz", + "integrity": "sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ - "openharmony" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.1" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.4.tgz", - "integrity": "sha512-AWLi0uBRYh6QlE7OKhiz+phZC0qwtij2QZmhmOdsLdFn64m7oMpooE9ICE3lhm9xMb4SpDo2WbHcxX1iFLFtqw==", + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.2.tgz", + "integrity": "sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.1" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.4.tgz", - "integrity": "sha512-UwSDJOg3dqCAejWdxclJjCsh3Qq4vLYMDxmyHqo1btz3stK2VqgwNd3mm5tuIwzSlGIQ/1H9Hr+Zn09mrezNqQ==", + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.2.tgz", + "integrity": "sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.1" } }, - "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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@scalar/client-side-rendering": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@scalar/client-side-rendering/-/client-side-rendering-0.3.5.tgz", - "integrity": "sha512-0MX6HN4hNhMlBTqm+PJ1Rgi5yQy7NkMEPMa6QXdyKAO59pQVzWlBGT+MlAnyXCeVrqFULzZh90v81t5UQ/uYEw==", - "license": "MIT", + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.2.tgz", + "integrity": "sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, "dependencies": { - "@scalar/schemas": "0.8.0", - "@scalar/types": "0.17.0", - "@scalar/validation": "0.6.2" + "@img/sharp-wasm32": "0.35.2" }, "engines": { - "node": ">=22" - } - }, - "node_modules/@scalar/helpers": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.9.2.tgz", - "integrity": "sha512-hjyMpMZjTBZQhyByZmz5oUgRKUQJO5V5AOiJxsVEGbUmgA7sJRQeTrXLB+BEwzaKS5nm2opJeNyMBYLFNK4hiQ==", - "license": "MIT", - "engines": { - "node": ">=22" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@scalar/hono-api-reference": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/@scalar/hono-api-reference/-/hono-api-reference-0.11.12.tgz", - "integrity": "sha512-8cdUntsPjx4WN/hqoP8sFN01ESnJXJDhmLQjAbZHJgnLxoGbITmFlS3Fy6cTPX+5eXuZHdqx9JTqRkdI3mHvzQ==", - "license": "MIT", + "node_modules/@img/sharp-webcontainers-wasm32/node_modules/@img/sharp-wasm32": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.2.tgz", + "integrity": "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==", + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, "dependencies": { - "@scalar/client-side-rendering": "0.3.5" + "@emnapi/runtime": "^1.11.1" }, "engines": { - "node": ">=22" + "node": ">=20.9.0" }, - "peerDependencies": { - "hono": "^4.12.5" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@scalar/schemas": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@scalar/schemas/-/schemas-0.8.0.tgz", - "integrity": "sha512-bwu/NCOghZI/cL6Ayti/Oeb5XEMRTncBsyQeHhkFwk4PZsR910me+kZPd5TAp6TqifMfDbAe3xyLSdlzU/KFLA==", - "license": "MIT", - "dependencies": { - "@scalar/helpers": "0.9.2", - "@scalar/validation": "0.6.2" - }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.2.tgz", + "integrity": "sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=22" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@scalar/types": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.17.0.tgz", - "integrity": "sha512-mj033MX0EFOEwfpO3ch7FGGnMbye1aLlnP6LmTC9Il2AlBCDL41rYPk67jF5ICAMsAES1RQ+8N2bcC0MJnupLQ==", - "license": "MIT", - "dependencies": { - "@scalar/helpers": "0.9.2", - "nanoid": "^5.1.6", - "type-fest": "^5.3.1", - "zod": "^4.3.5" - }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.2.tgz", + "integrity": "sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=22" + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@scalar/types/node_modules/nanoid": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", - "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.2.tgz", + "integrity": "sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, "engines": { - "node": "^18 || >=20" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@scalar/validation": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@scalar/validation/-/validation-0.6.2.tgz", - "integrity": "sha512-Sc1TkcwGV6aVCO51AyKeaGiP8gpwAHxEtO5d3tZzPV+KsnlC/YokQxFxwBrbIXw73k9hmcExnJyGu3k5i6n6VA==", + "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==", "license": "MIT", - "engines": { - "node": ">=20" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@selderee/plugin-htmlparser2": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", - "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "node_modules/@jridgewell/gen-mapping/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==", "license": "MIT", "dependencies": { - "domhandler": "^5.0.3", - "selderee": "^0.11.0" - }, - "funding": { - "url": "https://ko-fi.com/killymxi" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@sindresorhus/is": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", - "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", - "dev": true, + "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==", "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "node": ">=6.0.0" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "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==", "license": "MIT" }, - "node_modules/@speed-highlight/core": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.17.tgz", - "integrity": "sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "license": "CC0-1.0" - }, - "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==", - "license": "MIT" - }, - "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==", - "devOptional": true, "license": "MIT", "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", "license": "MIT", - "dependencies": { - "@types/node": "*" + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "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==", - "devOptional": true, - "license": "MIT" + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "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==", + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.144.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.144.0.tgz", + "integrity": "sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==", "devOptional": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } }, - "node_modules/@types/he": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz", - "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==", + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } }, - "node_modules/@types/node": { - "version": "25.9.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", - "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", - "license": "MIT", + "node_modules/@polar-sh/better-auth": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@polar-sh/better-auth/-/better-auth-1.8.4.tgz", + "integrity": "sha512-BgWCcBQDRYwQn2NEYYzGSEfnrmBJHaDTvYBXGE2V3mmGPKspUDS8+p1LzbNY0Sw681LT8HB5w5Q81Ysc46CVSQ==", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "@polar-sh/checkout": "^0.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@polar-sh/sdk": "^0.47.0", + "better-auth": "^1.4.12", + "zod": "^3.25.0 || ^4.0.0" } }, - "node_modules/@types/react": { - "version": "19.2.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", - "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", - "dev": true, - "license": "MIT", + "node_modules/@polar-sh/checkout": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@polar-sh/checkout/-/checkout-0.2.1.tgz", + "integrity": "sha512-AEKKw3o4ykApECA4bU6a2YC0+aQKTFUasca4ZgCDIjG8AHlu3SjW3Taxh2nfeYAczhah0m0axVF9AV8VfdYzfw==", + "license": "Apache-2.0", "dependencies": { - "csstype": "^3.2.2" + "date-fns": "^4.1.0" + }, + "peerDependencies": { + "@stripe/react-stripe-js": "^3.6.0 || ^4.0.2", + "@stripe/stripe-js": "^7.1.0", + "react": "^18 || ^19" } }, - "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==", - "license": "MIT", + "node_modules/@polar-sh/sdk": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@polar-sh/sdk/-/sdk-0.47.1.tgz", + "integrity": "sha512-fkz7wPLbqfuDmY9LxuXpE2uP2TAV6J0q/YN5hJ4UBxpjbkB0hKM6c4R35N89t83dfzMlG6EOlqOn+Rd1T6XrJQ==", + "peer": true, "dependencies": { - "@types/node": "*" + "standardwebhooks": "^1.0.0", + "zod": "^3.25.65 || ^4.0.0" } }, - "node_modules/@upstash/redis": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.38.2.tgz", - "integrity": "sha512-RZ+JaRCVIS+ZTGnjOnDMr+/0aqDxsBb5rV6aW+Pys4SGELwr5lwE3UbLHRCHqMQ5Ulxj0b/CFBHfbmE175Otog==", + "node_modules/@poppinss/colors": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", + "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", + "dev": true, "license": "MIT", "dependencies": { - "uncrypto": "^0.1.3" + "kleur": "^4.1.5" } }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", - "devOptional": true, + "node_modules/@poppinss/dumper": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", + "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", + "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "@poppinss/colors": "^4.1.5", + "@sindresorhus/is": "^7.0.2", + "supports-color": "^10.0.0" } }, - "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", - "devOptional": true, + "node_modules/@poppinss/exception": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", + "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-email/render": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-email/render/-/render-2.1.0.tgz", + "integrity": "sha512-F+zE3O6d6sW6Aj2UjvZAA17R7tJKM7kcq2mgV6k4HCT8jeLLFaVP2txMtH1lgqYFRMZ0Gxsd37q2PRyiXLXXxA==", "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" + "entities": "^4.5.0", + "html-to-text": "^9.0.5", + "html5parser": "^3.0.0", + "prettier": "^3.5.3" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.0.0" }, "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "react": "^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" } }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", - "devOptional": true, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.4.tgz", + "integrity": "sha512-jHC2cnyKz5xU2fhECtFl8OZ83cYNt13GZQD+0uMJ/X3o+ijmd56okHhTUwxVSHPx1IRVIJEZ1/1pPzeLCU6XKA==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", - "devOptional": true, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-Dc5mPD8F5F/FS8i01syd7FTF6yB2fVthH/TRkjwJkzUK6EpoxHtqvZQP5Zwq80/5z19TWYHIg1KOHboCgVx/aQ==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", - "devOptional": true, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.4.tgz", + "integrity": "sha512-fpDm4oBo6SqLvWUYCmFhdde3U9KH2fRNNMeAnAPAIwxRL345xutL0EtEUcuoxsoazdJGv/MuDBQHlCDrtbvqOg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", - "devOptional": true, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.4.tgz", + "integrity": "sha512-rSJoreDE/HoIzoaib6MTp5jQtCTdMHKIvItAKT/ImS6Y6Ww76oUaeMyp4Vc/fAgd/ehji068IxetHXAnqUwN9A==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", - "devOptional": true, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.4.tgz", + "integrity": "sha512-/jm8OGHgn7oGaJu3i/qZI9spUGcJ+y/lk43ttQ/iO1tOd9NissG6o97bighBCiL+BKRngmcDuR6ikfwYdJmVuQ==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.4.tgz", + "integrity": "sha512-tIP06BeD9EqvECBrPZ+sqdPlYrT+aYaAiu1wYziVx5elRK/ftm33JxVDy2bXGbr6J0CrtirCkR87/X5a2euEng==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.4.tgz", + "integrity": "sha512-Ql1Q0EQqVThvn9VAVlwNzsUvbSFtCMGjLpRRi4pk5i7NZZ4n5ISiLMjHYtus4VQ2PvkSw24zyaCVsiS+sXPj1w==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/accepts/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.4.tgz", + "integrity": "sha512-GjbjXD4XXfN19D0LZNbmiCBUoDiRACsYHr0yaIbbn8aFsXjHZifcYqu/W5Er5X2X990WjHXFrxarn5chzItorQ==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.4.tgz", + "integrity": "sha512-p5WR0NOwaRmJ/B1b6IjEFLLivwEsf3PrdBIhRbhTCQisbo2SvHHpG4ELB/+FgQNnB88LTOF86upmJmbvZdQ2lw==", + "cpu": [ + "s390x" + ], + "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.4.tgz", + "integrity": "sha512-4/GyVjmhR+Tc6HLJvwc1sOhPqAZtySiSMesOZyX6JQ5XBxoTDEMKQzvo07NIK6nTon/SivlZqvhzvuVBNQhObQ==", + "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.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.4.tgz", + "integrity": "sha512-l9eeLsCNvPpmSXUej0etw/J1eqV0Jj1D5G/xG6YTijmE6dkv6E2QezgWbTfQk63v952DPqrjOCoiqxq7Bw0YUQ==", + "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.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.4.tgz", + "integrity": "sha512-e0F355MSTMm3+UOqtV3L24gFUp2N5m1f8L/7d56deik6va+AXdrt9F8LbzGpeWGWRbZEDq4m8NVnJDeBtf9DZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.4.tgz", + "integrity": "sha512-AWLi0uBRYh6QlE7OKhiz+phZC0qwtij2QZmhmOdsLdFn64m7oMpooE9ICE3lhm9xMb4SpDo2WbHcxX1iFLFtqw==", + "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.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.4.tgz", + "integrity": "sha512-UwSDJOg3dqCAejWdxclJjCsh3Qq4vLYMDxmyHqo1btz3stK2VqgwNd3mm5tuIwzSlGIQ/1H9Hr+Zn09mrezNqQ==", + "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.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@scalar/client-side-rendering": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@scalar/client-side-rendering/-/client-side-rendering-0.3.5.tgz", + "integrity": "sha512-0MX6HN4hNhMlBTqm+PJ1Rgi5yQy7NkMEPMa6QXdyKAO59pQVzWlBGT+MlAnyXCeVrqFULzZh90v81t5UQ/uYEw==", "license": "MIT", "dependencies": { - "ajv": "^8.0.0" + "@scalar/schemas": "0.8.0", + "@scalar/types": "0.17.0", + "@scalar/validation": "0.6.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@scalar/helpers": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.9.2.tgz", + "integrity": "sha512-hjyMpMZjTBZQhyByZmz5oUgRKUQJO5V5AOiJxsVEGbUmgA7sJRQeTrXLB+BEwzaKS5nm2opJeNyMBYLFNK4hiQ==", + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@scalar/hono-api-reference": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/@scalar/hono-api-reference/-/hono-api-reference-0.11.12.tgz", + "integrity": "sha512-8cdUntsPjx4WN/hqoP8sFN01ESnJXJDhmLQjAbZHJgnLxoGbITmFlS3Fy6cTPX+5eXuZHdqx9JTqRkdI3mHvzQ==", + "license": "MIT", + "dependencies": { + "@scalar/client-side-rendering": "0.3.5" + }, + "engines": { + "node": ">=22" }, "peerDependencies": { - "ajv": "^8.0.0" + "hono": "^4.12.5" + } + }, + "node_modules/@scalar/schemas": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@scalar/schemas/-/schemas-0.8.0.tgz", + "integrity": "sha512-bwu/NCOghZI/cL6Ayti/Oeb5XEMRTncBsyQeHhkFwk4PZsR910me+kZPd5TAp6TqifMfDbAe3xyLSdlzU/KFLA==", + "license": "MIT", + "dependencies": { + "@scalar/helpers": "0.9.2", + "@scalar/validation": "0.6.2" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true + "engines": { + "node": ">=22" + } + }, + "node_modules/@scalar/types": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.17.0.tgz", + "integrity": "sha512-mj033MX0EFOEwfpO3ch7FGGnMbye1aLlnP6LmTC9Il2AlBCDL41rYPk67jF5ICAMsAES1RQ+8N2bcC0MJnupLQ==", + "license": "MIT", + "dependencies": { + "@scalar/helpers": "0.9.2", + "nanoid": "^5.1.6", + "type-fest": "^5.3.1", + "zod": "^4.3.5" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@scalar/types/node_modules/nanoid": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" } }, - "node_modules/all-things-youtube": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/all-things-youtube/-/all-things-youtube-0.2.2.tgz", - "integrity": "sha512-nnCSOuRgUVTl3/kCPzLDhXy9NEFS4XQMHTbqdr3FKrf21H6Ld+iCfL/UUC9a82hBPDCILrEpFmruinLe+ncRTA==", + "node_modules/@scalar/validation": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@scalar/validation/-/validation-0.6.2.tgz", + "integrity": "sha512-Sc1TkcwGV6aVCO51AyKeaGiP8gpwAHxEtO5d3tZzPV+KsnlC/YokQxFxwBrbIXw73k9hmcExnJyGu3k5i6n6VA==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", "license": "MIT", "dependencies": { - "he": "^1.2.0", - "striptags": "^3.2.0" + "domhandler": "^5.0.3", + "selderee": "^0.11.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@speed-highlight/core": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.17.tgz", + "integrity": "sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/@stripe/react-stripe-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-4.0.2.tgz", + "integrity": "sha512-l2wau+8/LOlHl+Sz8wQ1oDuLJvyw51nQCsu6/ljT6smqzTszcMHifjAJoXlnMfcou3+jK/kQyVe04u/ufyTXgg==", + "license": "MIT", + "peer": true, + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@stripe/stripe-js": ">=1.44.1 <8.0.0", + "react": ">=16.8.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@stripe/stripe-js": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz", + "integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.16" + } + }, + "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==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "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==", + "devOptional": 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==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/he": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz", + "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@upstash/redis": { + "version": "1.38.2", + "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.38.2.tgz", + "integrity": "sha512-RZ+JaRCVIS+ZTGnjOnDMr+/0aqDxsBb5rV6aW+Pys4SGELwr5lwE3UbLHRCHqMQ5Ulxj0b/CFBHfbmE175Otog==", + "license": "MIT", + "peer": true, + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "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.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/all-things-youtube": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/all-things-youtube/-/all-things-youtube-0.2.2.tgz", + "integrity": "sha512-nnCSOuRgUVTl3/kCPzLDhXy9NEFS4XQMHTbqdr3FKrf21H6Ld+iCfL/UUC9a82hBPDCILrEpFmruinLe+ncRTA==", + "license": "MIT", + "dependencies": { + "he": "^1.2.0", + "striptags": "^3.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/atomically": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.1.1.tgz", + "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", + "license": "MIT", + "dependencies": { + "stubborn-fs": "^2.0.0", + "when-exit": "^2.1.4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/better-auth": { + "version": "1.6.26", + "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.26.tgz", + "integrity": "sha512-nhXWrDDj+EnZsHq1j0z1c6DowOMFZWZHe6LCaXbBfLIgHHZm6dyazBQcbRspM4spUIcUt250Mc1BFOSuP7eniQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@better-auth/core": "1.6.26", + "@better-auth/drizzle-adapter": "1.6.26", + "@better-auth/kysely-adapter": "1.6.26", + "@better-auth/memory-adapter": "1.6.26", + "@better-auth/mongo-adapter": "1.6.26", + "@better-auth/prisma-adapter": "1.6.26", + "@better-auth/telemetry": "1.6.26", + "@better-auth/utils": "0.4.2", + "@better-fetch/fetch": "1.3.1", + "@noble/ciphers": "^2.1.1", + "@noble/hashes": "^2.0.1", + "better-call": "1.3.7", + "defu": "^6.1.4", + "jose": "^6.1.3", + "kysely": "^0.28.17 || ^0.29.0", + "nanostores": "^1.1.1", + "zod": "^4.3.6" + }, + "peerDependencies": { + "@lynx-js/react": "*", + "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", + "@sveltejs/kit": "^2.0.0", + "@tanstack/react-start": "^1.0.0", + "@tanstack/solid-start": "^1.0.0", + "better-sqlite3": "^12.0.0", + "drizzle-kit": ">=0.31.4", + "drizzle-orm": "^0.45.2", + "mongodb": "^6.0.0 || ^7.0.0", + "mysql2": "^3.0.0", + "next": "^14.0.0 || ^15.0.0 || ^16.0.0", + "pg": "^8.0.0", + "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0", + "solid-js": "^1.0.0", + "svelte": "^4.0.0 || ^5.0.0", + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", + "vue": "^3.0.0" + }, + "peerDependenciesMeta": { + "@lynx-js/react": { + "optional": true + }, + "@prisma/client": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "@tanstack/react-start": { + "optional": true + }, + "@tanstack/solid-start": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "drizzle-kit": { + "optional": true + }, + "drizzle-orm": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "next": { + "optional": true + }, + "pg": { + "optional": true + }, + "prisma": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "solid-js": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vitest": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/better-call": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.7.tgz", + "integrity": "sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@better-auth/utils": "^0.4.0", + "@better-fetch/fetch": "^1.1.21", + "rou3": "^0.7.12", + "set-cookie-parser": "^3.0.1" + }, + "peerDependencies": { + "zod": "^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", + "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", + "license": "MIT" + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/conf": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-15.1.0.tgz", + "integrity": "sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og==", + "license": "MIT", + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "atomically": "^2.0.3", + "debounce-fn": "^6.0.0", + "dot-prop": "^10.0.0", + "env-paths": "^3.0.0", + "json-schema-typed": "^8.0.1", + "semver": "^7.7.2", + "uint8array-extras": "^1.5.0" + }, + "engines": { + "node": ">=20" + }, + "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==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "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/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debounce": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.2.0.tgz", + "integrity": "sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debounce-fn": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-6.0.0.tgz", + "integrity": "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "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==", + "devOptional": true, + "license": "Apache-2.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==", + "license": "MIT", + "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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "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==", + "license": "BSD-2-Clause", + "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": "10.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-10.2.0.tgz", + "integrity": "sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw==", + "license": "MIT", + "dependencies": { + "type-fest": "^5.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/drizzle-kit": { + "version": "0.31.10", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.10.tgz", + "integrity": "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@drizzle-team/brocli": "^0.10.2", + "@esbuild-kit/esm-loader": "^2.5.5", + "esbuild": "^0.25.4", + "tsx": "^4.21.0" + }, + "bin": { + "drizzle-kit": "bin.cjs" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/drizzle-kit/node_modules/tsx": { + "version": "4.23.12", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.12.tgz", + "integrity": "sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" }, "engines": { "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "devOptional": true, + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/atomically": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.1.1.tgz", - "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "stubborn-fs": "^2.0.0", - "when-exit": "^2.1.4" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">=18" } }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">=18" } }, - "node_modules/better-auth": { - "version": "1.6.26", - "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.26.tgz", - "integrity": "sha512-nhXWrDDj+EnZsHq1j0z1c6DowOMFZWZHe6LCaXbBfLIgHHZm6dyazBQcbRspM4spUIcUt250Mc1BFOSuP7eniQ==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "peer": true, - "dependencies": { - "@better-auth/core": "1.6.26", - "@better-auth/drizzle-adapter": "1.6.26", - "@better-auth/kysely-adapter": "1.6.26", - "@better-auth/memory-adapter": "1.6.26", - "@better-auth/mongo-adapter": "1.6.26", - "@better-auth/prisma-adapter": "1.6.26", - "@better-auth/telemetry": "1.6.26", - "@better-auth/utils": "0.4.2", - "@better-fetch/fetch": "1.3.1", - "@noble/ciphers": "^2.1.1", - "@noble/hashes": "^2.0.1", - "better-call": "1.3.7", - "defu": "^6.1.4", - "jose": "^6.1.3", - "kysely": "^0.28.17 || ^0.29.0", - "nanostores": "^1.1.1", - "zod": "^4.3.6" - }, - "peerDependencies": { - "@lynx-js/react": "*", - "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", - "@sveltejs/kit": "^2.0.0", - "@tanstack/react-start": "^1.0.0", - "@tanstack/solid-start": "^1.0.0", - "better-sqlite3": "^12.0.0", - "drizzle-kit": ">=0.31.4", - "drizzle-orm": "^0.45.2", - "mongodb": "^6.0.0 || ^7.0.0", - "mysql2": "^3.0.0", - "next": "^14.0.0 || ^15.0.0 || ^16.0.0", - "pg": "^8.0.0", - "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0", - "solid-js": "^1.0.0", - "svelte": "^4.0.0 || ^5.0.0", - "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", - "vue": "^3.0.0" - }, - "peerDependenciesMeta": { - "@lynx-js/react": { - "optional": true - }, - "@prisma/client": { - "optional": true - }, - "@sveltejs/kit": { - "optional": true - }, - "@tanstack/react-start": { - "optional": true - }, - "@tanstack/solid-start": { - "optional": true - }, - "better-sqlite3": { - "optional": true - }, - "drizzle-kit": { - "optional": true - }, - "drizzle-orm": { - "optional": true - }, - "mongodb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "next": { - "optional": true - }, - "pg": { - "optional": true - }, - "prisma": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "solid-js": { - "optional": true - }, - "svelte": { - "optional": true - }, - "vitest": { - "optional": true - }, - "vue": { - "optional": true - } + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/better-call": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.7.tgz", - "integrity": "sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], "license": "MIT", - "peer": true, - "dependencies": { - "@better-auth/utils": "^0.4.0", - "@better-fetch/fetch": "^1.1.21", - "rou3": "^0.7.12", - "set-cookie-parser": "^3.0.1" - }, - "peerDependencies": { - "zod": "^4.0.0" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/blake3-wasm": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", - "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "20 || >=22" + "node": ">=18" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.4" + "node": ">=18" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" + } + }, + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "devOptional": true, + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" } }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=18" } }, - "node_modules/citty": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", - "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", - "license": "MIT" - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" } }, - "node_modules/conf": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/conf/-/conf-15.1.0.tgz", - "integrity": "sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "atomically": "^2.0.3", - "debounce-fn": "^6.0.0", - "dot-prop": "^10.0.0", - "env-paths": "^3.0.0", - "json-schema-typed": "^8.0.1", - "semver": "^7.7.2", - "uint8array-extras": "^1.5.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "dev": true, + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">=18" } }, - "node_modules/css-tree": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", - "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "mdn-data": "2.27.1", - "source-map-js": "^1.2.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": ">=18" } }, - "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/debounce": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.2.0.tgz", - "integrity": "sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/debounce-fn": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-6.0.0.tgz", - "integrity": "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=18" } }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/defu": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", - "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "license": "MIT" - }, - "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==", - "devOptional": true, - "license": "Apache-2.0", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "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==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">=18" } }, - "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==", - "license": "BSD-2-Clause", - "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/drizzle-kit/node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/dot-prop": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-10.2.0.tgz", - "integrity": "sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "type-fest": "^5.0.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/drizzle-kit/node_modules/tsx/node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "optional": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">= 0.4" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, "node_modules/engine.io": { @@ -2889,24 +4303,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es-module-lexer": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", @@ -2914,18 +4310,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/esbuild": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", @@ -2993,6 +4377,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fast-uri": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", @@ -3031,7 +4421,6 @@ "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, @@ -3042,57 +4431,11 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/get-tsconfig": { "version": "4.14.2", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.2.tgz", "integrity": "sha512-XpwZALwwl/BaKTAyC6+c5T8y6kCg2jk+XGqOVrKIQmW49pNypYLMRjCUXqa28tQgJlhS2RlzP7sc+Rx7W6qsfw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -3118,42 +4461,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -3245,6 +4552,12 @@ "url": "https://github.com/sponsors/panva" } }, + "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==", + "license": "MIT" + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -3587,6 +4900,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "11.5.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", @@ -3618,15 +4943,6 @@ "node": ">= 18" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/mdn-data": { "version": "2.27.1", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", @@ -3828,18 +5144,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obug": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", @@ -4056,20 +5360,15 @@ "node": ">=6" } }, - "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "license": "BSD-3-Clause", + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, "node_modules/react": { @@ -4135,6 +5434,12 @@ "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -4161,7 +5466,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" @@ -4287,78 +5592,6 @@ "@img/sharp-win32-x64": "0.35.2" } }, - "node_modules/side-channel": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", - "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4", - "side-channel-list": "^1.0.1", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -4413,6 +5646,16 @@ "node": ">=10.0.0" } }, + "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==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4422,6 +5665,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -4429,6 +5683,16 @@ "devOptional": true, "license": "MIT" }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/std-env": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", @@ -4445,26 +5709,6 @@ "node": ">=4" } }, - "node_modules/stripe": { - "version": "18.5.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-18.5.0.tgz", - "integrity": "sha512-Hp+wFiEQtCB0LlNgcFh5uVyKznpDjzyUZ+CNVEf+I3fhlYvh7rZruIg+jOwzJRCpy0ZTPMjlzm7J2/M2N6d+DA==", - "license": "MIT", - "dependencies": { - "qs": "^6.11.0" - }, - "engines": { - "node": ">=12.*" - }, - "peerDependencies": { - "@types/node": ">=12.x.x" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, "node_modules/striptags": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", @@ -5628,6 +6872,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/platform/package.json b/platform/package.json index 5ee1971..fdf53d6 100644 --- a/platform/package.json +++ b/platform/package.json @@ -9,6 +9,7 @@ "build": "tsc --noEmit", "test": "vitest run && npm --prefix youtube-processor test", "test:auth:integration": "vitest run --config vitest.auth.config.ts", + "test:payments:integration": "vitest run --config vitest.auth.config.ts test/billing.integration.test.ts test/credits.integration.test.ts", "test:auth:e2e": "playwright test --config playwright.auth.config.ts", "verify": "npm ci --prefix youtube-processor && npm run build && npm test && npm run test:auth:integration", "test:auth": "vitest run test/auth-config.test.ts test/authentication.test.ts test/cli-auth-boundary.test.ts test/account-route.test.ts", @@ -25,6 +26,8 @@ "dependencies": { "@better-auth/api-key": "1.6.26", "@cloudflare/containers": "0.3.7", + "@polar-sh/better-auth": "1.8.4", + "@polar-sh/sdk": "0.47.1", "@scalar/hono-api-reference": "^0.11.12", "@upstash/redis": "^1.38.2", "all-things-youtube": "0.2.2", @@ -34,8 +37,8 @@ "hono": "^4.13.1", "react": "19.2.8", "react-email": "6.9.2", - "stripe": "^18.5.0", - "striptags": "^3.2.0" + "striptags": "^3.2.0", + "zod": "4.4.3" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.21.3", diff --git a/platform/src/lib/auth.ts b/platform/src/lib/auth.ts index 01ae8a6..4a05209 100644 --- a/platform/src/lib/auth.ts +++ b/platform/src/lib/auth.ts @@ -1,10 +1,18 @@ import { APIError, betterAuth } from 'better-auth'; import type { BetterAuthOptions } from 'better-auth'; import { apiKey } from '@better-auth/api-key'; +import { checkout, polar, portal, webhooks } from '@polar-sh/better-auth'; import { bearer, deviceAuthorization, magicLink } from 'better-auth/plugins'; import type { EmailMessage } from '../types'; import { escapeHtml } from './http'; import { DEFAULT_API_KEY_PERMISSIONS } from './api-key-permissions'; +import { + applyPaidOrder, + applyRefundedOrder, + polarClient, + syncCustomerState, + syncRevokedSubscription, +} from './billing'; export const DEVICE_AUTH_CLIENT_ID = 'video2ctx-cli'; export const DEVICE_AUTH_SCOPE = 'data:read account:access'; @@ -86,6 +94,26 @@ export function createAuthOptions(env: Env, executionCtx: { waitUntil(promise: P await env.EMAIL_TASKS.send(message, { contentType: 'json' }); }, }), + polar({ + client: polarClient(env), + createCustomerOnSignUp: false, + use: [ + checkout({ + products: [{ productId: env.POLAR_BUILDER_PRODUCT_ID, slug: 'builder' }], + successUrl: `${env.APP_ORIGIN}/dashboard?section=settings&checkout=success`, + returnUrl: `${env.APP_ORIGIN}/dashboard?section=settings&checkout=cancelled`, + authenticatedUsersOnly: true, + }), + portal({ returnUrl: `${env.APP_ORIGIN}/dashboard?section=settings` }), + webhooks({ + secret: env.POLAR_WEBHOOK_SECRET, + onOrderPaid: (payload) => applyPaidOrder(env, payload), + onOrderRefunded: (payload) => applyRefundedOrder(env, payload), + onCustomerStateChanged: (payload) => syncCustomerState(env, payload), + onSubscriptionRevoked: (payload) => syncRevokedSubscription(env, payload), + }), + ], + }), ], advanced: { database: { generateId: () => crypto.randomUUID() }, diff --git a/platform/src/lib/billing.ts b/platform/src/lib/billing.ts index fb738fc..a6c93e7 100644 --- a/platform/src/lib/billing.ts +++ b/platform/src/lib/billing.ts @@ -1,64 +1,327 @@ -import Stripe from 'stripe'; -import { ApiError, now, sha256 } from './http'; - -function stripeClient(env: Env): Stripe { - return new Stripe(env.STRIPE_SECRET_KEY, { httpClient: Stripe.createFetchHttpClient() }); -} - -export async function createCheckout(env: Env, user: { id: string; email: string }): Promise { - const stripe = stripeClient(env); - const existing = await env.DB.prepare('SELECT stripe_customer_id FROM plans WHERE user_id=?') - .bind(user.id).first<{ stripe_customer_id: string | null }>(); - const session = await stripe.checkout.sessions.create({ - mode: 'subscription', - ...(existing?.stripe_customer_id ? { customer: existing.stripe_customer_id } : { customer_email: user.email }), - client_reference_id: user.id, - line_items: [{ price: env.STRIPE_PRO_PRICE_ID, quantity: 1 }], - success_url: `${env.APP_ORIGIN}/settings/billing?checkout=success`, - cancel_url: `${env.APP_ORIGIN}/settings/billing?checkout=cancelled`, - subscription_data: { metadata: { user_id: user.id } }, - metadata: { user_id: user.id }, - }, { idempotencyKey: `checkout:${user.id}:${new Date().toISOString().slice(0, 10)}` }); - if (!session.url) throw new ApiError(502, 'CHECKOUT_FAILED', 'Stripe did not return a checkout URL.'); - return session.url; -} - -export async function processStripeWebhook(env: Env, request: Request): Promise { - const signature = request.headers.get('stripe-signature'); - if (!signature) throw new ApiError(401, 'STRIPE_SIGNATURE_MISSING', 'Missing Stripe signature.'); - const payload = await request.text(); - const stripe = stripeClient(env); - let event: Stripe.Event; - try { - event = await stripe.webhooks.constructEventAsync( - payload, signature, env.STRIPE_WEBHOOK_SECRET, undefined, Stripe.createSubtleCryptoProvider() - ); - } catch { - throw new ApiError(401, 'STRIPE_SIGNATURE_INVALID', 'Invalid Stripe signature.'); +import { Polar } from '@polar-sh/sdk'; +import type { WebhookCustomerStateChangedPayload } from '@polar-sh/sdk/models/components/webhookcustomerstatechangedpayload'; +import type { WebhookOrderPaidPayload } from '@polar-sh/sdk/models/components/webhookorderpaidpayload'; +import type { WebhookOrderRefundedPayload } from '@polar-sh/sdk/models/components/webhookorderrefundedpayload'; +import type { WebhookSubscriptionRevokedPayload } from '@polar-sh/sdk/models/components/webhooksubscriptionrevokedpayload'; +import { creditBalance } from './entitlements'; +import { now, sha256 } from './http'; + +interface BillingAccountRow { + plan: 'starter' | 'builder'; + status: string; + provider_customer_id: string | null; + provider_subscription_id: string | null; + cancel_at_period_end: number; + current_period_start: number | null; + current_period_end: number | null; +} + +interface BillingState { + userId: string; + customerId: string; + subscriptionId: string | null; + productId: string | null; + plan: 'starter' | 'builder'; + status: string; + cancelAtPeriodEnd: boolean; + currentPeriodStart: number | null; + currentPeriodEnd: number | null; + eventAt: number; +} + +export interface BillingSummary { + plan: 'starter' | 'builder'; + status: string; + creditBalance: number; + includedCredits: number; + cancelAtPeriodEnd: boolean; + currentPeriodStart: number | null; + currentPeriodEnd: number | null; + canManageBilling: boolean; +} + +export interface PaymentWebhookEnv { + DB: D1Database; + POLAR_BUILDER_PRODUCT_ID: string; + BUILDER_MONTHLY_CREDITS: string; + STARTER_ONBOARDING_CREDITS: string; +} + +export function polarClient(env: Env): Polar { + return new Polar({ + accessToken: env.POLAR_ACCESS_TOKEN, + server: String(env.POLAR_ENVIRONMENT) === 'sandbox' ? 'sandbox' : 'production', + }); +} + +export async function getBillingSummary(env: Env, userId: string): Promise { + const [row, balance] = await Promise.all([ + env.DB.prepare( + `SELECT plan,status,provider_customer_id,provider_subscription_id,cancel_at_period_end, + current_period_start,current_period_end FROM billing_accounts WHERE user_id=?` + ).bind(userId).first(), + creditBalance(env, userId), + ]); + const plan = row?.plan === 'builder' ? 'builder' : 'starter'; + return { + plan, + status: row?.status ?? 'inactive', + creditBalance: balance, + includedCredits: Number(plan === 'builder' ? env.BUILDER_MONTHLY_CREDITS : env.STARTER_ONBOARDING_CREDITS), + cancelAtPeriodEnd: row?.cancel_at_period_end === 1, + currentPeriodStart: row?.current_period_start ?? null, + currentPeriodEnd: row?.current_period_end ?? null, + canManageBilling: Boolean(row?.provider_customer_id), + }; +} + +/** + * A paid order is the only event that grants Builder credits. Each order tops + * the balance up to the plan allowance, so unused credits carry forward without + * letting the balance grow beyond the included amount on renewal. + */ +export async function applyPaidOrder(env: PaymentWebhookEnv, payload: WebhookOrderPaidPayload): Promise { + const order = payload.data; + if (order.productId !== env.POLAR_BUILDER_PRODUCT_ID) return; + if (!order.paid) throw new Error(`Polar order ${order.id} was not paid.`); + + const userId = order.customer.externalId; + if (!userId) throw new Error(`Polar order ${order.id} is missing the Better Auth external ID.`); + const eventId = `order.paid:${order.id}`; + if (await processed(env.DB, eventId)) return; + + if (!await userExists(env.DB, userId)) { + await recordEvent(env.DB, eventId, eventFingerprint(payload)); + console.warn(JSON.stringify({ event: 'polar_order_without_user', orderId: order.id, userId })); + return; } - const duplicate = await env.DB.prepare('SELECT 1 FROM processed_events WHERE source=? AND event_id=?') - .bind('stripe', event.id).first(); - if (duplicate) return; - - if (event.type.startsWith('customer.subscription.')) { - const subscription = event.data.object as Stripe.Subscription; - const userId = subscription.metadata.user_id; - if (userId) { - const active = ['active', 'trialing'].includes(subscription.status); - const periodEnd = subscription.items.data.reduce((latest, item) => Math.max(latest, item.current_period_end), 0); - await env.DB.prepare( - `INSERT INTO plans (user_id,plan,stripe_customer_id,stripe_subscription_id,status,period_end,updated_at) - VALUES (?,?,?,?,?,?,?) - ON CONFLICT(user_id) DO UPDATE SET plan=excluded.plan,stripe_customer_id=excluded.stripe_customer_id, - stripe_subscription_id=excluded.stripe_subscription_id,status=excluded.status, - period_end=excluded.period_end,updated_at=excluded.updated_at` - ).bind( - userId, active ? 'pro' : 'free', String(subscription.customer), subscription.id, - subscription.status, periodEnd * 1000, now() - ).run(); - } + + const eventAt = payload.timestamp.getTime(); + const subscription = order.subscription; + const status = subscription?.status ?? 'active'; + const allowance = Number(env.BUILDER_MONTHLY_CREDITS); + const metadata = JSON.stringify({ + provider: 'polar', + kind: 'billing-cycle', + orderId: order.id, + billingReason: order.billingReason, + allowance, + }); + const state: BillingState = { + userId, + customerId: order.customerId, + subscriptionId: order.subscriptionId, + productId: order.productId, + plan: 'builder', + status, + cancelAtPeriodEnd: subscription?.cancelAtPeriodEnd ?? false, + currentPeriodStart: dateMillis(subscription?.currentPeriodStart), + currentPeriodEnd: dateMillis(subscription?.currentPeriodEnd), + eventAt, + }; + + await env.DB.batch([ + billingUpsert(env.DB, state), + env.DB.prepare( + `INSERT OR IGNORE INTO credit_ledger + (id,user_id,operation_id,entry_type,credits,metadata_json,created_at) + SELECT ?,?,?,'grant',CASE WHEN current_balance < ? THEN ? - current_balance ELSE 0 END,?,? + FROM ( + SELECT COALESCE(SUM(credits),0) AS current_balance + FROM credit_ledger WHERE user_id=? + ) + WHERE EXISTS ( + SELECT 1 FROM billing_accounts + WHERE user_id=? AND provider_updated_at=? AND plan='builder' AND status=? + )` + ).bind( + crypto.randomUUID(), userId, `polar:order:${order.id}`, allowance, allowance, + metadata, now(), userId, userId, eventAt, status, + ), + eventStatement(env.DB, eventId, await eventFingerprint(payload)), + ]); +} + +export async function syncCustomerState( + env: PaymentWebhookEnv, + payload: WebhookCustomerStateChangedPayload, +): Promise { + const customer = payload.data; + const userId = customer.externalId; + if (!userId) throw new Error(`Polar customer ${customer.id} is missing the Better Auth external ID.`); + if (!await userExists(env.DB, userId)) return; + + const current = await env.DB.prepare('SELECT status FROM billing_accounts WHERE user_id=?') + .bind(userId).first<{ status: string }>(); + const matchedSubscription = customer.activeSubscriptions.find( + (candidate) => candidate.productId === env.POLAR_BUILDER_PRODUCT_ID, + ); + const refundLocked = current?.status === 'refunded'; + const subscription = refundLocked ? undefined : matchedSubscription; + const eventId = `customer.state_changed:${customer.id}:${payload.timestamp.toISOString()}`; + if (await processed(env.DB, eventId)) return; + + await env.DB.batch([ + billingUpsert(env.DB, { + userId, + customerId: customer.id, + subscriptionId: matchedSubscription?.id ?? null, + productId: matchedSubscription?.productId ?? null, + plan: subscription ? 'builder' : 'starter', + status: refundLocked ? 'refunded' : subscription?.status ?? 'inactive', + cancelAtPeriodEnd: matchedSubscription?.cancelAtPeriodEnd ?? false, + currentPeriodStart: dateMillis(matchedSubscription?.currentPeriodStart), + currentPeriodEnd: dateMillis(matchedSubscription?.currentPeriodEnd), + eventAt: payload.timestamp.getTime(), + }), + eventStatement(env.DB, eventId, await eventFingerprint(payload)), + ]); +} + +export async function syncRevokedSubscription( + env: PaymentWebhookEnv, + payload: WebhookSubscriptionRevokedPayload, +): Promise { + const subscription = payload.data; + if (subscription.productId !== env.POLAR_BUILDER_PRODUCT_ID) return; + const userId = subscription.customer.externalId; + if (!userId) throw new Error(`Polar subscription ${subscription.id} is missing the Better Auth external ID.`); + if (!await userExists(env.DB, userId)) return; + + const eventId = `subscription.revoked:${subscription.id}:${payload.timestamp.toISOString()}`; + if (await processed(env.DB, eventId)) return; + await env.DB.batch([ + billingUpsert(env.DB, { + userId, + customerId: subscription.customerId, + subscriptionId: subscription.id, + productId: subscription.productId, + plan: 'starter', + status: subscription.status, + cancelAtPeriodEnd: subscription.cancelAtPeriodEnd, + currentPeriodStart: dateMillis(subscription.currentPeriodStart), + currentPeriodEnd: dateMillis(subscription.currentPeriodEnd), + eventAt: payload.timestamp.getTime(), + }), + eventStatement(env.DB, eventId, await eventFingerprint(payload)), + ]); +} + +/** A fully refunded Builder order downgrades the user and resets their balance to Starter. */ +export async function applyRefundedOrder(env: PaymentWebhookEnv, payload: WebhookOrderRefundedPayload): Promise { + const order = payload.data; + if (order.productId !== env.POLAR_BUILDER_PRODUCT_ID) return; + const eventId = `order.refunded:${order.id}`; + if (await processed(env.DB, eventId)) return; + + const userId = order.customer.externalId; + if (!userId) throw new Error(`Polar refund ${order.id} is missing the Better Auth external ID.`); + if (!await userExists(env.DB, userId)) { + await recordEvent(env.DB, eventId, eventFingerprint(payload)); + console.warn(JSON.stringify({ event: 'polar_refund_without_user', orderId: order.id, userId })); + return; + } + + const starterCredits = Number(env.STARTER_ONBOARDING_CREDITS); + const subscription = order.subscription; + const eventAt = payload.timestamp.getTime(); + const state: BillingState = { + userId, + customerId: order.customerId, + subscriptionId: order.subscriptionId, + productId: order.productId, + plan: 'starter', + status: 'refunded', + cancelAtPeriodEnd: subscription?.cancelAtPeriodEnd ?? false, + currentPeriodStart: dateMillis(subscription?.currentPeriodStart), + currentPeriodEnd: dateMillis(subscription?.currentPeriodEnd), + eventAt, + }; + await env.DB.batch([ + billingUpsert(env.DB, state), + env.DB.prepare( + `INSERT OR IGNORE INTO credit_ledger + (id,user_id,operation_id,entry_type,credits,metadata_json,created_at) + SELECT ?,?,?,'adjustment',? - current_balance,?,? + FROM ( + SELECT COALESCE(SUM(credits),0) AS current_balance + FROM credit_ledger WHERE user_id=? + ) + WHERE EXISTS ( + SELECT 1 FROM billing_accounts + WHERE user_id=? AND provider_updated_at=? AND plan='starter' AND status='refunded' + )` + ).bind( + crypto.randomUUID(), userId, `polar:refund:${order.id}`, starterCredits, + JSON.stringify({ provider: 'polar', kind: 'refund-reset', orderId: order.id, balance: starterCredits }), + now(), userId, userId, eventAt, + ), + eventStatement(env.DB, eventId, await eventFingerprint(payload)), + ]); +} + +export async function closeBillingAccount(env: Env, userId: string): Promise { + try { + await polarClient(env).customers.deleteExternal({ externalId: userId, anonymize: true }); + } catch (cause) { + if (isHttpStatus(cause, 404)) return; + throw cause; } - await env.DB.prepare( - `INSERT OR IGNORE INTO processed_events (source,event_id,processed_at,payload_hash) VALUES ('stripe',?,?,?)` - ).bind(event.id, now(), await sha256(payload)).run(); +} + +function billingUpsert(db: D1Database, state: BillingState): D1PreparedStatement { + return db.prepare( + `INSERT INTO billing_accounts + (user_id,provider,provider_customer_id,provider_subscription_id,provider_product_id,plan,status, + cancel_at_period_end,current_period_start,current_period_end,provider_updated_at,updated_at) + VALUES (?,'polar',?,?,?,?,?,?,?,?,?,?) + ON CONFLICT(user_id) DO UPDATE SET + provider_customer_id=excluded.provider_customer_id, + provider_subscription_id=excluded.provider_subscription_id, + provider_product_id=excluded.provider_product_id, + plan=excluded.plan, + status=excluded.status, + cancel_at_period_end=excluded.cancel_at_period_end, + current_period_start=excluded.current_period_start, + current_period_end=excluded.current_period_end, + provider_updated_at=excluded.provider_updated_at, + updated_at=excluded.updated_at + WHERE excluded.provider_updated_at >= billing_accounts.provider_updated_at` + ).bind( + state.userId, state.customerId, state.subscriptionId, state.productId, state.plan, state.status, + state.cancelAtPeriodEnd ? 1 : 0, state.currentPeriodStart, state.currentPeriodEnd, state.eventAt, now(), + ); +} + +function eventStatement(db: D1Database, eventId: string, fingerprint: string): D1PreparedStatement { + return db.prepare( + `INSERT OR IGNORE INTO processed_events (source,event_id,processed_at,payload_hash) VALUES ('polar',?,?,?)` + ).bind(eventId, now(), fingerprint); +} + +async function recordEvent(db: D1Database, eventId: string, fingerprint: Promise): Promise { + await eventStatement(db, eventId, await fingerprint).run(); +} + +async function processed(db: D1Database, eventId: string): Promise { + return Boolean(await db.prepare( + `SELECT 1 FROM processed_events WHERE source='polar' AND event_id=?` + ).bind(eventId).first()); +} + +async function userExists(db: D1Database, userId: string): Promise { + return Boolean(await db.prepare('SELECT 1 FROM user WHERE id=?').bind(userId).first()); +} + +function eventFingerprint(payload: unknown): Promise { + return sha256(JSON.stringify(payload)); +} + +function dateMillis(value: Date | null | undefined): number | null { + return value ? value.getTime() : null; +} + +function isHttpStatus(cause: unknown, statusCode: number): boolean { + return typeof cause === 'object' && cause !== null && 'statusCode' in cause + && (cause as { statusCode?: unknown }).statusCode === statusCode; } diff --git a/platform/src/lib/entitlements.ts b/platform/src/lib/entitlements.ts index 4118b9c..8391f8f 100644 --- a/platform/src/lib/entitlements.ts +++ b/platform/src/lib/entitlements.ts @@ -4,28 +4,41 @@ import { ApiError, now } from './http'; export interface Entitlements { plan: Plan; includedCredits: number; - creditGrant: 'onboarding' | 'monthly'; + creditGrant: 'onboarding' | 'billing-cycle'; projectLimit: number; monitorLimit: number; dailyImportLimit: number; } -export async function entitlements(env: Env, userId: string): Promise { - const row = await env.DB.prepare('SELECT plan FROM plans WHERE user_id = ?').bind(userId).first<{ plan: Plan }>(); - const plan = row?.plan === 'pro' ? 'pro' : 'free'; +export interface CreditEnv { + DB: D1Database; + STARTER_ONBOARDING_CREDITS: string; + BUILDER_MONTHLY_CREDITS: string; + STARTER_PROJECT_LIMIT: string; + STARTER_MONITOR_LIMIT: string; + STARTER_DAILY_IMPORTS: string; + BUILDER_PROJECT_LIMIT: string; + BUILDER_MONITOR_LIMIT: string; + BUILDER_DAILY_IMPORTS: string; +} + +export async function entitlements(env: CreditEnv, userId: string): Promise { + const row = await env.DB.prepare('SELECT plan FROM billing_accounts WHERE user_id = ?') + .bind(userId).first<{ plan: Plan }>(); + const plan = row?.plan === 'builder' ? 'builder' : 'starter'; return { plan, - includedCredits: Number(plan === 'pro' ? env.PRO_MONTHLY_CREDITS : env.FREE_ONBOARDING_CREDITS), - creditGrant: plan === 'pro' ? 'monthly' : 'onboarding', - projectLimit: Number(plan === 'pro' ? env.PRO_PROJECT_LIMIT : env.FREE_PROJECT_LIMIT), - monitorLimit: Number(plan === 'pro' ? env.PRO_MONITOR_LIMIT : env.FREE_MONITOR_LIMIT), - dailyImportLimit: Number(plan === 'pro' ? env.PRO_DAILY_IMPORTS : env.FREE_DAILY_IMPORTS), + includedCredits: Number(plan === 'builder' ? env.BUILDER_MONTHLY_CREDITS : env.STARTER_ONBOARDING_CREDITS), + creditGrant: plan === 'builder' ? 'billing-cycle' : 'onboarding', + projectLimit: Number(plan === 'builder' ? env.BUILDER_PROJECT_LIMIT : env.STARTER_PROJECT_LIMIT), + monitorLimit: Number(plan === 'builder' ? env.BUILDER_MONITOR_LIMIT : env.STARTER_MONITOR_LIMIT), + dailyImportLimit: Number(plan === 'builder' ? env.BUILDER_DAILY_IMPORTS : env.STARTER_DAILY_IMPORTS), }; } export async function enforceImportLimit(env: Env, userId: string, limits: Entitlements, deep = false): Promise { - if (deep && limits.plan !== 'pro') { - throw new ApiError(403, 'PRO_REQUIRED', 'Deep comment fetch is available on Pro.'); + if (deep && limits.plan !== 'builder') { + throw new ApiError(403, 'BUILDER_REQUIRED', 'Deep comment fetch is available on Builder.'); } const row = await env.DB.prepare( 'SELECT COUNT(*) AS count FROM jobs WHERE user_id=? AND created_at>=?' @@ -49,7 +62,7 @@ export async function enforceCount( } } -export async function creditBalance(env: Env, userId: string): Promise { +export async function creditBalance(env: CreditEnv, userId: string): Promise { await ensureCreditGrant(env, userId); const row = await env.DB.prepare('SELECT COALESCE(SUM(credits), 0) AS balance FROM credit_ledger WHERE user_id = ?') .bind(userId) @@ -57,25 +70,12 @@ export async function creditBalance(env: Env, userId: string): Promise { return Number(row?.balance ?? 0); } -export async function ensureCreditGrant(env: Env, userId: string): Promise { +export async function ensureCreditGrant(env: CreditEnv, userId: string): Promise { const limits = await entitlements(env, userId); - if (limits.creditGrant === 'onboarding') { - await ensureOnboardingGrant(env, userId, limits); - return; - } - - const month = new Date().toISOString().slice(0, 7); - await env.DB.prepare( - `INSERT OR IGNORE INTO credit_ledger - (id, user_id, operation_id, entry_type, credits, metadata_json, created_at) - VALUES (?, ?, ?, 'grant', ?, ?, ?)` - ).bind( - crypto.randomUUID(), userId, `monthly:${month}`, limits.includedCredits, - JSON.stringify({ plan: limits.plan, month }), now() - ).run(); + if (limits.creditGrant === 'onboarding') await ensureOnboardingGrant(env, userId, limits); } -async function ensureOnboardingGrant(env: Env, userId: string, limits: Entitlements): Promise { +async function ensureOnboardingGrant(env: CreditEnv, userId: string, limits: Entitlements): Promise { await env.DB.prepare( `INSERT OR IGNORE INTO credit_ledger (id, user_id, operation_id, entry_type, credits, metadata_json, created_at) @@ -94,7 +94,7 @@ async function ensureOnboardingGrant(env: Env, userId: string, limits: Entitleme } export async function reserveCredits( - env: Env, + env: CreditEnv, userId: string, operationId: string, amount: number, @@ -119,7 +119,7 @@ export async function reserveCredits( } export async function settleCredits( - env: Env, + env: CreditEnv, userId: string, operationId: string, reserved: number, @@ -139,7 +139,7 @@ export async function settleCredits( } export async function releaseCredits( - env: Env, + env: CreditEnv, userId: string, operationId: string, reserved: number, diff --git a/platform/src/openapi-audience.ts b/platform/src/openapi-audience.ts index f382413..db4513a 100644 --- a/platform/src/openapi-audience.ts +++ b/platform/src/openapi-audience.ts @@ -70,8 +70,7 @@ export const OPENAPI_OPERATION_AUDIENCE: Readonly> = { confirmNotificationEmail: 'Enables email delivery only for the signed-in account after validating the confirmation token.', createYouTubeConnectUrl: 'Returns a state-bound OAuth URL; start it only from a user-initiated connection flow.', disconnectYouTube: 'Mutates the account connection state; require an explicit user action.', - createBillingCheckout: 'Starts an external checkout session; the user must review and complete payment with Stripe.', + getBilling: 'Returns subscription state for the current browser account; do not expose another customer’s provider identifiers.', deleteAccount: 'Destructive account operation; require deliberate confirmation and never automate it for a user.', - handleStripeWebhook: 'Accept only Stripe-signed requests and preserve idempotent event handling.', unsubscribeEmail: 'A signed link changes email preferences; do not expose or reuse its token.', unsubscribeEmailPost: 'Changes email preferences; validate the signed request and avoid logging its token.', completeYouTubeOAuth: 'OAuth callback; validate state and consume authorization codes only once.', diff --git a/platform/src/openapi.ts b/platform/src/openapi.ts index ecdce49..1623e20 100644 --- a/platform/src/openapi.ts +++ b/platform/src/openapi.ts @@ -295,7 +295,7 @@ export const openApiDocument = { { name: 'Exports', description: 'Project export creation and download.' }, { name: 'Monitoring', description: 'Monitors, notifications, and digest preferences.' }, { name: 'YouTube OAuth', description: 'Connect or disconnect the user’s YouTube account.' }, - { name: 'Billing', description: 'Checkout, usage, and Stripe webhook handling.' }, + { name: 'Billing', description: 'Plan, credit, and subscription status.' }, { name: 'Administration', description: 'Restricted operational APIs.' }, { name: 'Account', description: 'Account lifecycle operations.' }, ], @@ -1283,41 +1283,19 @@ export const openApiDocument = { }, }, }, - '/v1/billing/checkout': { - post: { + '/v1/billing': { + get: { tags: ['Billing'], - operationId: 'createBillingCheckout', - summary: 'Create a Stripe Checkout session', - security: privateSecurity, + operationId: 'getBilling', + summary: 'Get the signed-in account billing status', + security: browserSessionSecurity, responses: { - '200': jsonResponse('Checkout URL.', { - type: 'object', required: ['url'], properties: { url: { type: 'string', format: 'uri' } }, - }), + '200': jsonResponse('Current billing status.', schemaRef('BillingSummary')), '401': responseRef('Unauthorized'), '500': responseRef('ServerError'), }, }, }, - '/v1/billing/webhook': { - post: { - tags: ['Billing'], - operationId: 'handleStripeWebhook', - summary: 'Handle a Stripe webhook', - description: 'Intended for Stripe delivery. Scalar cannot generate a valid signature for an edited payload.', - security: [{ stripeSignature: [] }], - requestBody: { - required: true, - content: { 'application/json': { schema: { type: 'object', additionalProperties: true } } }, - }, - responses: { - '200': jsonResponse('Event processed.', { - type: 'object', required: ['received'], properties: { received: { const: true } }, - }), - '400': responseRef('BadRequest'), - '500': responseRef('ServerError'), - }, - }, - }, '/v1/usage': { get: { tags: ['Billing'], @@ -1429,12 +1407,6 @@ export const openApiDocument = { name: 'X-Demo-User', description: 'Local development only. Any stable value selects an isolated demo account. Rejected in production.', }, - stripeSignature: { - type: 'apiKey', - in: 'header', - name: 'stripe-signature', - description: 'Stripe-generated signature over the exact raw request body.', - }, }, headers: { CreditsCharged: { @@ -2000,12 +1972,26 @@ export const openApiDocument = { type: 'object', additionalProperties: true, properties: { - plan: { type: 'string', enum: ['free', 'pro'] }, + plan: { type: 'string', enum: ['starter', 'builder'] }, includedCredits: { type: 'integer' }, - creditGrant: { type: 'string', enum: ['onboarding', 'monthly'] }, + creditGrant: { type: 'string', enum: ['onboarding', 'billing-cycle'] }, creditBalance: { type: 'integer' }, }, }, + BillingSummary: { + type: 'object', + required: ['plan', 'status', 'creditBalance', 'includedCredits', 'cancelAtPeriodEnd', 'currentPeriodStart', 'currentPeriodEnd', 'canManageBilling'], + properties: { + plan: { type: 'string', enum: ['starter', 'builder'] }, + status: { type: 'string' }, + creditBalance: { type: 'integer' }, + includedCredits: { type: 'integer' }, + cancelAtPeriodEnd: { type: 'boolean' }, + currentPeriodStart: { type: ['integer', 'null'] }, + currentPeriodEnd: { type: ['integer', 'null'] }, + canManageBilling: { type: 'boolean' }, + }, + }, }, }, } as const; diff --git a/platform/src/routes/public/public.index.ts b/platform/src/routes/public/public.index.ts index ad9957a..a525d1d 100644 --- a/platform/src/routes/public/public.index.ts +++ b/platform/src/routes/public/public.index.ts @@ -1,6 +1,5 @@ import { Hono } from 'hono'; import type { App } from '../../types'; -import { processStripeWebhook } from '../../lib/billing'; import { unsubscribe } from '../../lib/digests'; import { youtubeOAuthCallback } from '../../lib/oauth'; import { ApiError, body, escapeHtml, text } from '../../lib/http'; @@ -79,11 +78,6 @@ publicRoutes.post('/scale-inquiries', async (c) => { return c.json(result, 202); }); -publicRoutes.post('/billing/webhook', async (c) => { - await processStripeWebhook(c.env, c.req.raw); - return c.json({ received: true }); -}); - publicRoutes.get('/email/unsubscribe', (c) => { const user = text(c.req.query('user'), 200); const token = text(c.req.query('token'), 500); diff --git a/platform/src/routes/session/session.index.ts b/platform/src/routes/session/session.index.ts index 0d8fafe..aa9c2cb 100644 --- a/platform/src/routes/session/session.index.ts +++ b/platform/src/routes/session/session.index.ts @@ -10,7 +10,7 @@ import { ApiError, asId, body, now, text } from '../../lib/http'; import { enforceCount, enforceImportLimit, entitlements } from '../../lib/entitlements'; import { assertFormat, createProjectExport } from '../../lib/exports'; import { disconnectYoutube, youtubeConnectUrl } from '../../lib/oauth'; -import { createCheckout } from '../../lib/billing'; +import { closeBillingAccount, getBillingSummary } from '../../lib/billing'; import { deleteProjectAssets, deleteR2Prefix, userSearchInstanceId } from '../../lib/research-storage'; import { getProvider } from '../../providers'; import { @@ -42,7 +42,7 @@ export const ACCOUNT_ROUTE_PATTERNS = [ export const SESSION_ONLY_ROUTE_PATTERNS = [ '/oauth/youtube/connect', '/oauth/youtube', - '/billing/checkout', + '/billing', '/admin/*', ] as const; @@ -355,8 +355,8 @@ sessionRoutes.delete('/oauth/youtube', async (c) => { return c.body(null, 204); }); -sessionRoutes.post('/billing/checkout', async (c) => { - return c.json({ url: await createCheckout(c.env, requireUser(c)) }); +sessionRoutes.get('/billing', async (c) => { + return c.json(await getBillingSummary(c.env, requireUser(c).id)); }); sessionRoutes.get('/admin/jobs', async (c) => { @@ -370,6 +370,7 @@ sessionRoutes.get('/admin/jobs', async (c) => { sessionRoutes.delete('/account', requireSessionPrincipal, async (c) => { const user = requireUser(c); + await closeBillingAccount(c.env, user.id); await disconnectYoutube(c.env, user.id); await deleteR2Prefix(c.env.RESEARCH, `private/${user.id}/`); const instanceId = userSearchInstanceId(user.id); diff --git a/platform/src/secrets.d.ts b/platform/src/secrets.d.ts index 895741a..8aca2a2 100644 --- a/platform/src/secrets.d.ts +++ b/platform/src/secrets.d.ts @@ -4,9 +4,8 @@ interface Env { GOOGLE_CLIENT_SECRET: string; YOUTUBE_OAUTH_ENCRYPTION_KEY: string; TURNSTILE_SECRET: string; - STRIPE_SECRET_KEY: string; - STRIPE_WEBHOOK_SECRET: string; - STRIPE_PRO_PRICE_ID: string; + POLAR_ACCESS_TOKEN: string; + POLAR_WEBHOOK_SECRET: string; UPSTASH_REDIS_REST_URL: string; UPSTASH_REDIS_REST_TOKEN: string; LANDING_RATE_LIMIT_SALT: string; diff --git a/platform/src/types.ts b/platform/src/types.ts index ff0a5d6..b0617c8 100644 --- a/platform/src/types.ts +++ b/platform/src/types.ts @@ -1,7 +1,7 @@ import type { createAuth } from './lib/auth'; import type { ProviderId } from './providers/contract'; -export type Plan = 'free' | 'pro'; +export type Plan = 'starter' | 'builder'; export interface AppUser { id: string; diff --git a/platform/test/auth-config.test.ts b/platform/test/auth-config.test.ts index f6f6f35..ce1d705 100644 --- a/platform/test/auth-config.test.ts +++ b/platform/test/auth-config.test.ts @@ -3,6 +3,10 @@ const captured = vi.hoisted(() => ({ auth: undefined as Record | undefined, bearer: undefined as Record | undefined, deviceAuthorization: undefined as Record | undefined, + checkout: undefined as Record | undefined, + portal: undefined as Record | undefined, + webhooks: undefined as Record | undefined, + polar: undefined as Record | undefined, })); vi.mock('@better-auth/api-key', () => ({ @@ -32,6 +36,29 @@ vi.mock('better-auth/plugins', () => ({ }), magicLink: vi.fn(() => ({ id: 'magic-link' })), })); +vi.mock('@polar-sh/sdk', () => ({ + Polar: vi.fn(class { + customers = { deleteExternal: vi.fn() }; + }), +})); +vi.mock('@polar-sh/better-auth', () => ({ + checkout: vi.fn((options: Record) => { + captured.checkout = options; + return () => ({ id: 'polar-checkout' }); + }), + portal: vi.fn((options: Record) => { + captured.portal = options; + return () => ({ id: 'polar-portal' }); + }), + webhooks: vi.fn((options: Record) => { + captured.webhooks = options; + return () => ({ id: 'polar-webhooks' }); + }), + polar: vi.fn((options: Record) => { + captured.polar = options; + return { id: 'polar' }; + }), +})); import { createAuth } from '../src/lib/auth'; @@ -43,6 +70,10 @@ describe('Better Auth API-key configuration', () => { BETTER_AUTH_SECRET: 'test-secret-that-is-long-enough-for-tests', GOOGLE_CLIENT_ID: 'google-client', GOOGLE_CLIENT_SECRET: 'google-secret', + POLAR_ACCESS_TOKEN: 'polar-token', + POLAR_WEBHOOK_SECRET: 'polar-webhook-secret', + POLAR_BUILDER_PRODUCT_ID: 'builder-product', + POLAR_ENVIRONMENT: 'sandbox', } as unknown as Env, { waitUntil: vi.fn() }); expect(captured.apiKey).toMatchObject({ @@ -72,6 +103,10 @@ describe('Better Auth API-key configuration', () => { BETTER_AUTH_SECRET: 'test-secret-that-is-long-enough-for-tests', GOOGLE_CLIENT_ID: 'google-client', GOOGLE_CLIENT_SECRET: 'google-secret', + POLAR_ACCESS_TOKEN: 'polar-token', + POLAR_WEBHOOK_SECRET: 'polar-webhook-secret', + POLAR_BUILDER_PRODUCT_ID: 'builder-product', + POLAR_ENVIRONMENT: 'sandbox', } as unknown as Env, { waitUntil: vi.fn() }); expect(captured.deviceAuthorization).toMatchObject({ @@ -98,6 +133,35 @@ describe('Better Auth API-key configuration', () => { { id: 'bearer' }, { id: 'device-authorization' }, { id: 'magic-link' }, + { id: 'polar' }, ])); }); + + test('uses Polar for authenticated checkout, customer self-service, and signed lifecycle webhooks', () => { + createAuth({ + AUTH_BASE_URL: 'http://localhost:3000', + APP_ORIGIN: 'http://localhost:3000', + BETTER_AUTH_SECRET: 'test-secret-that-is-long-enough-for-tests', + GOOGLE_CLIENT_ID: 'google-client', + GOOGLE_CLIENT_SECRET: 'google-secret', + POLAR_ACCESS_TOKEN: 'polar-token', + POLAR_WEBHOOK_SECRET: 'polar-webhook-secret', + POLAR_BUILDER_PRODUCT_ID: 'builder-product', + POLAR_ENVIRONMENT: 'sandbox', + } as unknown as Env, { waitUntil: vi.fn() }); + + expect(captured.polar).toMatchObject({ createCustomerOnSignUp: false }); + expect(captured.checkout).toEqual({ + products: [{ productId: 'builder-product', slug: 'builder' }], + successUrl: 'http://localhost:3000/dashboard?section=settings&checkout=success', + returnUrl: 'http://localhost:3000/dashboard?section=settings&checkout=cancelled', + authenticatedUsersOnly: true, + }); + expect(captured.portal).toEqual({ returnUrl: 'http://localhost:3000/dashboard?section=settings' }); + expect(captured.webhooks).toMatchObject({ secret: 'polar-webhook-secret' }); + expect(captured.webhooks?.onOrderPaid).toEqual(expect.any(Function)); + expect(captured.webhooks?.onOrderRefunded).toEqual(expect.any(Function)); + expect(captured.webhooks?.onCustomerStateChanged).toEqual(expect.any(Function)); + expect(captured.webhooks?.onSubscriptionRevoked).toEqual(expect.any(Function)); + }); }); diff --git a/platform/test/billing.integration.test.ts b/platform/test/billing.integration.test.ts new file mode 100644 index 0000000..68c05ed --- /dev/null +++ b/platform/test/billing.integration.test.ts @@ -0,0 +1,168 @@ +/// + +import type { WebhookCustomerStateChangedPayload } from '@polar-sh/sdk/models/components/webhookcustomerstatechangedpayload'; +import type { WebhookOrderPaidPayload } from '@polar-sh/sdk/models/components/webhookorderpaidpayload'; +import type { WebhookOrderRefundedPayload } from '@polar-sh/sdk/models/components/webhookorderrefundedpayload'; +import { env as workerEnv } from 'cloudflare:workers'; +import { describe, expect, test } from 'vitest'; +import { + applyPaidOrder, + applyRefundedOrder, + syncCustomerState, + type PaymentWebhookEnv, +} from '../src/lib/billing'; + +const env = { + DB: workerEnv.DB, + POLAR_BUILDER_PRODUCT_ID: 'builder-product', + BUILDER_MONTHLY_CREDITS: '20000', + STARTER_ONBOARDING_CREDITS: '1000', +} satisfies PaymentWebhookEnv; + +describe('Polar payment queries on D1', () => { + test('tops up Builder credits and makes Polar retries idempotent', async () => { + const userId = 'payment-paid-user'; + await createUser(userId); + await addCredits(userId, 6_500, 'test:opening-balance'); + const payload = paidOrder(userId, 'paid-order'); + + await applyPaidOrder(env, payload); + + await expect(balance(userId)).resolves.toBe(20_000); + await expect(account(userId)).resolves.toMatchObject({ plan: 'builder', status: 'active' }); + await expect(operationCount(userId, 'polar:order:paid-order')).resolves.toBe(1); + + await addCredits(userId, -500, 'test:usage'); + await applyPaidOrder(env, payload); + + await expect(balance(userId)).resolves.toBe(19_500); + await expect(operationCount(userId, 'polar:order:paid-order')).resolves.toBe(1); + }); + + test('preserves balances already above the Builder allowance', async () => { + const userId = 'payment-carry-user'; + await createUser(userId); + await addCredits(userId, 25_000, 'test:opening-balance'); + + await applyPaidOrder(env, paidOrder(userId, 'carry-order')); + + await expect(balance(userId)).resolves.toBe(25_000); + }); + + test('refunds reset credits to Starter and lock out stale active state', async () => { + const userId = 'payment-refund-user'; + await createUser(userId); + await addCredits(userId, 3_500, 'test:opening-balance'); + + await applyRefundedOrder(env, refundedOrder(userId, 'refund-order')); + + await expect(balance(userId)).resolves.toBe(1_000); + await expect(account(userId)).resolves.toMatchObject({ plan: 'starter', status: 'refunded' }); + await expect(operationCount(userId, 'polar:refund:refund-order')).resolves.toBe(1); + + await addCredits(userId, -100, 'test:post-refund-usage'); + await applyRefundedOrder(env, refundedOrder(userId, 'refund-order')); + await expect(balance(userId)).resolves.toBe(900); + + await syncCustomerState(env, activeCustomerState(userId)); + await expect(account(userId)).resolves.toMatchObject({ plan: 'starter', status: 'refunded' }); + }); + + test('does not let an older webhook overwrite newer billing state', async () => { + const userId = 'payment-ordering-user'; + await createUser(userId); + + await applyRefundedOrder(env, refundedOrder(userId, 'ordering-order')); + await applyPaidOrder(env, paidOrder(userId, 'late-paid-order', new Date('2026-08-20T00:00:00.000Z'))); + + await expect(account(userId)).resolves.toMatchObject({ plan: 'starter', status: 'refunded' }); + await expect(balance(userId)).resolves.toBe(1_000); + }); +}); + +async function createUser(userId: string): Promise { + const timestamp = Date.now(); + await env.DB.prepare( + 'INSERT INTO user (id,name,email,emailVerified,createdAt,updatedAt) VALUES (?,?,?,?,?,?)' + ).bind(userId, userId, `${userId}@test.local`, 1, timestamp, timestamp).run(); +} + +async function addCredits(userId: string, credits: number, operationId: string): Promise { + await env.DB.prepare( + `INSERT INTO credit_ledger + (id,user_id,operation_id,entry_type,credits,metadata_json,created_at) + VALUES (?,?,?,'adjustment',?,'{}',?)` + ).bind(crypto.randomUUID(), userId, operationId, credits, Date.now()).run(); +} + +async function balance(userId: string): Promise { + const row = await env.DB.prepare( + 'SELECT COALESCE(SUM(credits),0) AS balance FROM credit_ledger WHERE user_id=?' + ).bind(userId).first<{ balance: number }>(); + return Number(row?.balance ?? 0); +} + +async function account(userId: string): Promise<{ plan: string; status: string } | null> { + return env.DB.prepare('SELECT plan,status FROM billing_accounts WHERE user_id=?') + .bind(userId).first<{ plan: string; status: string }>(); +} + +async function operationCount(userId: string, operationId: string): Promise { + const row = await env.DB.prepare( + 'SELECT COUNT(*) AS count FROM credit_ledger WHERE user_id=? AND operation_id=?' + ).bind(userId, operationId).first<{ count: number }>(); + return Number(row?.count ?? 0); +} + +function paidOrder( + userId: string, + id: string, + timestamp = new Date('2026-08-22T00:00:00.000Z'), +): WebhookOrderPaidPayload { + return { + type: 'order.paid', + timestamp, + data: { + id, + paid: true, + productId: 'builder-product', + customerId: `customer-${userId}`, + subscriptionId: `subscription-${userId}`, + billingReason: 'subscription_cycle', + customer: { externalId: userId }, + subscription: { + status: 'active', + cancelAtPeriodEnd: false, + currentPeriodStart: new Date('2026-08-01T00:00:00.000Z'), + currentPeriodEnd: new Date('2026-09-01T00:00:00.000Z'), + }, + }, + } as WebhookOrderPaidPayload; +} + +function refundedOrder(userId: string, id: string): WebhookOrderRefundedPayload { + return { + ...paidOrder(userId, id), + type: 'order.refunded', + timestamp: new Date('2026-08-23T00:00:00.000Z'), + } as WebhookOrderRefundedPayload; +} + +function activeCustomerState(userId: string): WebhookCustomerStateChangedPayload { + return { + type: 'customer.state_changed', + timestamp: new Date('2026-08-24T00:00:00.000Z'), + data: { + id: `customer-${userId}`, + externalId: userId, + activeSubscriptions: [{ + id: `subscription-${userId}`, + productId: 'builder-product', + status: 'active', + cancelAtPeriodEnd: false, + currentPeriodStart: new Date('2026-08-01T00:00:00.000Z'), + currentPeriodEnd: new Date('2026-09-01T00:00:00.000Z'), + }], + }, + } as WebhookCustomerStateChangedPayload; +} diff --git a/platform/test/credits.integration.test.ts b/platform/test/credits.integration.test.ts new file mode 100644 index 0000000..db2b4b9 --- /dev/null +++ b/platform/test/credits.integration.test.ts @@ -0,0 +1,116 @@ +/// + +import { env as workerEnv } from 'cloudflare:workers'; +import { describe, expect, test } from 'vitest'; +import { + creditBalance, + entitlements, + releaseCredits, + reserveCredits, + settleCredits, + type CreditEnv, +} from '../src/lib/entitlements'; + +const env = { + DB: workerEnv.DB, + STARTER_ONBOARDING_CREDITS: '1000', + BUILDER_MONTHLY_CREDITS: '20000', + STARTER_PROJECT_LIMIT: '3', + STARTER_MONITOR_LIMIT: '1', + STARTER_DAILY_IMPORTS: '10', + BUILDER_PROJECT_LIMIT: '100', + BUILDER_MONITOR_LIMIT: '50', + BUILDER_DAILY_IMPORTS: '200', +} satisfies CreditEnv; + +describe('credit queries on D1', () => { + test('grants Starter onboarding credits exactly once', async () => { + const userId = 'payment-starter-credit-user'; + await createUser(userId); + + await expect(creditBalance(env, userId)).resolves.toBe(1_000); + await expect(creditBalance(env, userId)).resolves.toBe(1_000); + await expect(operationCount(userId, 'onboarding:v1', 'grant')).resolves.toBe(1); + }); + + test('tops a pre-existing Starter balance up to the onboarding allowance', async () => { + const userId = 'payment-legacy-credit-user'; + await createUser(userId); + await addCredits(userId, 96, 'test:legacy-balance'); + + await expect(creditBalance(env, userId)).resolves.toBe(1_000); + }); + + test('does not grant Builder credits outside a paid-order webhook', async () => { + const userId = 'payment-builder-credit-user'; + await createUser(userId); + await addCredits(userId, 400, 'test:builder-balance'); + await setBuilderPlan(userId); + + await expect(entitlements(env, userId)).resolves.toMatchObject({ + plan: 'builder', + includedCredits: 20_000, + creditGrant: 'billing-cycle', + }); + await expect(creditBalance(env, userId)).resolves.toBe(400); + }); + + test('reserves, settles, and releases credits idempotently', async () => { + const userId = 'payment-credit-lifecycle-user'; + await createUser(userId); + + await reserveCredits(env, userId, 'operation:one', 200, { kind: 'test' }); + await reserveCredits(env, userId, 'operation:one', 200, { kind: 'test' }); + await expect(creditBalance(env, userId)).resolves.toBe(800); + + await settleCredits(env, userId, 'operation:one', 200, 120, 500); + await settleCredits(env, userId, 'operation:one', 200, 120, 500); + await expect(creditBalance(env, userId)).resolves.toBe(880); + + await reserveCredits(env, userId, 'operation:two', 100, { kind: 'test' }); + await releaseCredits(env, userId, 'operation:two', 100); + await releaseCredits(env, userId, 'operation:two', 100); + await expect(creditBalance(env, userId)).resolves.toBe(880); + }); + + test('rejects a reservation larger than the available balance', async () => { + const userId = 'payment-insufficient-credit-user'; + await createUser(userId); + + await expect(reserveCredits(env, userId, 'operation:too-large', 1_001, {})) + .rejects.toMatchObject({ status: 402, code: 'INSUFFICIENT_CREDITS' }); + await expect(creditBalance(env, userId)).resolves.toBe(1_000); + }); +}); + +async function createUser(userId: string): Promise { + const timestamp = Date.now(); + await env.DB.prepare( + 'INSERT INTO user (id,name,email,emailVerified,createdAt,updatedAt) VALUES (?,?,?,?,?,?)' + ).bind(userId, userId, `${userId}@test.local`, 1, timestamp, timestamp).run(); +} + +async function addCredits(userId: string, credits: number, operationId: string): Promise { + await env.DB.prepare( + `INSERT INTO credit_ledger + (id,user_id,operation_id,entry_type,credits,metadata_json,created_at) + VALUES (?,?,?,'adjustment',?,'{}',?)` + ).bind(crypto.randomUUID(), userId, operationId, credits, Date.now()).run(); +} + +async function setBuilderPlan(userId: string): Promise { + const timestamp = Date.now(); + await env.DB.prepare( + `INSERT INTO billing_accounts + (user_id,provider,plan,status,provider_updated_at,updated_at) + VALUES (?,'polar','builder','active',?,?)` + ).bind(userId, timestamp, timestamp).run(); +} + +async function operationCount(userId: string, operationId: string, entryType: string): Promise { + const row = await env.DB.prepare( + `SELECT COUNT(*) AS count FROM credit_ledger + WHERE user_id=? AND operation_id=? AND entry_type=?` + ).bind(userId, operationId, entryType).first<{ count: number }>(); + return Number(row?.count ?? 0); +} diff --git a/platform/test/entitlements.test.ts b/platform/test/entitlements.test.ts index 2fd4822..05a8585 100644 --- a/platform/test/entitlements.test.ts +++ b/platform/test/entitlements.test.ts @@ -4,7 +4,7 @@ class CreditDatabase { balance: number; readonly operations = new Set(); - constructor(balance = 0, readonly plan: 'free' | 'pro' = 'free') { + constructor(balance = 0, readonly plan: 'starter' | 'builder' = 'starter') { this.balance = balance; } @@ -12,7 +12,7 @@ class CreditDatabase { return { bind: (...values: unknown[]) => ({ first: async () => { - if (sql.includes('SELECT plan FROM plans')) return this.plan === 'pro' ? { plan: 'pro' } : null; + if (sql.includes('SELECT plan FROM billing_accounts')) return this.plan === 'builder' ? { plan: 'builder' } : null; if (sql.includes('SUM(credits)')) return { balance: this.balance }; return null; }, @@ -25,8 +25,6 @@ class CreditDatabase { if (operationId === 'onboarding:v1') { const allowance = Number(values[3]); this.balance += Math.max(0, allowance - this.balance); - } else { - this.balance += Number(values[3]); } return { meta: { changes: 1 } }; }, @@ -38,35 +36,35 @@ class CreditDatabase { function environment(database: CreditDatabase): Env { return { DB: database, - FREE_ONBOARDING_CREDITS: '1000', - PRO_MONTHLY_CREDITS: '20000', - FREE_PROJECT_LIMIT: '3', - FREE_MONITOR_LIMIT: '1', - FREE_DAILY_IMPORTS: '10', - PRO_PROJECT_LIMIT: '100', - PRO_MONITOR_LIMIT: '50', - PRO_DAILY_IMPORTS: '200', + STARTER_ONBOARDING_CREDITS: '1000', + BUILDER_MONTHLY_CREDITS: '20000', + STARTER_PROJECT_LIMIT: '3', + STARTER_MONITOR_LIMIT: '1', + STARTER_DAILY_IMPORTS: '10', + BUILDER_PROJECT_LIMIT: '100', + BUILDER_MONITOR_LIMIT: '50', + BUILDER_DAILY_IMPORTS: '200', } as unknown as Env; } describe('credit entitlements', () => { - test('describes the free credit allocation as a one-time onboarding grant', async () => { + test('describes the Starter credit allocation as a one-time onboarding grant', async () => { await expect(entitlements(environment(new CreditDatabase()), 'user-1')).resolves.toMatchObject({ - plan: 'free', + plan: 'starter', includedCredits: 1000, creditGrant: 'onboarding', }); }); test('describes the paid allocation as 20,000 recurring monthly credits', async () => { - await expect(entitlements(environment(new CreditDatabase(0, 'pro')), 'user-1')).resolves.toMatchObject({ - plan: 'pro', + await expect(entitlements(environment(new CreditDatabase(0, 'builder')), 'user-1')).resolves.toMatchObject({ + plan: 'builder', includedCredits: 20000, - creditGrant: 'monthly', + creditGrant: 'billing-cycle', }); }); - test('grants a new free account exactly 1,000 credits once', async () => { + test('grants a new Starter account exactly 1,000 credits once', async () => { const database = new CreditDatabase(); const env = environment(database); @@ -81,4 +79,11 @@ describe('credit entitlements', () => { await expect(creditBalance(environment(database), 'user-1')).resolves.toBe(1000); expect([...database.operations]).toEqual(['onboarding:v1']); }); + + test('does not grant Builder credits on a calendar timer', async () => { + const database = new CreditDatabase(400, 'builder'); + + await expect(creditBalance(environment(database), 'user-1')).resolves.toBe(400); + expect([...database.operations]).toEqual([]); + }); }); diff --git a/platform/test/openapi-docs.test.ts b/platform/test/openapi-docs.test.ts index a698079..384e77e 100644 --- a/platform/test/openapi-docs.test.ts +++ b/platform/test/openapi-docs.test.ts @@ -17,7 +17,7 @@ describe('documentation audience', () => { }); test('keeps callbacks, administration, and account deletion out of the consumer playground', () => { - expect(OPENAPI_OPERATION_AUDIENCE.handleStripeWebhook).toBe('callback'); + expect(OPENAPI_OPERATION_AUDIENCE.getBilling).toBe('first-party'); expect(OPENAPI_OPERATION_AUDIENCE.completeYouTubeOAuth).toBe('callback'); expect(OPENAPI_OPERATION_AUDIENCE.listAdminJobs).toBe('operator'); expect(OPENAPI_OPERATION_AUDIENCE.deleteAccount).toBe('first-party'); diff --git a/platform/test/openapi.test.ts b/platform/test/openapi.test.ts index fb4333c..c14029a 100644 --- a/platform/test/openapi.test.ts +++ b/platform/test/openapi.test.ts @@ -145,7 +145,7 @@ describe('OpenAPI and Scalar documentation', () => { expect(operation.responses['402']).toEqual({ $ref: '#/components/responses/InsufficientCredits' }); } expect(paths['/v1/projects']!.get.security).toContainEqual({ bearerApiKey: [] }); - expect(paths['/v1/billing/checkout']!.post.security).not.toContainEqual({ bearerApiKey: [] }); + expect(paths['/v1/billing']!.get.security).not.toContainEqual({ bearerApiKey: [] }); expect(paths['/v1/account']!.delete.security).not.toContainEqual({ bearerApiKey: [] }); expect(paths['/v1/account']!.delete.security).not.toContainEqual({ cliSession: [] }); expect(paths['/v1/account']!.get.security).toContainEqual({ cliSession: [] }); diff --git a/platform/vitest.auth.config.ts b/platform/vitest.auth.config.ts index 58b20af..adf5fc3 100644 --- a/platform/vitest.auth.config.ts +++ b/platform/vitest.auth.config.ts @@ -14,7 +14,11 @@ export default defineConfig({ })), ], test: { - include: ['test/auth-worker.integration.test.ts'], + include: [ + 'test/auth-worker.integration.test.ts', + 'test/billing.integration.test.ts', + 'test/credits.integration.test.ts', + ], setupFiles: ['./test/apply-auth-migrations.ts'], }, }); diff --git a/platform/vitest.config.ts b/platform/vitest.config.ts index 96fb1b2..33cefda 100644 --- a/platform/vitest.config.ts +++ b/platform/vitest.config.ts @@ -5,7 +5,11 @@ export default defineConfig({ environment: 'node', globals: true, include: ['test/**/*.test.ts'], - exclude: ['test/auth-worker.integration.test.ts'], + exclude: [ + 'test/auth-worker.integration.test.ts', + 'test/billing.integration.test.ts', + 'test/credits.integration.test.ts', + ], setupFiles: ['./test/setup.ts'], }, }); diff --git a/platform/worker-configuration.d.ts b/platform/worker-configuration.d.ts index ce0ba4a..2f03a39 100644 --- a/platform/worker-configuration.d.ts +++ b/platform/worker-configuration.d.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -// Generated by Wrangler by running `wrangler types` (hash: a0e555761723b6cffa9a7e5c8a5b5957) +// Generated by Wrangler by running `wrangler types` (hash: bcf01bfc26bdf536de13d0f2c312781b) // Runtime types generated with workerd@1.20260801.1 2026-08-08 nodejs_compat interface __BaseEnv_Env { YOUTUBE_CACHE: KVNamespace; @@ -20,14 +20,16 @@ interface __BaseEnv_Env { AI_GATEWAY_ID: "all-things-youtube"; PUBLIC_SEARCH_INSTANCE: "youtube-public"; ADMIN_EMAILS: ""; - FREE_ONBOARDING_CREDITS: "1000"; - PRO_MONTHLY_CREDITS: "20000"; - FREE_PROJECT_LIMIT: "3"; - FREE_MONITOR_LIMIT: "1"; - FREE_DAILY_IMPORTS: "10"; - PRO_PROJECT_LIMIT: "100"; - PRO_MONITOR_LIMIT: "50"; - PRO_DAILY_IMPORTS: "200"; + STARTER_ONBOARDING_CREDITS: "1000"; + BUILDER_MONTHLY_CREDITS: "20000"; + STARTER_PROJECT_LIMIT: "3"; + STARTER_MONITOR_LIMIT: "1"; + STARTER_DAILY_IMPORTS: "10"; + BUILDER_PROJECT_LIMIT: "100"; + BUILDER_MONITOR_LIMIT: "50"; + BUILDER_DAILY_IMPORTS: "200"; + POLAR_ENVIRONMENT: "production"; + POLAR_BUILDER_PRODUCT_ID: ""; LANDING_DEMO_RATE_LIMIT_MODE: "enforced"; YOUTUBE_PROCESSOR_INSTANCE_COUNT: "2"; YOUTUBE_PROCESSOR_VERSION: "v1"; @@ -40,9 +42,8 @@ interface __BaseEnv_Env { GOOGLE_CLIENT_SECRET: string; YOUTUBE_OAUTH_ENCRYPTION_KEY: string; TURNSTILE_SECRET: string; - STRIPE_SECRET_KEY: string; - STRIPE_WEBHOOK_SECRET: string; - STRIPE_PRO_PRICE_ID: string; + POLAR_ACCESS_TOKEN: string; + POLAR_WEBHOOK_SECRET: string; CAPTION_API_TOKEN: string; UPSTASH_REDIS_REST_URL: string; UPSTASH_REDIS_REST_TOKEN: string; @@ -64,7 +65,7 @@ type StringifyValues> = { [Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string; }; declare namespace NodeJS { - interface ProcessEnv extends StringifyValues> {} + interface ProcessEnv extends StringifyValues> {} } // Begin runtime types diff --git a/platform/wrangler.jsonc b/platform/wrangler.jsonc index 37795a1..46d0109 100644 --- a/platform/wrangler.jsonc +++ b/platform/wrangler.jsonc @@ -16,14 +16,16 @@ "AI_GATEWAY_ID": "all-things-youtube", "PUBLIC_SEARCH_INSTANCE": "youtube-public", "ADMIN_EMAILS": "", - "FREE_ONBOARDING_CREDITS": "1000", - "PRO_MONTHLY_CREDITS": "20000", - "FREE_PROJECT_LIMIT": "3", - "FREE_MONITOR_LIMIT": "1", - "FREE_DAILY_IMPORTS": "10", - "PRO_PROJECT_LIMIT": "100", - "PRO_MONITOR_LIMIT": "50", - "PRO_DAILY_IMPORTS": "200", + "STARTER_ONBOARDING_CREDITS": "1000", + "BUILDER_MONTHLY_CREDITS": "20000", + "STARTER_PROJECT_LIMIT": "3", + "STARTER_MONITOR_LIMIT": "1", + "STARTER_DAILY_IMPORTS": "10", + "BUILDER_PROJECT_LIMIT": "100", + "BUILDER_MONITOR_LIMIT": "50", + "BUILDER_DAILY_IMPORTS": "200", + "POLAR_ENVIRONMENT": "production", + "POLAR_BUILDER_PRODUCT_ID": "", "LANDING_DEMO_RATE_LIMIT_MODE": "enforced", "YOUTUBE_PROCESSOR_INSTANCE_COUNT": "2", "YOUTUBE_PROCESSOR_VERSION": "v1", diff --git a/reference/engineering/IMPLEMENTATION.md b/reference/engineering/IMPLEMENTATION.md index 5bf0a67..e8a3683 100644 --- a/reference/engineering/IMPLEMENTATION.md +++ b/reference/engineering/IMPLEMENTATION.md @@ -64,7 +64,9 @@ Important routes: | Jobs | `POST /v1/imports`, `GET /v1/jobs/:id` | | Exports | `POST /v1/projects/:id/exports`, `GET /v1/exports/:id/download` | | Automation | `/v1/monitors`, `/v1/notifications`, `/v1/notification-preferences` | -| Account | `/v1/oauth/youtube`, `/v1/billing/checkout`, `/v1/usage`, `DELETE /v1/account` | +| Account | `/v1/oauth/youtube`, `GET /v1/billing`, `/v1/usage`, `DELETE /v1/account` | + +Polar checkout, customer portal, and the signed `/api/auth/polar/webhooks` callback are mounted by the Better Auth Polar plugin. The application projects verified Polar events into `billing_accounts`, while `credit_ledger` remains authoritative for spendable credits. Wrangler applies the versioned SQL files in `platform/migrations`. A paid order tops the balance up to the Builder allowance using the Polar order ID as an idempotency key. A refunded order downgrades the account and adjusts its balance to the Starter default. Credit changes and their billing projection are submitted in one D1 batch, and stale payment events cannot change credits after a newer refund. Calendar time and checkout return URLs never grant credits. Long-running imports return `202` with a stable job ID. Reusing an idempotency key returns the existing job. Jobs expose `queued`, `running`, `partial`, `succeeded`, `failed`, or `cancelled`, plus progress, partial result, retry time, and permanent failure information. @@ -140,10 +142,10 @@ X-Demo-User: postman The `platform/wrangler.jsonc` file binds separate preview and production D1 databases and Workers KV namespaces. Wrangler development uses the preview IDs; deployment uses the production IDs. Before production deployment: 1. Enable Email Sending for the domain in `EMAIL_FROM` and update that address. -2. Set `APP_ORIGIN`, `AUTH_BASE_URL`, `ENVIRONMENT=production`, Stripe price ID, admin emails, and plan limits per environment. -3. Add secrets interactively: `BETTER_AUTH_SECRET`, Google client credentials, a base64 32-byte `YOUTUBE_OAUTH_ENCRYPTION_KEY`, `TURNSTILE_SECRET`, and Stripe credentials. If direct YouTube egress is unreliable, also run `wrangler secret put OUTBOUND_PROXY_URL` and enter the proxy URL interactively. +2. Set `APP_ORIGIN`, `AUTH_BASE_URL`, `ENVIRONMENT=production`, `POLAR_ENVIRONMENT`, `POLAR_BUILDER_PRODUCT_ID`, admin emails, and plan limits per environment. +3. Add secrets interactively: `BETTER_AUTH_SECRET`, Google client credentials, a base64 32-byte `YOUTUBE_OAUTH_ENCRYPTION_KEY`, `TURNSTILE_SECRET`, `POLAR_ACCESS_TOKEN`, and `POLAR_WEBHOOK_SECRET`. If direct YouTube egress is unreliable, also run `wrangler secret put OUTBOUND_PROXY_URL` and enter the proxy URL interactively. 4. Connect the platform to Cloudflare Builds and the web application to Vercel, using the repository settings in `reference/engineering/DEPLOYMENT.md`. -5. Apply D1 migrations remotely and configure Google/Stripe callback URLs. +5. Apply D1 migrations remotely. In Polar, create the monthly Builder product and a webhook endpoint targeting `/api/auth/polar/webhooks` with `order.paid`, `order.refunded`, `customer.state_changed`, and `subscription.revoked` enabled. Never commit `.dev.vars`. The web Worker does not receive provider secrets; it reaches the platform through `PLATFORM`. @@ -152,9 +154,9 @@ Never commit `.dev.vars`. The web Worker does not receive provider secrets; it r - Public YouTube responses are cached in Workers KV and a retained stale value is returned when an upstream YouTube section fails. - Private documents use one AI Search instance per user and project metadata filters; D1/R2 remain authoritative. - Public transcript imports grow the shared hybrid corpus. Channel and playlist workflows eagerly fan out recent videos, with lazy access still supported. -- Queue tasks and Stripe webhooks have deterministic replay records. Credit reservation is a single conditional D1 mutation, followed by settlement or release. +- Queue tasks and Polar payment events have deterministic replay records. Credit reservation is a single conditional D1 mutation, followed by settlement or release. - Prompt evidence is delimited as untrusted content; synthesis without aligned citations returns `INSUFFICIENT_EVIDENCE`. -- Account deletion revokes YouTube OAuth, removes private R2 objects and D1 rows, and queues private AI Search instance removal. +- Account deletion cancels and anonymizes the Polar customer, revokes YouTube OAuth, removes private R2 objects and D1 rows, and queues private AI Search instance removal. ## Verification diff --git a/web/app/_directions/craft-pricing.tsx b/web/app/_directions/craft-pricing.tsx index 0350815..3e6794a 100644 --- a/web/app/_directions/craft-pricing.tsx +++ b/web/app/_directions/craft-pricing.tsx @@ -43,7 +43,7 @@ const PLANS: PricingPlan[] = [ 'Standard support', ], cta: 'Start building', - href: '/dashboard', + href: '/dashboard?section=settings', recommended: true, }, { diff --git a/web/app/dashboard/WorkspaceClient.tsx b/web/app/dashboard/WorkspaceClient.tsx index 708fc59..a53c084 100644 --- a/web/app/dashboard/WorkspaceClient.tsx +++ b/web/app/dashboard/WorkspaceClient.tsx @@ -12,10 +12,12 @@ import { loadDashboardAccountData, pathWithoutEmailConsent, publishCreditBalance, + type DashboardBilling, type DashboardUsage, type DashboardNotification, type DashboardNotificationPreferences, } from '../../lib/dashboard-data'; +import { authClient } from '../../lib/auth-client'; import { DashboardSidebar, Icon, type DashboardSection } from './DashboardSidebar'; import { useDashboardSession } from './DashboardSessionProvider'; @@ -207,6 +209,7 @@ export default function WorkspaceClient({ initialSection = 'trends', emailConsen const [projectLoading, setProjectLoading] = useState(false); const [projectError, setProjectError] = useState(''); const [usage, setUsage] = useState(null); + const [billing, setBilling] = useState(null); const [monitorSavingId, setMonitorSavingId] = useState(); const operationController = useRef(null); const projectController = useRef(null); @@ -252,6 +255,7 @@ export default function WorkspaceClient({ initialSection = 'trends', emailConsen setProjects(data.projects); setMonitors(data.monitors); setUsage(data.usage); + setBilling(data.billing); setNotifications(data.notifications); setNotificationPreferences(data.notificationPreferences); }, [authenticated]); @@ -269,6 +273,7 @@ export default function WorkspaceClient({ initialSection = 'trends', emailConsen const updateCreditBalance = (event: Event) => { const balance = (event as CustomEvent).detail; setUsage((current) => current ? { ...current, creditBalance: balance } : current); + setBilling((current) => current ? { ...current, creditBalance: balance } : current); }; window.addEventListener(CREDIT_BALANCE_EVENT, updateCreditBalance); return () => window.removeEventListener(CREDIT_BALANCE_EVENT, updateCreditBalance); @@ -622,7 +627,7 @@ export default function WorkspaceClient({ initialSection = 'trends', emailConsen - + {showSignIn && setShowSignIn(false)} />} {showNewProject && setShowNewProject(false)} onCreate={(name) => void createProject(name)} />} @@ -658,11 +663,13 @@ function NotificationMenu({ notifications, enabled, onOpen, onMarkAll, onSetting ; } -function SettingsView({ email, emailConsent, accountDataReady, isDemo, preferences, onPreferencesChange }: { +function SettingsView({ email, emailConsent, accountDataReady, isDemo, billing, onBillingChange, preferences, onPreferencesChange }: { email?: string; emailConsent?: string; accountDataReady: boolean; isDemo: boolean; + billing: DashboardBilling | null; + onBillingChange: (billing: DashboardBilling) => void; preferences: DashboardNotificationPreferences; onPreferencesChange: (preferences: DashboardNotificationPreferences) => void; }) { @@ -673,9 +680,68 @@ function SettingsView({ email, emailConsent, accountDataReady, isDemo, preferenc const [preferenceMessage, setPreferenceMessage] = useState(''); const [confirmationState, setConfirmationState] = useState<'idle' | 'confirming' | 'success' | 'error'>('idle'); const [confirmationMessage, setConfirmationMessage] = useState(''); + const [billingAction, setBillingAction] = useState<'checkout' | 'portal'>(); + const [billingMessage, setBillingMessage] = useState(''); const attemptedEmailConsent = useRef(undefined); const confirmed = canDeleteAccount(confirmation); + const startCheckout = async () => { + if (billingAction || isDemo) return; + setBillingAction('checkout'); + setBillingMessage(''); + try { + const result = await authClient.checkout({ slug: 'builder' }); + if (result.error) throw new Error(result.error.message ?? 'Could not start checkout.'); + } catch (cause) { + setBillingMessage(cause instanceof Error ? cause.message : 'Could not start checkout.'); + setBillingAction(undefined); + } + }; + + const openBillingPortal = async () => { + if (billingAction || isDemo) return; + setBillingAction('portal'); + setBillingMessage(''); + try { + const result = await authClient.customer.portal(); + if (result.error) throw new Error(result.error.message ?? 'Could not open billing management.'); + } catch (cause) { + setBillingMessage(cause instanceof Error ? cause.message : 'Could not open billing management.'); + setBillingAction(undefined); + } + }; + + useEffect(() => { + const checkout = new URLSearchParams(window.location.search).get('checkout'); + if (checkout === 'cancelled') { + setBillingMessage('Checkout was cancelled. Your current plan has not changed.'); + return; + } + if (checkout !== 'success') return; + + let cancelled = false; + let attempts = 0; + setBillingMessage('Payment received. Confirming your Builder plan and credits...'); + const reconcile = async () => { + attempts += 1; + try { + const next = await api('/v1/billing', { cache: 'no-store' }); + if (cancelled) return; + onBillingChange(next); + if (next.plan === 'builder') { + setBillingMessage('Builder is active and your credit balance is ready.'); + return; + } + } catch { + // Polar may still be delivering the signed webhook. Retry briefly. + } + if (!cancelled && attempts < 8) window.setTimeout(() => void reconcile(), 1_500); + else if (!cancelled) setBillingMessage('Payment is still syncing. Refresh in a moment if Builder does not appear.'); + }; + void reconcile(); + return () => { cancelled = true; }; + }, [onBillingChange]); + const savePreference = async (key: 'inApp' | 'emailAlerts', value: boolean) => { const previous = preferences; const next = key === 'emailAlerts' && value @@ -751,8 +817,27 @@ function SettingsView({ email, emailConsent, accountDataReady, isDemo, preferenc return
-

Settings

Choose how monitor updates reach you and manage your account.

+

Settings

Manage billing, monitor updates, and your account.

+
+
+ Billing +

{billing?.plan === 'builder' ? 'Builder plan' : 'Starter plan'}

+

{billing?.plan === 'builder' + ? `${formatNumber(billing.creditBalance)} credits available from a ${formatNumber(billing.includedCredits)} credit monthly allowance.` + : 'Includes 1,000 onboarding credits. Upgrade to Builder for a 20,000 credit monthly allowance and higher workspace limits.'}

+ {billing?.plan === 'builder' && billing.currentPeriodEnd &&

{billing.cancelAtPeriodEnd + ? `Builder remains active until ${formatBillingDate(billing.currentPeriodEnd)}.` + : `Next renewal: ${formatBillingDate(billing.currentPeriodEnd)}.`}

} + {billingMessage &&

{billingMessage}

} +
+
+ {billing?.plan === 'builder' || billing?.canManageBilling + ? + : } + {isDemo && Sign in with a real account to test checkout.} +
+
Monitor updates @@ -1279,6 +1364,7 @@ function useDialogFocus(onClose: () => void) { function formatTime(ms:number){const total=Math.floor(ms/1000);return `${Math.floor(total/60)}:${String(total%60).padStart(2,'0')}`;} function formatNumber(value:unknown){const number=Number(value);return Number.isFinite(number)?Intl.NumberFormat('en',{notation:'compact'}).format(number):'—';} +function formatBillingDate(timestamp:number){return new Date(timestamp).toLocaleDateString([],{dateStyle:'medium'});} function formatDuration(seconds:number){const minutes=Math.round(seconds/60);return minutes >= 60 ? `${Math.floor(minutes/60)}h ${minutes%60}m` : `${minutes} minutes`;} function relativeNotificationTime(timestamp:number){ const elapsed = Math.max(0, Date.now() - timestamp); diff --git a/web/lib/auth-client.ts b/web/lib/auth-client.ts index a642eee..458ff80 100644 --- a/web/lib/auth-client.ts +++ b/web/lib/auth-client.ts @@ -1,8 +1,9 @@ import { apiKeyClient } from '@better-auth/api-key/client'; +import { polarClient } from '@polar-sh/better-auth/client'; import { createAuthClient } from 'better-auth/react'; import { deviceAuthorizationClient } from 'better-auth/client/plugins'; export const authClient = createAuthClient({ basePath: '/api/auth', - plugins: [apiKeyClient(), deviceAuthorizationClient()], + plugins: [apiKeyClient(), deviceAuthorizationClient(), polarClient()], }); diff --git a/web/lib/dashboard-data.test.ts b/web/lib/dashboard-data.test.ts index 0fce849..d234bd3 100644 --- a/web/lib/dashboard-data.test.ts +++ b/web/lib/dashboard-data.test.ts @@ -16,7 +16,8 @@ describe('dashboard account bootstrap', () => { paths.push(path); if (path === '/v1/projects') return { projects: [] }; if (path === '/v1/monitors') return { monitors: [] }; - if (path === '/v1/usage') return { plan: 'free', includedCredits: 1000, creditGrant: 'onboarding', creditBalance: 1000 }; + if (path === '/v1/usage') return { plan: 'starter', includedCredits: 1000, creditGrant: 'onboarding', creditBalance: 1000 }; + if (path === '/v1/billing') return { plan: 'starter', status: 'inactive', creditBalance: 1000, includedCredits: 1000, cancelAtPeriodEnd: false, currentPeriodStart: null, currentPeriodEnd: null, canManageBilling: false }; if (path === '/v1/notifications') return { notifications: [] }; if (path === '/v1/notification-preferences') return { inApp: true, emailAlerts: false, emailAlertsPending: false, emailDigest: 'off' }; throw new Error(`Unexpected request: ${path}`); @@ -26,12 +27,14 @@ describe('dashboard account bootstrap', () => { assert.deepEqual(data.projects, []); assert.deepEqual(data.monitors, []); assert.equal(data.usage?.creditBalance, 1000); + assert.equal(data.billing?.plan, 'starter'); assert.deepEqual(data.notifications, []); assert.equal(data.notificationPreferences.emailAlerts, false); assert.deepEqual(paths, [ '/v1/projects', '/v1/monitors', '/v1/usage', + '/v1/billing', '/v1/notifications', '/v1/notification-preferences', ]); diff --git a/web/lib/dashboard-data.ts b/web/lib/dashboard-data.ts index 0b239fa..f6313e4 100644 --- a/web/lib/dashboard-data.ts +++ b/web/lib/dashboard-data.ts @@ -1,10 +1,21 @@ export interface DashboardUsage { - plan: 'free' | 'pro'; + plan: 'starter' | 'builder'; includedCredits: number; - creditGrant: 'onboarding' | 'monthly'; + creditGrant: 'onboarding' | 'billing-cycle'; creditBalance: number; } +export interface DashboardBilling { + plan: 'starter' | 'builder'; + status: string; + creditBalance: number; + includedCredits: number; + cancelAtPeriodEnd: boolean; + currentPeriodStart: number | null; + currentPeriodEnd: number | null; + canManageBilling: boolean; +} + export interface DashboardProject { id: string; name: string; @@ -52,6 +63,7 @@ export interface DashboardAccountData { projects: DashboardProject[]; monitors: DashboardMonitor[]; usage: DashboardUsage | null; + billing: DashboardBilling | null; notifications: DashboardNotification[]; notificationPreferences: DashboardNotificationPreferences; } @@ -63,10 +75,11 @@ type DashboardPreferenceMutation = ( ) => Promise; export async function loadDashboardAccountData(request: DashboardRequest): Promise { - const [projectData, monitorData, usage, notificationData, notificationPreferences] = await Promise.all([ + const [projectData, monitorData, usage, billing, notificationData, notificationPreferences] = await Promise.all([ request('/v1/projects').catch(() => ({ projects: [] })) as Promise<{ projects: DashboardProject[] }>, request('/v1/monitors').catch(() => ({ monitors: [] })) as Promise<{ monitors: DashboardMonitor[] }>, request('/v1/usage').catch(() => null) as Promise, + request('/v1/billing').catch(() => null) as Promise, request('/v1/notifications').catch(() => ({ notifications: [] })) as Promise<{ notifications: DashboardNotification[] }>, request('/v1/notification-preferences').catch(() => DEFAULT_NOTIFICATION_PREFERENCES) as Promise, ]); @@ -75,6 +88,7 @@ export async function loadDashboardAccountData(request: DashboardRequest): Promi projects: projectData.projects, monitors: monitorData.monitors, usage, + billing, notifications: notificationData.notifications, notificationPreferences, }; diff --git a/web/package-lock.json b/web/package-lock.json index ee59449..d6d60da 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -10,13 +10,16 @@ "dependencies": { "@better-auth/api-key": "1.6.26", "@phosphor-icons/react": "^2.1.10", + "@polar-sh/better-auth": "1.8.4", + "@polar-sh/sdk": "0.47.1", "@vercel/analytics": "^2.0.1", "better-auth": "1.6.26", "better-call": "1.3.7", "geist": "^1.7.2", "next": "^16.3.0", "react": "^19.2.6", - "react-dom": "^19.2.6" + "react-dom": "^19.2.6", + "zod": "4.4.3" }, "devDependencies": { "@tailwindcss/postcss": "^4.3.3", @@ -61,6 +64,7 @@ "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.26.tgz", "integrity": "sha512-Ud4FqnjIJDvmeo+3bN+OsuVVAiuvFjNERbW7G8/65ictSxCox62gNgTOsJ4YXmbwXzBzyyekStzrupg2qNGEkA==", "license": "MIT", + "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.39.0", "@standard-schema/spec": "^1.1.0", @@ -179,6 +183,7 @@ "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.2.tgz", "integrity": "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==", "license": "MIT", + "peer": true, "dependencies": { "@noble/hashes": "^2.0.1" } @@ -199,7 +204,8 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.1.tgz", "integrity": "sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emnapi/runtime": { "version": "1.11.3", @@ -918,12 +924,83 @@ "react-dom": ">= 16.8" } }, + "node_modules/@polar-sh/better-auth": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@polar-sh/better-auth/-/better-auth-1.8.4.tgz", + "integrity": "sha512-BgWCcBQDRYwQn2NEYYzGSEfnrmBJHaDTvYBXGE2V3mmGPKspUDS8+p1LzbNY0Sw681LT8HB5w5Q81Ysc46CVSQ==", + "dependencies": { + "@polar-sh/checkout": "^0.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@polar-sh/sdk": "^0.47.0", + "better-auth": "^1.4.12", + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/@polar-sh/checkout": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@polar-sh/checkout/-/checkout-0.2.1.tgz", + "integrity": "sha512-AEKKw3o4ykApECA4bU6a2YC0+aQKTFUasca4ZgCDIjG8AHlu3SjW3Taxh2nfeYAczhah0m0axVF9AV8VfdYzfw==", + "license": "Apache-2.0", + "dependencies": { + "date-fns": "^4.1.0" + }, + "peerDependencies": { + "@stripe/react-stripe-js": "^3.6.0 || ^4.0.2", + "@stripe/stripe-js": "^7.1.0", + "react": "^18 || ^19" + } + }, + "node_modules/@polar-sh/sdk": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@polar-sh/sdk/-/sdk-0.47.1.tgz", + "integrity": "sha512-fkz7wPLbqfuDmY9LxuXpE2uP2TAV6J0q/YN5hJ4UBxpjbkB0hKM6c4R35N89t83dfzMlG6EOlqOn+Rd1T6XrJQ==", + "peer": true, + "dependencies": { + "standardwebhooks": "^1.0.0", + "zod": "^3.25.65 || ^4.0.0" + } + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "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==", "license": "MIT" }, + "node_modules/@stripe/react-stripe-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-4.0.2.tgz", + "integrity": "sha512-l2wau+8/LOlHl+Sz8wQ1oDuLJvyw51nQCsu6/ljT6smqzTszcMHifjAJoXlnMfcou3+jK/kQyVe04u/ufyTXgg==", + "license": "MIT", + "peer": true, + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@stripe/stripe-js": ">=1.44.1 <8.0.0", + "react": ">=16.8.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@stripe/stripe-js": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz", + "integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.16" + } + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -1156,27 +1233,6 @@ "node": ">=14.0.0" } }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "dev": true, @@ -1286,6 +1342,7 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1359,6 +1416,7 @@ "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.26.tgz", "integrity": "sha512-nhXWrDDj+EnZsHq1j0z1c6DowOMFZWZHe6LCaXbBfLIgHHZm6dyazBQcbRspM4spUIcUt250Mc1BFOSuP7eniQ==", "license": "MIT", + "peer": true, "dependencies": { "@better-auth/core": "1.6.26", "@better-auth/drizzle-adapter": "1.6.26", @@ -1488,6 +1546,7 @@ "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.7.tgz", "integrity": "sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w==", "license": "MIT", + "peer": true, "dependencies": { "@better-auth/utils": "^0.4.0", "@better-fetch/fetch": "^1.1.21", @@ -1536,6 +1595,16 @@ "dev": true, "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/defu": { "version": "6.1.7", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", @@ -1566,6 +1635,12 @@ "node": ">=10.13.0" } }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/geist": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/geist/-/geist-1.7.2.tgz", @@ -1597,15 +1672,23 @@ "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.8.tgz", "integrity": "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/panva" } }, + "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==", + "license": "MIT" + }, "node_modules/kysely": { "version": "0.29.4", "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.29.4.tgz", "integrity": "sha512-y5mVgQNkMbs1eK9Xyc0pmNdabN2wHhRYY/5r4W5HrUT1rYCEPeVNSj1RUJeSDKT3U0p+mXCvLgkrFuIafYI6BA==", "license": "MIT", + "peer": true, "engines": { "node": ">=22.0.0" } @@ -1871,6 +1954,18 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -1910,6 +2005,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": "^20.0.0 || >=22.0.0" } @@ -1919,6 +2015,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.3.0.tgz", "integrity": "sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "16.3.0", "@swc/helpers": "0.5.15", @@ -1995,6 +2092,15 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2030,11 +2136,23 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/react": { "version": "19.2.6", "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -2044,6 +2162,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -2051,6 +2170,12 @@ "react": "^19.2.6" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/rou3": { "version": "0.7.12", "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.7.12.tgz", @@ -2141,6 +2266,16 @@ "node": ">=0.10.0" } }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -2217,6 +2352,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/web/package.json b/web/package.json index 629410d..04d4cb7 100644 --- a/web/package.json +++ b/web/package.json @@ -13,13 +13,16 @@ "dependencies": { "@better-auth/api-key": "1.6.26", "@phosphor-icons/react": "^2.1.10", + "@polar-sh/better-auth": "1.8.4", + "@polar-sh/sdk": "0.47.1", "@vercel/analytics": "^2.0.1", "better-auth": "1.6.26", "better-call": "1.3.7", "geist": "^1.7.2", "next": "^16.3.0", "react": "^19.2.6", - "react-dom": "^19.2.6" + "react-dom": "^19.2.6", + "zod": "4.4.3" }, "devDependencies": { "@tailwindcss/postcss": "^4.3.3", From 643e581532c4df97b017dcef5b0d489496f57399 Mon Sep 17 00:00:00 2001 From: Himanshu Gupta Date: Thu, 20 Aug 2026 21:10:59 +0530 Subject: [PATCH 2/2] fix(web): repair npm lockfile --- web/package-lock.json | 46 +++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index d6d60da..b5c5023 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -64,7 +64,6 @@ "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.26.tgz", "integrity": "sha512-Ud4FqnjIJDvmeo+3bN+OsuVVAiuvFjNERbW7G8/65ictSxCox62gNgTOsJ4YXmbwXzBzyyekStzrupg2qNGEkA==", "license": "MIT", - "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.39.0", "@standard-schema/spec": "^1.1.0", @@ -183,7 +182,6 @@ "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.2.tgz", "integrity": "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "^2.0.1" } @@ -204,8 +202,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.3.1.tgz", "integrity": "sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@emnapi/runtime": { "version": "1.11.3", @@ -958,7 +955,6 @@ "version": "0.47.1", "resolved": "https://registry.npmjs.org/@polar-sh/sdk/-/sdk-0.47.1.tgz", "integrity": "sha512-fkz7wPLbqfuDmY9LxuXpE2uP2TAV6J0q/YN5hJ4UBxpjbkB0hKM6c4R35N89t83dfzMlG6EOlqOn+Rd1T6XrJQ==", - "peer": true, "dependencies": { "standardwebhooks": "^1.0.0", "zod": "^3.25.65 || ^4.0.0" @@ -1233,6 +1229,27 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "dev": true, @@ -1342,7 +1359,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1416,7 +1432,6 @@ "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.26.tgz", "integrity": "sha512-nhXWrDDj+EnZsHq1j0z1c6DowOMFZWZHe6LCaXbBfLIgHHZm6dyazBQcbRspM4spUIcUt250Mc1BFOSuP7eniQ==", "license": "MIT", - "peer": true, "dependencies": { "@better-auth/core": "1.6.26", "@better-auth/drizzle-adapter": "1.6.26", @@ -1546,7 +1561,6 @@ "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.7.tgz", "integrity": "sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w==", "license": "MIT", - "peer": true, "dependencies": { "@better-auth/utils": "^0.4.0", "@better-fetch/fetch": "^1.1.21", @@ -1672,7 +1686,6 @@ "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.8.tgz", "integrity": "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/panva" } @@ -1681,14 +1694,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/kysely": { "version": "0.29.4", "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.29.4.tgz", "integrity": "sha512-y5mVgQNkMbs1eK9Xyc0pmNdabN2wHhRYY/5r4W5HrUT1rYCEPeVNSj1RUJeSDKT3U0p+mXCvLgkrFuIafYI6BA==", "license": "MIT", - "peer": true, "engines": { "node": ">=22.0.0" } @@ -1959,6 +1972,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", + "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -2005,7 +2019,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": "^20.0.0 || >=22.0.0" } @@ -2015,7 +2028,6 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.3.0.tgz", "integrity": "sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==", "license": "MIT", - "peer": true, "dependencies": { "@next/env": "16.3.0", "@swc/helpers": "0.5.15", @@ -2097,6 +2109,7 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -2141,6 +2154,7 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -2152,7 +2166,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -2162,7 +2175,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -2174,7 +2186,8 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/rou3": { "version": "0.7.12", @@ -2352,7 +2365,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }