diff --git a/apps/sim/lib/auth.ts b/apps/sim/lib/auth.ts index 1978cd484..c1599670d 100644 --- a/apps/sim/lib/auth.ts +++ b/apps/sim/lib/auth.ts @@ -48,7 +48,7 @@ const validStripeKey = env.STRIPE_SECRET_KEY let stripeClient = null if (validStripeKey) { stripeClient = new Stripe(env.STRIPE_SECRET_KEY || '', { - apiVersion: '2025-02-24.acacia', + apiVersion: '2025-08-27.basil', }) } @@ -592,7 +592,6 @@ export const auth = betterAuth({ id: uniqueId, name: 'Wealthbox User', email: `${uniqueId.replace(/[^a-zA-Z0-9]/g, '')}@wealthbox.user`, - image: null, emailVerified: false, createdAt: now, updatedAt: now, @@ -650,7 +649,6 @@ export const auth = betterAuth({ id: uniqueId, name: 'Supabase User', email: `${uniqueId.replace(/[^a-zA-Z0-9]/g, '')}@supabase.user`, - image: null, emailVerified: false, createdAt: now, updatedAt: now, @@ -760,7 +758,7 @@ export const auth = betterAuth({ id: profile.account_id, name: profile.name || profile.display_name || 'Confluence User', email: profile.email || `${profile.account_id}@atlassian.com`, - image: profile.picture || null, + image: profile.picture || undefined, emailVerified: true, // Assume verified since it's an Atlassian account createdAt: now, updatedAt: now, @@ -811,7 +809,7 @@ export const auth = betterAuth({ email: profile.email || `${profile.id}@discord.user`, image: profile.avatar ? `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.png` - : null, + : undefined, emailVerified: profile.verified || false, createdAt: now, updatedAt: now, @@ -881,7 +879,7 @@ export const auth = betterAuth({ id: profile.account_id, name: profile.name || profile.display_name || 'Jira User', email: profile.email || `${profile.account_id}@atlassian.com`, - image: profile.picture || null, + image: profile.picture || undefined, emailVerified: true, // Assume verified since it's an Atlassian account createdAt: now, updatedAt: now, @@ -949,7 +947,6 @@ export const auth = betterAuth({ id: profile.bot?.owner?.user?.id || profile.id, name: profile.name || profile.bot?.owner?.user?.name || 'Notion User', email: profile.person?.email || `${profile.id}@notion.user`, - image: null, // Notion API doesn't provide profile images emailVerified: !!profile.person?.email, createdAt: now, updatedAt: now, @@ -1000,7 +997,7 @@ export const auth = betterAuth({ id: data.id, name: data.name || 'Reddit User', email: `${data.name}@reddit.user`, // Reddit doesn't provide email in identity scope - image: data.icon_img || null, + image: data.icon_img || undefined, emailVerified: false, createdAt: now, updatedAt: now, @@ -1075,7 +1072,7 @@ export const auth = betterAuth({ emailVerified: true, createdAt: new Date(), updatedAt: new Date(), - image: viewer.avatarUrl || null, + image: viewer.avatarUrl || undefined, } } catch (error) { logger.error('Error in getUserInfo:', error) @@ -1138,7 +1135,6 @@ export const auth = betterAuth({ id: uniqueId, name: 'Slack Bot', email: `${uniqueId.replace(/[^a-zA-Z0-9]/g, '')}@slack.bot`, - image: null, emailVerified: false, createdAt: now, updatedAt: now, diff --git a/apps/sim/lib/billing/core/usage.ts b/apps/sim/lib/billing/core/usage.ts index 738fd5a74..b017dfdc4 100644 --- a/apps/sim/lib/billing/core/usage.ts +++ b/apps/sim/lib/billing/core/usage.ts @@ -50,13 +50,12 @@ export async function getUserUsageData(userId: string): Promise { ]) if (userStatsData.length === 0) { + logger.error('User stats not found for userId', { userId }) throw new Error(`User stats not found for userId: ${userId}`) } const stats = userStatsData[0] - const currentUsage = Number.parseFloat( - stats.currentPeriodCost?.toString() ?? stats.totalCost.toString() - ) + const currentUsage = Number.parseFloat(stats.currentPeriodCost?.toString() ?? '0') // Determine usage limit based on plan type let limit: number diff --git a/apps/sim/lib/billing/stripe-client.ts b/apps/sim/lib/billing/stripe-client.ts index 93bcc6485..7a93a0bf4 100644 --- a/apps/sim/lib/billing/stripe-client.ts +++ b/apps/sim/lib/billing/stripe-client.ts @@ -38,7 +38,7 @@ const createStripeClientSingleton = () => { isInitializing = true stripeClient = new Stripe(env.STRIPE_SECRET_KEY || '', { - apiVersion: '2025-02-24.acacia', + apiVersion: '2025-08-27.basil', }) logger.info('Stripe client initialized successfully') diff --git a/apps/sim/lib/billing/webhooks/enterprise.ts b/apps/sim/lib/billing/webhooks/enterprise.ts index 18191e785..44b256957 100644 --- a/apps/sim/lib/billing/webhooks/enterprise.ts +++ b/apps/sim/lib/billing/webhooks/enterprise.ts @@ -98,6 +98,9 @@ export async function handleManualEnterpriseSubscription(event: Stripe.Event) { throw new Error('Enterprise subscription must include valid monthlyPrice in metadata') } + // Get the first subscription item which contains the period information + const referenceItem = stripeSubscription.items?.data?.[0] + const subscriptionRow = { id: crypto.randomUUID(), plan: 'enterprise', @@ -105,11 +108,11 @@ export async function handleManualEnterpriseSubscription(event: Stripe.Event) { stripeCustomerId, stripeSubscriptionId: stripeSubscription.id, status: stripeSubscription.status || null, - periodStart: stripeSubscription.current_period_start - ? new Date(stripeSubscription.current_period_start * 1000) + periodStart: referenceItem?.current_period_start + ? new Date(referenceItem.current_period_start * 1000) : null, - periodEnd: stripeSubscription.current_period_end - ? new Date(stripeSubscription.current_period_end * 1000) + periodEnd: referenceItem?.current_period_end + ? new Date(referenceItem.current_period_end * 1000) : null, cancelAtPeriodEnd: stripeSubscription.cancel_at_period_end ?? null, seats, diff --git a/apps/sim/lib/billing/webhooks/invoices.ts b/apps/sim/lib/billing/webhooks/invoices.ts index 2557e2d10..3d51cda60 100644 --- a/apps/sim/lib/billing/webhooks/invoices.ts +++ b/apps/sim/lib/billing/webhooks/invoices.ts @@ -53,8 +53,14 @@ export async function handleInvoicePaymentSucceeded(event: Stripe.Event) { try { const invoice = event.data.object as Stripe.Invoice - if (!invoice.subscription) return - const stripeSubscriptionId = String(invoice.subscription) + const subscription = invoice.parent?.subscription_details?.subscription + const stripeSubscriptionId = typeof subscription === 'string' ? subscription : subscription?.id + if (!stripeSubscriptionId) { + logger.info('No subscription found on invoice; skipping payment succeeded handler', { + invoiceId: invoice.id, + }) + return + } const records = await db .select() .from(subscriptionTable) @@ -156,7 +162,9 @@ export async function handleInvoicePaymentFailed(event: Stripe.Event) { attemptCount, }) // Block all users under this customer (org members or individual) - const stripeSubscriptionId = String(invoice.subscription || '') + // Overage invoices are manual invoices without parent.subscription_details + // We store the subscription ID in metadata when creating them + const stripeSubscriptionId = invoice.metadata?.subscriptionId as string | undefined if (stripeSubscriptionId) { const records = await db .select() @@ -203,10 +211,16 @@ export async function handleInvoiceFinalized(event: Stripe.Event) { try { const invoice = event.data.object as Stripe.Invoice // Only run for subscription renewal invoices (cycle boundary) - if (!invoice.subscription) return + const subscription = invoice.parent?.subscription_details?.subscription + const stripeSubscriptionId = typeof subscription === 'string' ? subscription : subscription?.id + if (!stripeSubscriptionId) { + logger.info('No subscription found on invoice; skipping finalized handler', { + invoiceId: invoice.id, + }) + return + } if (invoice.billing_reason && invoice.billing_reason !== 'subscription_cycle') return - const stripeSubscriptionId = String(invoice.subscription) const records = await db .select() .from(subscriptionTable) @@ -216,11 +230,9 @@ export async function handleInvoiceFinalized(event: Stripe.Event) { if (records.length === 0) return const sub = records[0] - // Always reset usage at cycle end for all plans - await resetUsageForSubscription({ plan: sub.plan, referenceId: sub.referenceId }) - - // Enterprise plans have no overages - skip overage invoice creation + // Enterprise plans have no overages - reset usage and exit if (sub.plan === 'enterprise') { + await resetUsageForSubscription({ plan: sub.plan, referenceId: sub.referenceId }) return } @@ -229,7 +241,7 @@ export async function handleInvoiceFinalized(event: Stripe.Event) { invoice.lines?.data?.[0]?.period?.end || invoice.period_end || Math.floor(Date.now() / 1000) const billingPeriod = new Date(periodEnd * 1000).toISOString().slice(0, 7) - // Compute overage (only for team and pro plans) + // Compute overage (only for team and pro plans), before resetting usage let totalOverage = 0 if (sub.plan === 'team') { const members = await db @@ -254,88 +266,101 @@ export async function handleInvoiceFinalized(event: Stripe.Event) { totalOverage = Math.max(0, usage.currentUsage - basePrice) } - if (totalOverage <= 0) return + if (totalOverage > 0) { + const customerId = String(invoice.customer) + const cents = Math.round(totalOverage * 100) + const itemIdemKey = `overage-item:${customerId}:${stripeSubscriptionId}:${billingPeriod}` + const invoiceIdemKey = `overage-invoice:${customerId}:${stripeSubscriptionId}:${billingPeriod}` - const customerId = String(invoice.customer) - const cents = Math.round(totalOverage * 100) - const itemIdemKey = `overage-item:${customerId}:${stripeSubscriptionId}:${billingPeriod}` - const invoiceIdemKey = `overage-invoice:${customerId}:${stripeSubscriptionId}:${billingPeriod}` + // Inherit billing settings from the Stripe subscription/customer for autopay + const getPaymentMethodId = ( + pm: string | Stripe.PaymentMethod | null | undefined + ): string | undefined => (typeof pm === 'string' ? pm : pm?.id) - // Inherit billing settings from the Stripe subscription/customer for autopay - const getPaymentMethodId = ( - pm: string | Stripe.PaymentMethod | null | undefined - ): string | undefined => (typeof pm === 'string' ? pm : pm?.id) - - let collectionMethod: 'charge_automatically' | 'send_invoice' = 'charge_automatically' - let defaultPaymentMethod: string | undefined - try { - const stripeSub = await stripe.subscriptions.retrieve(stripeSubscriptionId) - if (stripeSub.collection_method === 'send_invoice') { - collectionMethod = 'send_invoice' + let collectionMethod: 'charge_automatically' | 'send_invoice' = 'charge_automatically' + let defaultPaymentMethod: string | undefined + try { + const stripeSub = await stripe.subscriptions.retrieve(stripeSubscriptionId) + if (stripeSub.collection_method === 'send_invoice') { + collectionMethod = 'send_invoice' + } + const subDpm = getPaymentMethodId(stripeSub.default_payment_method) + if (subDpm) { + defaultPaymentMethod = subDpm + } else if (collectionMethod === 'charge_automatically') { + const custObj = await stripe.customers.retrieve(customerId) + if (custObj && !('deleted' in custObj)) { + const cust = custObj as Stripe.Customer + const custDpm = getPaymentMethodId(cust.invoice_settings?.default_payment_method) + if (custDpm) defaultPaymentMethod = custDpm + } + } + } catch (e) { + logger.error('Failed to retrieve subscription or customer', { error: e }) } - const subDpm = getPaymentMethodId(stripeSub.default_payment_method) - if (subDpm) { - defaultPaymentMethod = subDpm - } else if (collectionMethod === 'charge_automatically') { - const custObj = await stripe.customers.retrieve(customerId) - if (custObj && !('deleted' in custObj)) { - const cust = custObj as Stripe.Customer - const custDpm = getPaymentMethodId(cust.invoice_settings?.default_payment_method) - if (custDpm) defaultPaymentMethod = custDpm + + // Create a draft invoice first so we can attach the item directly + const overageInvoice = await stripe.invoices.create( + { + customer: customerId, + collection_method: collectionMethod, + auto_advance: false, + ...(defaultPaymentMethod ? { default_payment_method: defaultPaymentMethod } : {}), + metadata: { + type: 'overage_billing', + billingPeriod, + subscriptionId: stripeSubscriptionId, + }, + }, + { idempotencyKey: invoiceIdemKey } + ) + + // Attach the item to this invoice + await stripe.invoiceItems.create( + { + customer: customerId, + invoice: overageInvoice.id, + amount: cents, + currency: 'usd', + description: `Usage Based Overage – ${billingPeriod}`, + metadata: { + type: 'overage_billing', + billingPeriod, + subscriptionId: stripeSubscriptionId, + }, + }, + { idempotencyKey: itemIdemKey } + ) + + // Finalize to trigger autopay (if charge_automatically and a PM is present) + const draftId = overageInvoice.id + if (typeof draftId !== 'string' || draftId.length === 0) { + logger.error('Stripe created overage invoice without id; aborting finalize') + } else { + const finalized = await stripe.invoices.finalizeInvoice(draftId) + // Some manual invoices may remain open after finalize; ensure we pay immediately when possible + if (collectionMethod === 'charge_automatically' && finalized.status === 'open') { + try { + const payId = finalized.id + if (typeof payId !== 'string' || payId.length === 0) { + logger.error('Finalized invoice missing id') + throw new Error('Finalized invoice missing id') + } + await stripe.invoices.pay(payId, { + payment_method: defaultPaymentMethod, + }) + } catch (payError) { + logger.error('Failed to auto-pay overage invoice', { + error: payError, + invoiceId: finalized.id, + }) + } } } - } catch (e) { - logger.error('Failed to retrieve subscription or customer', { error: e }) } - // Create a draft invoice first so we can attach the item directly - const overageInvoice = await stripe.invoices.create( - { - customer: customerId, - collection_method: collectionMethod, - auto_advance: false, - ...(defaultPaymentMethod ? { default_payment_method: defaultPaymentMethod } : {}), - metadata: { - type: 'overage_billing', - billingPeriod, - subscriptionId: stripeSubscriptionId, - }, - }, - { idempotencyKey: invoiceIdemKey } - ) - - // Attach the item to this invoice - await stripe.invoiceItems.create( - { - customer: customerId, - invoice: overageInvoice.id, - amount: cents, - currency: 'usd', - description: `Usage Based Overage – ${billingPeriod}`, - metadata: { - type: 'overage_billing', - billingPeriod, - subscriptionId: stripeSubscriptionId, - }, - }, - { idempotencyKey: itemIdemKey } - ) - - // Finalize to trigger autopay (if charge_automatically and a PM is present) - const finalized = await stripe.invoices.finalizeInvoice(overageInvoice.id) - // Some manual invoices may remain open after finalize; ensure we pay immediately when possible - if (collectionMethod === 'charge_automatically' && finalized.status === 'open') { - try { - await stripe.invoices.pay(finalized.id, { - payment_method: defaultPaymentMethod, - }) - } catch (payError) { - logger.error('Failed to auto-pay overage invoice', { - error: payError, - invoiceId: finalized.id, - }) - } - } + // Finally, reset usage for this subscription after overage handling + await resetUsageForSubscription({ plan: sub.plan, referenceId: sub.referenceId }) } catch (error) { logger.error('Failed to handle invoice finalized', { error }) throw error diff --git a/apps/sim/package.json b/apps/sim/package.json index daa83498d..50410d5d9 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -26,17 +26,17 @@ "test:billing:suite": "bun run scripts/test-billing-suite.ts" }, "dependencies": { - "@e2b/code-interpreter": "^2.0.0", "@anthropic-ai/sdk": "^0.39.0", "@aws-sdk/client-s3": "^3.779.0", "@aws-sdk/s3-request-presigner": "^3.779.0", "@azure/communication-email": "1.0.0", "@azure/storage-blob": "12.27.0", - "@better-auth/stripe": "^1.2.9", + "@better-auth/stripe": "https://pkg.pr.new/better-auth/better-auth/@better-auth/stripe@4683", "@browserbasehq/stagehand": "^2.0.0", "@cerebras/cerebras_cloud_sdk": "^1.23.0", "@chatscope/chat-ui-kit-react": "2.1.1", "@chatscope/chat-ui-kit-styles": "1.4.0", + "@e2b/code-interpreter": "^2.0.0", "@hookform/resolvers": "^4.1.3", "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-collector": "^0.25.0", @@ -75,7 +75,7 @@ "@vercel/og": "^0.6.5", "@vercel/speed-insights": "^1.2.0", "ai": "^4.3.2", - "better-auth": "^1.2.9", + "better-auth": "1.3.10", "browser-image-compression": "^2.0.2", "cheerio": "1.1.2", "class-variance-authority": "^0.7.1", @@ -127,7 +127,7 @@ "rtf-stream-parser": "3.8.0", "sharp": "0.34.3", "socket.io": "^4.8.1", - "stripe": "^17.7.0", + "stripe": "18.5.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "three": "0.177.0", diff --git a/bun.lock b/bun.lock index c93bd57a8..6de6da560 100644 --- a/bun.lock +++ b/bun.lock @@ -62,7 +62,7 @@ "@aws-sdk/s3-request-presigner": "^3.779.0", "@azure/communication-email": "1.0.0", "@azure/storage-blob": "12.27.0", - "@better-auth/stripe": "^1.2.9", + "@better-auth/stripe": "https://pkg.pr.new/better-auth/better-auth/@better-auth/stripe@4683", "@browserbasehq/stagehand": "^2.0.0", "@cerebras/cerebras_cloud_sdk": "^1.23.0", "@chatscope/chat-ui-kit-react": "2.1.1", @@ -106,7 +106,7 @@ "@vercel/og": "^0.6.5", "@vercel/speed-insights": "^1.2.0", "ai": "^4.3.2", - "better-auth": "^1.2.9", + "better-auth": "1.3.10", "browser-image-compression": "^2.0.2", "cheerio": "1.1.2", "class-variance-authority": "^0.7.1", @@ -123,6 +123,7 @@ "geist": "1.4.2", "groq-sdk": "^0.15.0", "html-to-text": "^9.0.5", + "@better-auth/stripe": "https://pkg.pr.new/better-auth/better-auth/@better-auth/stripe@4683", "iconv-lite": "0.7.0", "input-otp": "^1.4.2", "ioredis": "^5.6.0", @@ -158,7 +159,7 @@ "rtf-stream-parser": "3.8.0", "sharp": "0.34.3", "socket.io": "^4.8.1", - "stripe": "^17.7.0", + "stripe": "18.5.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "three": "0.177.0", @@ -439,9 +440,9 @@ "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="], - "@better-auth/stripe": ["@better-auth/stripe@1.3.7", "", { "dependencies": { "better-auth": "^1.3.7" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-hmcWJu9RB1IOf+Mb8izQyLOAkRFKes8O0j/VoIFwLR0l2zWTknXKzkLUjadFPeKXHtV3i2n2++prjuVev6F6zw=="], + "@better-auth/stripe": ["@better-auth/stripe@https://pkg.pr.new/better-auth/better-auth/@better-auth/stripe@4683", { "dependencies": { "zod": "^4.1.5" }, "peerDependencies": { "better-auth": "1.3.10", "stripe": "^18" } }], - "@better-auth/utils": ["@better-auth/utils@0.2.6", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-3y/vaL5Ox33dBwgJ6ub3OPkVqr6B5xL2kgxNHG8eHZuryLyG/4JSPGqjbdRSgjuy9kALUZYDFl+ORIAxlWMSuA=="], + "@better-auth/utils": ["@better-auth/utils@0.3.0", "", {}, "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw=="], "@better-fetch/fetch": ["@better-fetch/fetch@1.1.18", "", {}, "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="], @@ -717,9 +718,9 @@ "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.4.1", "", { "os": "win32", "cpu": "x64" }, "sha512-y+wTBxelk2xiNofmDOVU7O5WxTHcvOoL3srOM0kxTzKDjQ57kPU0tpnPJ/BWrRnsOwXEv0+3QSbGR7hY4n9LkQ=="], - "@noble/ciphers": ["@noble/ciphers@0.6.0", "", {}, "sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ=="], + "@noble/ciphers": ["@noble/ciphers@2.0.0", "", {}, "sha512-j/l6jpnpaIBM87cAYPJzi/6TgqmBv9spkqPyCXvRYsu5uxqh6tPJZDnD85yo8VWqzTuTQPgfv7NgT63u7kbwAQ=="], - "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "@noble/hashes": ["@noble/hashes@2.0.0", "", {}, "sha512-h8VUBlE8R42+XIDO229cgisD287im3kdY6nbNZJFjc6ZvKIXPYXe6Vc/t+kyjFdMFyt5JpapzTsEg8n63w5/lw=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -1633,9 +1634,9 @@ "bcryptjs": ["bcryptjs@3.0.2", "", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog=="], - "better-auth": ["better-auth@1.3.7", "", { "dependencies": { "@better-auth/utils": "0.2.6", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^0.6.0", "@noble/hashes": "^1.8.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "^1.0.13", "defu": "^6.1.4", "jose": "^5.10.0", "kysely": "^0.28.5", "nanostores": "^0.11.4" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-/1fEyx2SGgJQM5ujozDCh9eJksnVkNU/J7Fk/tG5Y390l8nKbrPvqiFlCjlMM+scR+UABJbQzA6An7HT50LHyQ=="], + "better-auth": ["better-auth@1.3.10", "", { "dependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "1.0.19", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.1.5" }, "peerDependencies": { "@lynx-js/react": "*", "@sveltejs/kit": "^2.0.0", "next": "^14.0.0 || ^15.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", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@sveltejs/kit", "next", "react", "react-dom", "solid-js", "svelte", "vue"] }, "sha512-cEdvbqJ2TlTXUSktHKs8V3rHdFYkEG7QmQZpLXGjXZX6F0nYbTk2QPsWXNhxbinFAlE2ca4virzuDsmsQlLIVw=="], - "better-call": ["better-call@1.0.16", "", { "dependencies": { "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-42dgJ1rOtc0anOoxjXPOWuel/Z/4aeO7EJ2SiXNwvlkySSgjXhNjAjTMWa8DL1nt6EXS3jl3VKC3mPsU/lUgVA=="], + "better-call": ["better-call@1.0.19", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw=="], "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], @@ -2575,7 +2576,7 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "nanostores": ["nanostores@0.11.4", "", {}, "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ=="], + "nanostores": ["nanostores@1.0.1", "", {}, "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw=="], "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], @@ -3057,7 +3058,7 @@ "strip-literal": ["strip-literal@3.0.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA=="], - "stripe": ["stripe@17.7.0", "", { "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" } }, "sha512-aT2BU9KkizY9SATf14WhhYVv2uOapBWX0OFWF4xvcj1mPaNotlSc2CsxpS4DS46ZueSppmCF5BX1sNYBtwBvfw=="], + "stripe": ["stripe@18.5.0", "", { "dependencies": { "qs": "^6.11.0" }, "peerDependencies": { "@types/node": ">=12.x.x" }, "optionalPeers": ["@types/node"] }, "sha512-Hp+wFiEQtCB0LlNgcFh5uVyKznpDjzyUZ+CNVEf+I3fhlYvh7rZruIg+jOwzJRCpy0ZTPMjlzm7J2/M2N6d+DA=="], "strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], @@ -3363,6 +3364,8 @@ "@babel/template/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], + "@better-auth/stripe/zod": ["zod@4.1.5", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="], + "@browserbasehq/sdk/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="], "@browserbasehq/sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], @@ -3747,7 +3750,9 @@ "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "better-auth/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], + "better-auth/jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="], + + "better-auth/zod": ["zod@4.1.5", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="], "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], @@ -3925,8 +3930,6 @@ "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "stripe/@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -4405,8 +4408,6 @@ "sim/tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - "stripe/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], - "sucrase/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],