diff --git a/package/package.json b/package/package.json index 0769896..7309f07 100644 --- a/package/package.json +++ b/package/package.json @@ -91,6 +91,21 @@ "types": "./dist/libraries/backend/index.d.ts", "require": "./dist/libraries/backend/index.js", "import": "./dist/libraries/backend/index.mjs" + }, + "./sveltekit": { + "types": "./dist/libraries/backend/sveltekit.d.ts", + "require": "./dist/libraries/backend/sveltekit.js", + "import": "./dist/libraries/backend/sveltekit.mjs" + }, + "./svelte": { + "svelte": "./dist/libraries/svelte/index.js", + "types": "./dist/libraries/svelte/index.d.ts", + "require": "./dist/libraries/svelte/index.js", + "import": "./dist/libraries/svelte/index.mjs" + }, + "./svelte/AutumnProvider.svelte": { + "svelte": "./dist/libraries/svelte/AutumnProvider.svelte", + "default": "./dist/libraries/svelte/AutumnProvider.svelte" } }, "keywords": [ @@ -140,12 +155,16 @@ "tsconfig-paths": "^4.2.0", "tsup": "^8.4.0", "tsx": "^4.19.3", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "svelte": "^5.28.2", + "@sveltejs/kit": "^2.21.5" }, "peerDependencies": { "better-auth": "^1.3.17", "better-call": "^1.0.12", - "convex": "^1.25.4" + "convex": "^1.25.4", + "svelte": "^5.0.0", + "@sveltejs/kit": "^2.0.0" }, "peerDependenciesMeta": { "react": { @@ -156,6 +175,12 @@ }, "better-call": { "optional": true + }, + "svelte": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true } }, "dependencies": { @@ -192,6 +217,12 @@ ], "supabase": [ "./dist/libraries/backend/supabase.d.ts" + ], + "sveltekit": [ + "./dist/libraries/backend/sveltekit.d.ts" + ], + "svelte": [ + "./dist/libraries/svelte/index.d.ts" ] } } diff --git a/package/scripts/post-build.js b/package/scripts/post-build.js index fa42d1a..112bd09 100644 --- a/package/scripts/post-build.js +++ b/package/scripts/post-build.js @@ -163,6 +163,32 @@ function processInjectedCss() { }); } +// Copy Svelte component files to dist (they need to be processed by user's Svelte compiler) +function copySvelteFiles() { + const svelteSourceDir = path.join(__dirname, '../src/libraries/svelte'); + const svelteDistDir = path.join(__dirname, '../dist/libraries/svelte'); + + // Ensure dist directory exists + if (!fs.existsSync(svelteDistDir)) { + fs.mkdirSync(svelteDistDir, { recursive: true }); + } + + // Find and copy all .svelte files + if (fs.existsSync(svelteSourceDir)) { + const files = fs.readdirSync(svelteSourceDir); + files.forEach(file => { + if (file.endsWith('.svelte')) { + const sourcePath = path.join(svelteSourceDir, file); + const destPath = path.join(svelteDistDir, file); + fs.copyFileSync(sourcePath, destPath); + console.log('📄 Copied Svelte component:', file); + } + }); + console.log('✅ Svelte component files copied to dist'); + } +} + // Run the processing processCssFiles(); -processInjectedCss(); \ No newline at end of file +processInjectedCss(); +copySvelteFiles(); \ No newline at end of file diff --git a/package/src/libraries/backend/sveltekit.ts b/package/src/libraries/backend/sveltekit.ts new file mode 100644 index 0000000..cb64fb2 --- /dev/null +++ b/package/src/libraries/backend/sveltekit.ts @@ -0,0 +1,123 @@ +import { findRoute } from "rou3"; +import { Autumn } from "../../sdk"; +import { createRouterWithOptions } from "./routes/backendRouter"; +import { AuthResult } from "./utils/AuthFunction"; +import { autumnApiUrl } from "./constants"; +import { secretKeyCheck } from "./utils/secretKeyCheck"; + +// SvelteKit types - using generic types to avoid requiring @sveltejs/kit as dependency +type RequestEvent = { + request: Request; + url: URL; + params: Record; + cookies: { + get(name: string): string | undefined; + set(name: string, value: string, options?: any): void; + delete(name: string, options?: any): void; + }; + locals: Record; +}; + +type RequestHandler = (event: RequestEvent) => Promise | Response; + +export type AutumnSvelteKitHandlerOptions = { + identify: (event: RequestEvent) => AuthResult; + url?: string; + version?: string; + secretKey?: string; +}; + +/** + * Creates an Autumn handler for SvelteKit API routes. + * + * @example + * ```typescript + * // src/routes/api/autumn/[...path]/+server.ts + * import { autumnHandler } from 'autumn-js/sveltekit'; + * + * const handler = autumnHandler({ + * identify: async (event) => { + * const session = await event.locals.auth(); + * if (!session?.user?.id) return null; + * return { + * customerId: session.user.id, + * customerData: { + * name: session.user.name, + * email: session.user.email, + * } + * }; + * } + * }); + * + * export const GET = handler.GET; + * export const POST = handler.POST; + * ``` + */ +export function autumnHandler(options: AutumnSvelteKitHandlerOptions): { + GET: RequestHandler; + POST: RequestHandler; +} { + const router = createRouterWithOptions(); + + const { found, error: resError } = secretKeyCheck(options?.secretKey); + + const handler: RequestHandler = async (event) => { + if (!found && !options?.secretKey) { + return Response.json(resError, { status: resError!.statusCode }); + } + + const autumn = new Autumn({ + url: options?.url || autumnApiUrl, + version: options?.version, + }); + + const request = event.request; + const url = event.url; + const method = request.method; + const pathname = url.pathname; + const searchParams = Object.fromEntries(url.searchParams); + + const match = findRoute(router, method, pathname); + + if (!match) { + return Response.json({ error: "Not found" }, { status: 404 }); + } + + const { data, params: pathParams } = match; + const { handler: routeHandler } = data; + + let body = null; + if (method === "POST" || method === "PUT" || method === "PATCH") { + try { + body = await request.json(); + } catch (_) { + // Body parsing failed, continue with null body + } + } + + try { + const result = await routeHandler({ + autumn, + body, + path: pathname, + getCustomer: async () => await options.identify(event), + pathParams, + searchParams, + }); + + return Response.json(result.body, { status: result.statusCode }); + } catch (error) { + console.error("[Autumn] Error handling request:", error); + return Response.json( + { error: "Internal server error" }, + { status: 500 } + ); + } + }; + + return { + GET: handler, + POST: handler, + }; +} + diff --git a/package/src/libraries/svelte/AutumnProvider.svelte b/package/src/libraries/svelte/AutumnProvider.svelte new file mode 100644 index 0000000..0a3d8ca --- /dev/null +++ b/package/src/libraries/svelte/AutumnProvider.svelte @@ -0,0 +1,61 @@ + + + + +{@render props.children()} diff --git a/package/src/libraries/svelte/SvelteAutumnClient.svelte.ts b/package/src/libraries/svelte/SvelteAutumnClient.svelte.ts new file mode 100644 index 0000000..dccc418 --- /dev/null +++ b/package/src/libraries/svelte/SvelteAutumnClient.svelte.ts @@ -0,0 +1,361 @@ +import { + AutumnError, + AutumnPromise, + CreateCustomerParams, + CustomerData, + Product, + toContainerResult, +} from "../../sdk"; + +export interface ErrorResponse { + message: string; + code: string; +} + +export type OmitCustomerType = + | "id" + | "name" + | "email" + | "fingerprint" + | "customer_id"; + +export interface SvelteAutumnClientConfig { + backendUrl?: string; + getBearerToken?: () => Promise; + customerData?: CustomerData; + includeCredentials?: boolean; + betterAuthUrl?: string; + headers?: Record; + pathPrefix?: string; + defaultReturnUrl?: string; +} + +/** + * Autumn client for Svelte applications. + * Handles all API communication with the Autumn backend. + */ +export class SvelteAutumnClient { + public readonly backendUrl?: string; + protected readonly getBearerToken?: () => Promise; + public readonly customerData?: CustomerData; + protected includeCredentials?: boolean; + public readonly prefix: string; + public readonly camelCase: boolean; + public readonly headers?: Record; + public readonly defaultReturnUrl?: string; + + constructor({ + backendUrl, + getBearerToken, + customerData, + includeCredentials, + betterAuthUrl, + headers, + pathPrefix, + defaultReturnUrl, + }: SvelteAutumnClientConfig) { + this.backendUrl = backendUrl; + this.getBearerToken = getBearerToken; + this.customerData = customerData; + this.includeCredentials = includeCredentials; + this.prefix = "/api/autumn"; + let camelCase = false; + + if (betterAuthUrl) { + this.prefix = "/api/auth/autumn"; + this.backendUrl = betterAuthUrl; + camelCase = true; + } + + if (pathPrefix) { + const normalized = `/${pathPrefix}` + .replace(/\/+/g, "/") + .replace(/\/$/, ""); + this.prefix = normalized; + } + + this.headers = headers; + this.camelCase = camelCase; + this.defaultReturnUrl = defaultReturnUrl; + } + + /** + * Detects if the backend supports CORS credentials + */ + public async detectCors() { + if (this.prefix?.includes("/api/auth")) { + return { valid: true, includeCredentials: true }; + } + + const testEndpoint = `${this.backendUrl}${this.prefix}/cors`; + + try { + await fetch(testEndpoint, { + method: "POST", + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}), + }); + return { valid: true, includeCredentials: true }; + } catch (_) { + try { + await fetch(testEndpoint, { + method: "POST", + credentials: "omit", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}), + }); + return { valid: true, includeCredentials: false }; + } catch (_) { + return { valid: false, includeCredentials: undefined }; + } + } + } + + /** + * Determines whether to include credentials based on CORS detection + */ + public async shouldIncludeCredentials(): Promise { + if (this.includeCredentials !== undefined) { + return this.includeCredentials; + } + + try { + const corsResult = await this.detectCors(); + if (corsResult.valid) { + console.warn( + `[Autumn] Detected CORS credentials: ${corsResult.includeCredentials}` + ); + console.warn( + `[Autumn] To disable this warning, set includeCredentials={${ + corsResult.includeCredentials ? "true" : "false" + }} in AutumnProvider` + ); + this.includeCredentials = corsResult.includeCredentials; + return corsResult.includeCredentials || false; + } + + console.warn(`[Autumn] CORS detection failed, defaulting to false`); + return false; + } catch (error: any) { + console.error(`[Autumn] Error detecting CORS: ${error.message}`); + return false; + } + } + + async getHeaders() { + let headers: Record = { + "Content-Type": "application/json", + }; + + if (this.getBearerToken) { + try { + const token = await this.getBearerToken(); + if (token) { + headers.Authorization = `Bearer ${token}`; + } + } catch (_) { + console.error(`Failed to call getBearerToken() in AutumnProvider`); + } + } + + if (this.headers) { + headers = { ...headers, ...this.headers }; + } + + return headers; + } + + async handleFetch({ + path, + method, + body, + }: { + path: string; + method: string; + body?: Record | Record[]; + }) { + body = + method === "POST" + ? { + ...body, + [this.camelCase ? "customerData" : "customer_data"]: + this.customerData || undefined, + } + : undefined; + + const includeCredentials = await this.shouldIncludeCredentials(); + + try { + const response = await fetch(`${this.backendUrl}${path}`, { + method, + body: body ? JSON.stringify(body) : undefined, + headers: await this.getHeaders(), + credentials: includeCredentials ? "include" : "omit", + }); + + return await toContainerResult({ + response, + logger: console, + logError: true, + }); + } catch (error: unknown) { + console.error(`[Autumn] Fetch error:`, { + method, + backendUrl: this.backendUrl || "", + path, + error, + }); + return { + data: null, + error: new AutumnError({ + message: + error instanceof Error ? error.message : JSON.stringify(error), + code: "fetch_failed", + }), + }; + } + } + + async post( + path: string, + body: Record | Record[] + ) { + return await this.handleFetch({ + path, + method: "POST", + body, + }); + } + + async get(path: string) { + return await this.handleFetch({ + path, + method: "GET", + }); + } + + async delete(path: string) { + return await this.handleFetch({ + path, + method: "DELETE", + }); + } + + // Customer methods + async createCustomer( + params: Omit & { + errorOnNotFound?: boolean; + } + ) { + return await this.post(`${this.prefix}/customers`, params); + } + + // Attach / Checkout methods + async attach(params: { + productId: string; + successUrl?: string; + cancelUrl?: string; + options?: Record; + }) { + const finalParams = { + ...params, + successUrl: params.successUrl ?? this.defaultReturnUrl, + }; + return await this.post(`${this.prefix}/attach`, finalParams); + } + + async checkout(params: { + productId: string; + successUrl?: string; + cancelUrl?: string; + options?: Record; + }) { + const finalParams = { + ...params, + successUrl: params.successUrl ?? this.defaultReturnUrl, + }; + return await this.post(`${this.prefix}/checkout`, finalParams); + } + + // Subscription management + async cancel(params: { productId: string; cancelAtPeriodEnd?: boolean }) { + return await this.post(`${this.prefix}/cancel`, params); + } + + // Feature checking + async check(params: { featureId: string; delta?: number }) { + return await this.post(`${this.prefix}/check`, params); + } + + // Usage tracking + async track(params: { + featureId: string; + delta?: number; + entityId?: string; + set?: number; + }) { + return await this.post(`${this.prefix}/track`, params); + } + + // Billing portal + async openBillingPortal(params?: { returnUrl?: string }) { + const finalParams = { + ...(params || {}), + returnUrl: params?.returnUrl ?? this.defaultReturnUrl, + }; + return await this.post(`${this.prefix}/billing_portal`, finalParams); + } + + // Payment setup + async setupPayment(params?: { successUrl?: string; cancelUrl?: string }) { + const finalParams = { + ...(params || {}), + successUrl: params?.successUrl ?? this.defaultReturnUrl, + }; + return await this.post(`${this.prefix}/setup_payment`, finalParams); + } + + // Query + async query(params: { query: string }) { + return await this.post(`${this.prefix}/query`, params); + } + + // Entity methods + entities = { + create: async ( + params: + | { id: string; name?: string; featureId?: string } + | { id: string; name?: string; featureId?: string }[] + ) => { + return await this.post(`${this.prefix}/entities`, params); + }, + get: async (entityId: string, params?: { expand?: string[] }) => { + const queryString = params?.expand + ? `?expand=${params.expand.join(",")}` + : ""; + return await this.get(`${this.prefix}/entities/${entityId}${queryString}`); + }, + delete: async (params: { entityId: string }) => { + return await this.delete(`${this.prefix}/entities/${params.entityId}`); + }, + }; + + // Referral methods + referrals = { + createCode: async (params: { code?: string; programId?: string }) => { + return await this.post(`${this.prefix}/referrals/codes`, params); + }, + redeemCode: async (params: { code: string }) => { + return await this.post(`${this.prefix}/referrals/redeem`, params); + }, + }; + + // Product methods + products = { + list: async (): AutumnPromise<{ list: Product[] }> => { + return await this.get(`${this.prefix}/products`); + }, + }; +} + diff --git a/package/src/libraries/svelte/context.svelte.ts b/package/src/libraries/svelte/context.svelte.ts new file mode 100644 index 0000000..a220321 --- /dev/null +++ b/package/src/libraries/svelte/context.svelte.ts @@ -0,0 +1,151 @@ +import { setContext, getContext } from "svelte"; +import { SvelteAutumnClient, type SvelteAutumnClientConfig } from "./SvelteAutumnClient.svelte"; +import type { Customer, AutumnError } from "../../sdk"; + +const AUTUMN_CONTEXT_KEY = Symbol("autumn"); + +export interface AutumnContextValue { + // Client instance + readonly client: SvelteAutumnClient; + + // Customer state (reactive via getters/setters) + readonly customer: Customer | null; + readonly isLoading: boolean; + readonly error: AutumnError | null; + + // Methods to update state + setCustomer: (customer: Customer | null) => void; + setIsLoading: (loading: boolean) => void; + setError: (error: AutumnError | null) => void; + + // Refetch customer data + refetch: () => Promise; +} + +/** + * Creates the Autumn context with reactive state using Svelte 5 runes. + * Must be called in a component's script during initialization. + * + * @example + * ```svelte + * + * ``` + */ +export function createAutumnContext( + config: SvelteAutumnClientConfig +): AutumnContextValue { + const client = new SvelteAutumnClient(config); + + // Reactive state using $state rune + let customer = $state(null); + let isLoading = $state(true); + let error = $state(null); + + const fetchCustomer = async (): Promise => { + isLoading = true; + error = null; + + try { + const { data, error: fetchError } = await client.createCustomer({ + errorOnNotFound: false, + }); + + if (fetchError) { + error = fetchError; + customer = null; + return null; + } + + customer = data; + return data; + } catch (e: any) { + error = e; + customer = null; + return null; + } finally { + isLoading = false; + } + }; + + // Initial fetch + fetchCustomer(); + + const context: AutumnContextValue = { + get client() { + return client; + }, + get customer() { + return customer; + }, + get isLoading() { + return isLoading; + }, + get error() { + return error; + }, + setCustomer: (c: Customer | null) => { + customer = c; + }, + setIsLoading: (loading: boolean) => { + isLoading = loading; + }, + setError: (e: AutumnError | null) => { + error = e; + }, + refetch: fetchCustomer, + }; + + setContext(AUTUMN_CONTEXT_KEY, context); + + return context; +} + +/** + * Retrieves the Autumn context from a parent AutumnProvider. + * Must be called in a component that is a descendant of AutumnProvider. + * + * @example + * ```svelte + * + * + * {#if isLoading} + *

Loading...

+ * {:else if customer} + *

Welcome, {customer.name}!

+ * {/if} + * ``` + */ +export function getAutumnContext(): AutumnContextValue { + const context = getContext(AUTUMN_CONTEXT_KEY); + + if (!context) { + throw new Error( + "getAutumnContext must be called within a component that is a descendant of AutumnProvider" + ); + } + + return context; +} + +/** + * Attempts to get the Autumn context without throwing if not found. + * Returns null if context is not available. + */ +export function tryGetAutumnContext(): AutumnContextValue | null { + try { + return getContext(AUTUMN_CONTEXT_KEY) || null; + } catch { + return null; + } +} + diff --git a/package/src/libraries/svelte/index.ts b/package/src/libraries/svelte/index.ts new file mode 100644 index 0000000..d64b4f1 --- /dev/null +++ b/package/src/libraries/svelte/index.ts @@ -0,0 +1,50 @@ +// Autumn Svelte 5 Library +// Provides reactive billing, subscriptions, and feature access for Svelte applications + +// Note: The AutumnProvider.svelte component should be imported directly: +// import AutumnProvider from 'autumn-js/svelte/AutumnProvider.svelte'; + +// Context utilities +export { + createAutumnContext, + getAutumnContext, + tryGetAutumnContext, + type AutumnContextValue, +} from "./context.svelte"; + +// Hook-like functions (Svelte 5 runes-based) +export { + useCustomer, + type UseCustomerReturn, + type ClientCheckResult, + type AttachParams, + type CheckoutParams, + type CancelParams, + type CheckParams, + type TrackParams, +} from "./useCustomer.svelte"; +export { + usePricingTable, + type UsePricingTableReturn, + type PricingTableProduct, + type ProductDetails, +} from "./usePricingTable.svelte"; +export { useEntity, type UseEntityReturn, type UseEntityParams } from "./useEntity.svelte"; +export { usePaywall, type UsePaywallReturn, type UsePaywallParams } from "./usePaywall.svelte"; + +// Client (for advanced usage) +export { + SvelteAutumnClient, + type SvelteAutumnClientConfig, +} from "./SvelteAutumnClient.svelte"; + +// Re-export common types from SDK +export type { + Customer, + Entity, + Product, + CheckResult, + AutumnError, + CustomerData, +} from "../../sdk"; + diff --git a/package/src/libraries/svelte/useCustomer.svelte.ts b/package/src/libraries/svelte/useCustomer.svelte.ts new file mode 100644 index 0000000..ac95331 --- /dev/null +++ b/package/src/libraries/svelte/useCustomer.svelte.ts @@ -0,0 +1,254 @@ +import { getAutumnContext } from "./context.svelte"; +import type { Customer, AutumnError } from "../../sdk"; + +export interface AttachParams { + productId: string; + successUrl?: string; + cancelUrl?: string; + options?: Record; +} + +export interface CheckoutParams { + productId: string; + successUrl?: string; + cancelUrl?: string; + options?: Record; +} + +export interface CancelParams { + productId: string; + cancelAtPeriodEnd?: boolean; +} + +export interface CheckParams { + featureId: string; + delta?: number; +} + +export interface TrackParams { + featureId: string; + delta?: number; + entityId?: string; + set?: number; +} + +/** + * Client-side check result for feature access. + * Simplified from the full server-side CheckResult type. + */ +export interface ClientCheckResult { + allowed: boolean; + reason?: string; + balance?: number; + feature_id?: string; + unlimited?: boolean; +} + +export interface UseCustomerReturn { + /** Current customer data */ + readonly customer: Customer | null; + /** Whether customer data is loading */ + readonly isLoading: boolean; + /** Any error from fetching customer data */ + readonly error: AutumnError | null; + + /** Attach a product to the customer */ + attach: (params: AttachParams) => Promise; + /** Initiate checkout for a product */ + checkout: (params: CheckoutParams) => Promise; + /** Cancel a subscription */ + cancel: (params: CancelParams) => Promise; + /** Check feature access (client-side) */ + check: (params: CheckParams) => ClientCheckResult; + /** Track feature usage */ + track: (params: TrackParams) => Promise; + /** Open billing portal */ + openBillingPortal: (params?: { returnUrl?: string }) => Promise; + /** Setup payment method */ + setupPayment: (params?: { successUrl?: string }) => Promise; + /** Create an entity */ + createEntity: ( + params: { id: string; name?: string; featureId?: string } | { id: string; name?: string; featureId?: string }[] + ) => Promise; + /** Create a referral code */ + createReferralCode: (params: { code?: string; programId?: string }) => Promise; + /** Redeem a referral code */ + redeemReferralCode: (params: { code: string }) => Promise; + /** Refetch customer data */ + refetch: () => Promise; +} + +/** + * Svelte 5 hook for managing customer billing, subscriptions, and feature access. + * + * @example + * ```svelte + * + * + * {#if customer.isLoading} + *

Loading...

+ * {:else if customer.customer} + *

Welcome, {customer.customer.name}!

+ * + * {/if} + * ``` + */ +export function useCustomer(): UseCustomerReturn { + const context = getAutumnContext(); + const { client } = context; + + const checkFeature = (params: CheckParams): ClientCheckResult => { + const customer = context.customer; + + if (!customer) { + return { + allowed: false, + reason: "no_customer", + }; + } + + // Find the feature in customer's features object + const features = customer.features || {}; + const feature = features[params.featureId]; + + if (!feature) { + return { + allowed: false, + reason: "feature_not_found", + feature_id: params.featureId, + }; + } + + // Static features are always allowed + if (feature.type === "static") { + return { + allowed: true, + feature_id: params.featureId, + }; + } + + // Check if feature has unlimited access + if (feature.unlimited || feature.overage_allowed) { + return { + allowed: true, + feature_id: params.featureId, + unlimited: true, + }; + } + + // Check balance-based features + const delta = params.delta ?? 1; + const balance = feature.balance ?? 0; + + // Handle usage limits + if (feature.usage_limit) { + const extraUsage = (feature.usage_limit || 0) - (feature.included_usage || 0); + const effectiveBalance = balance + extraUsage; + + if (effectiveBalance >= delta) { + return { + allowed: true, + balance: effectiveBalance, + feature_id: params.featureId, + }; + } + } else if (balance >= delta) { + return { + allowed: true, + balance, + feature_id: params.featureId, + }; + } + + return { + allowed: false, + reason: "insufficient_balance", + balance, + feature_id: params.featureId, + }; + }; + + return { + get customer() { + return context.customer; + }, + get isLoading() { + return context.isLoading; + }, + get error() { + return context.error; + }, + + attach: async (params: AttachParams) => { + const result = await client.attach(params); + // Refetch customer after attach + if (!result.error) { + await context.refetch(); + } + return result; + }, + + checkout: async (params: CheckoutParams) => { + const result = await client.checkout(params); + if (result.data?.checkout_url) { + window.location.href = result.data.checkout_url; + } + return result; + }, + + cancel: async (params: CancelParams) => { + const result = await client.cancel(params); + if (!result.error) { + await context.refetch(); + } + return result; + }, + + check: checkFeature, + + track: async (params: TrackParams) => { + const result = await client.track(params); + if (!result.error) { + await context.refetch(); + } + return result; + }, + + openBillingPortal: async (params) => { + const result = await client.openBillingPortal(params); + if (result.data?.url) { + window.location.href = result.data.url; + } + return result; + }, + + setupPayment: async (params) => { + const result = await client.setupPayment(params); + if (result.data?.url) { + window.location.href = result.data.url; + } + return result; + }, + + createEntity: async (params) => { + return await client.entities.create(params); + }, + + createReferralCode: async (params) => { + return await client.referrals.createCode(params); + }, + + redeemReferralCode: async (params) => { + return await client.referrals.redeemCode(params); + }, + + refetch: context.refetch, + }; +} + diff --git a/package/src/libraries/svelte/useEntity.svelte.ts b/package/src/libraries/svelte/useEntity.svelte.ts new file mode 100644 index 0000000..0de3524 --- /dev/null +++ b/package/src/libraries/svelte/useEntity.svelte.ts @@ -0,0 +1,199 @@ +import { getAutumnContext } from "./context.svelte"; +import type { Entity, AutumnError } from "../../sdk"; + +/** + * Client-side check result for feature access. + * Simplified from the full server-side CheckResult type. + */ +export interface ClientCheckResult { + allowed: boolean; + reason?: string; + balance?: number; + feature_id?: string; + unlimited?: boolean; +} + +export interface UseEntityParams { + entityId: string; + expand?: string[]; +} + +export interface UseEntityReturn { + /** Current entity data */ + readonly entity: Entity | null; + /** Whether entity data is loading */ + readonly isLoading: boolean; + /** Any error from fetching entity data */ + readonly error: AutumnError | null; + + /** Check feature access for this entity (client-side) */ + check: (params: { featureId: string; delta?: number }) => ClientCheckResult; + /** Track feature usage for this entity */ + track: (params: { featureId: string; delta?: number; set?: number }) => Promise; + /** Refetch entity data */ + refetch: () => Promise; +} + +/** + * Svelte 5 hook for managing entity-level billing and feature access. + * Entities allow per-user or per-workspace feature limits. + * + * @example + * ```svelte + * + * + * {#if entity.isLoading} + *

Loading...

+ * {:else if entity.entity} + *

Workspace: {entity.entity.name}

+ * + * {#if entity.check({ featureId: 'api_calls' }).allowed} + * + * {:else} + *

API call limit reached

+ * {/if} + * {/if} + * ``` + */ +export function useEntity(params: UseEntityParams): UseEntityReturn { + const context = getAutumnContext(); + const { client } = context; + + let entity = $state(null); + let isLoading = $state(true); + let error = $state(null); + + const fetchEntity = async (): Promise => { + isLoading = true; + error = null; + + try { + const { data, error: fetchError } = await client.entities.get( + params.entityId, + { expand: params.expand } + ); + + if (fetchError) { + error = fetchError; + entity = null; + return null; + } + + entity = data; + return data; + } catch (e: any) { + error = e; + entity = null; + return null; + } finally { + isLoading = false; + } + }; + + // Initial fetch + fetchEntity(); + + const checkFeature = (checkParams: { + featureId: string; + delta?: number; + }): ClientCheckResult => { + if (!entity) { + return { + allowed: false, + reason: "no_entity", + }; + } + + // Find the feature in entity's features object + const features = (entity as any).features || {}; + const feature = features[checkParams.featureId]; + + if (!feature) { + return { + allowed: false, + reason: "feature_not_found", + feature_id: checkParams.featureId, + }; + } + + // Static features are always allowed + if (feature.type === "static") { + return { + allowed: true, + feature_id: checkParams.featureId, + }; + } + + if (feature.unlimited || feature.overage_allowed) { + return { + allowed: true, + feature_id: checkParams.featureId, + unlimited: true, + }; + } + + const delta = checkParams.delta ?? 1; + const balance = feature.balance ?? 0; + + // Handle usage limits + if (feature.usage_limit) { + const extraUsage = (feature.usage_limit || 0) - (feature.included_usage || 0); + const effectiveBalance = balance + extraUsage; + + if (effectiveBalance >= delta) { + return { + allowed: true, + balance: effectiveBalance, + feature_id: checkParams.featureId, + }; + } + } else if (balance >= delta) { + return { + allowed: true, + balance, + feature_id: checkParams.featureId, + }; + } + + return { + allowed: false, + reason: "insufficient_balance", + balance, + feature_id: checkParams.featureId, + }; + }; + + return { + get entity() { + return entity; + }, + get isLoading() { + return isLoading; + }, + get error() { + return error; + }, + + check: checkFeature, + + track: async (trackParams) => { + const result = await client.track({ + ...trackParams, + entityId: params.entityId, + }); + if (!result.error) { + await fetchEntity(); + } + return result; + }, + + refetch: fetchEntity, + }; +} + diff --git a/package/src/libraries/svelte/usePaywall.svelte.ts b/package/src/libraries/svelte/usePaywall.svelte.ts new file mode 100644 index 0000000..be83746 --- /dev/null +++ b/package/src/libraries/svelte/usePaywall.svelte.ts @@ -0,0 +1,156 @@ +import { getAutumnContext } from "./context.svelte"; + +/** + * Client-side check result for feature access. + * Simplified from the full server-side CheckResult type. + */ +export interface ClientCheckResult { + allowed: boolean; + reason?: string; + balance?: number; + feature_id?: string; + unlimited?: boolean; +} + +export interface UsePaywallParams { + featureId: string; + delta?: number; +} + +export interface UsePaywallReturn { + /** Whether the feature is allowed */ + readonly allowed: boolean; + /** Whether the check is loading */ + readonly isLoading: boolean; + /** The balance remaining (if applicable) */ + readonly balance: number | undefined; + /** The reason access was denied */ + readonly reason: string | undefined; + /** The full check result */ + readonly checkResult: ClientCheckResult; + /** Recheck the feature access */ + recheck: () => void; +} + +/** + * Svelte 5 hook for implementing feature paywalls. + * Provides reactive feature gating based on customer entitlements. + * + * @example + * ```svelte + * + * + * {#if paywall.isLoading} + *

Checking access...

+ * {:else if paywall.allowed} + * + * {:else} + * + * {/if} + * ``` + */ +export function usePaywall(params: UsePaywallParams): UsePaywallReturn { + const context = getAutumnContext(); + + // Derived state that recomputes when customer changes + let checkResult = $derived.by((): ClientCheckResult => { + const customer = context.customer; + + if (context.isLoading) { + return { + allowed: false, + reason: "loading", + }; + } + + if (!customer) { + return { + allowed: false, + reason: "no_customer", + }; + } + + // Find the feature in customer's features object + const features = customer.features || {}; + const feature = features[params.featureId]; + + if (!feature) { + return { + allowed: false, + reason: "feature_not_found", + feature_id: params.featureId, + }; + } + + // Static features are always allowed + if (feature.type === "static") { + return { + allowed: true, + feature_id: params.featureId, + }; + } + + if (feature.unlimited || feature.overage_allowed) { + return { + allowed: true, + feature_id: params.featureId, + unlimited: true, + }; + } + + const delta = params.delta ?? 1; + const balance = feature.balance ?? 0; + + // Handle usage limits + if (feature.usage_limit) { + const extraUsage = (feature.usage_limit || 0) - (feature.included_usage || 0); + const effectiveBalance = balance + extraUsage; + + if (effectiveBalance >= delta) { + return { + allowed: true, + balance: effectiveBalance, + feature_id: params.featureId, + }; + } + } else if (balance >= delta) { + return { + allowed: true, + balance, + feature_id: params.featureId, + }; + } + + return { + allowed: false, + reason: "insufficient_balance", + balance, + feature_id: params.featureId, + }; + }); + + return { + get allowed() { + return checkResult.allowed; + }, + get isLoading() { + return context.isLoading; + }, + get balance() { + return checkResult.balance; + }, + get reason() { + return checkResult.reason; + }, + get checkResult() { + return checkResult; + }, + recheck: () => { + context.refetch(); + }, + }; +} diff --git a/package/src/libraries/svelte/usePricingTable.svelte.ts b/package/src/libraries/svelte/usePricingTable.svelte.ts new file mode 100644 index 0000000..1f3eecf --- /dev/null +++ b/package/src/libraries/svelte/usePricingTable.svelte.ts @@ -0,0 +1,113 @@ +import { getAutumnContext } from "./context.svelte"; +import type { Product } from "../../sdk"; + +export interface ProductDetails { + id: string; + name?: string; + description?: string; + cta?: string; + features?: string[]; +} + +export interface PricingTableProduct extends Product { + details?: ProductDetails; +} + +export interface UsePricingTableReturn { + /** List of products with pricing information */ + readonly products: PricingTableProduct[]; + /** Whether products are loading */ + readonly isLoading: boolean; + /** Any error from fetching products */ + readonly error: Error | null; + /** Refetch the pricing table */ + refetch: () => Promise; +} + +/** + * Svelte 5 hook for fetching and managing pricing table data. + * + * @example + * ```svelte + * + * + * {#if pricing.isLoading} + *

Loading pricing...

+ * {:else} + * {#each pricing.products as product} + *
+ *

{product.name}

+ *

{product.description}

+ *
+ * {/each} + * {/if} + * ``` + */ +export function usePricingTable(params?: { + productDetails?: ProductDetails[]; +}): UsePricingTableReturn { + const context = getAutumnContext(); + const { client } = context; + + let products = $state([]); + let isLoading = $state(true); + let error = $state(null); + + const fetchProducts = async () => { + isLoading = true; + error = null; + + try { + const { data, error: fetchError } = await client.products.list(); + + if (fetchError) { + error = fetchError; + products = []; + return; + } + + // Merge with product details if provided + const productList = data?.list || []; + + if (params?.productDetails) { + products = productList.map((product: Product) => { + const details = params.productDetails?.find( + (d) => d.id === product.id + ); + return { + ...product, + details, + }; + }); + } else { + products = productList; + } + } catch (e: any) { + error = e; + products = []; + } finally { + isLoading = false; + } + }; + + // Initial fetch + fetchProducts(); + + return { + get products() { + return products; + }, + get isLoading() { + return isLoading; + }, + get error() { + return error; + }, + refetch: fetchProducts, + }; +} + diff --git a/package/tsup.config.ts b/package/tsup.config.ts index 5432cba..103aa2c 100644 --- a/package/tsup.config.ts +++ b/package/tsup.config.ts @@ -9,6 +9,11 @@ const pathAliases = { "@styles": path.resolve("./src/styles"), }; +// Path aliases for Svelte library +const sveltePathAliases = { + "@sdk": path.resolve("./src/sdk"), +}; + const reactConfigs: Options[] = [ // Backend { @@ -210,4 +215,26 @@ export default defineConfig([ options.format = "esm"; }, }, + + // Svelte library - TypeScript files (including .svelte.ts runes files) + { + entry: [ + "src/libraries/svelte/**/*.ts", + "!src/libraries/svelte/**/*.svelte", + ], + format: ["cjs", "esm"], + dts: true, + clean: false, + outDir: "./dist/libraries/svelte", + external: ["svelte", "svelte/store", "@sveltejs/kit"], + bundle: true, + skipNodeModulesBundle: true, + esbuildOptions(options) { + options.plugins = options.plugins || []; + options.plugins.push(alias(sveltePathAliases)); + options.define = { + ...options.define, + }; + }, + }, ]); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec6370f..5606ad8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,7 +101,7 @@ importers: dependencies: convex-helpers: specifier: ^0.1.104 - version: 0.1.104(@standard-schema/spec@1.0.0)(convex@1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1))(hono@4.9.1)(react@19.1.1)(typescript@5.5.4)(zod@4.1.5) + version: 0.1.104(@standard-schema/spec@1.0.0)(convex@1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1))(hono@4.9.1)(react@19.1.1)(typescript@5.5.4)(zod@4.1.5) react: specifier: ^18.3.1 || ^19.0.0 version: 19.1.1 @@ -123,10 +123,10 @@ importers: version: 3.0.0 convex: specifier: 1.29.3 - version: 1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1) + version: 1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) convex-test: specifier: 0.0.37 - version: 0.0.37(convex@1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1)) + version: 0.0.37(convex@1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)) eslint: specifier: 9.29.0 version: 9.29.0(jiti@2.5.1) @@ -280,7 +280,7 @@ importers: dependencies: better-auth: specifier: ^1.3.17 - version: 1.3.34(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 1.3.34(@sveltejs/kit@2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(svelte@5.45.5) better-call: specifier: ^1.0.12 version: 1.0.13 @@ -318,6 +318,9 @@ importers: '@supabase/ssr': specifier: ^0.6.1 version: 0.6.1(@supabase/supabase-js@2.78.0) + '@sveltejs/kit': + specifier: ^2.21.5 + version: 2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) '@tanstack/react-start': specifier: ^1.120.5 version: 1.131.8(@netlify/blobs@9.1.2)(@tanstack/react-router@1.131.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@vitejs/plugin-react@5.0.0(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(better-sqlite3@12.2.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rolldown@1.0.0-beta.34)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1))(webpack@5.101.1(esbuild@0.25.9)) @@ -335,7 +338,7 @@ importers: version: 10.4.21(postcss@8.5.6) autumn-js: specifier: ^0.0.115 - version: 0.0.115(better-auth@1.3.34(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(better-call@1.0.13)(react@19.1.1) + version: 0.0.115(better-auth@1.3.34(@sveltejs/kit@2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(svelte@5.45.5))(better-call@1.0.13)(react@19.1.1) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -393,6 +396,9 @@ importers: stripe: specifier: ^18.3.0 version: 18.4.0(@types/node@22.17.1) + svelte: + specifier: ^5.28.2 + version: 5.45.5 tailwind-merge: specifier: ^2.6.0 version: 2.6.0 @@ -467,7 +473,7 @@ importers: version: 15.6.10(@types/react@18.3.23)(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-router@7.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) fumadocs-mdx: specifier: ^11.6.1 - version: 11.7.5(acorn@8.15.0)(fumadocs-core@15.6.10(@types/react@18.3.23)(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-router@7.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1))(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(vite@7.1.5(@types/node@20.19.10)(jiti@2.5.1)) + version: 11.7.5(acorn@8.15.0)(fumadocs-core@15.6.10(@types/react@18.3.23)(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-router@7.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1))(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(vite@7.1.5(@types/node@20.19.10)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) fumadocs-ui: specifier: ^15.2.11 version: 15.6.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-router@7.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.10)(typescript@5.9.2))) @@ -1710,6 +1716,9 @@ packages: '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -2018,6 +2027,9 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@poppinss/colors@4.1.5': resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==} @@ -2989,6 +3001,39 @@ packages: '@supabase/supabase-js@2.78.0': resolution: {integrity: sha512-xYMRNBFmKp2m1gMuwcp/gr/HlfZKqjye1Ib8kJe29XJNsgwsfO/f8skxnWiscFKTlkOKLuBexNgl5L8dzGt6vA==} + '@sveltejs/acorn-typescript@1.0.8': + resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==} + peerDependencies: + acorn: ^8.9.0 + + '@sveltejs/kit@2.49.1': + resolution: {integrity: sha512-vByReCTTdlNM80vva8alAQC80HcOiHLkd8XAxIiKghKSHcqeNfyhp3VsYAV8VSiPKu4Jc8wWCfsZNAIvd1uCqA==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.0.0 + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@sveltejs/vite-plugin-svelte-inspector@5.0.1': + resolution: {integrity: sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + + '@sveltejs/vite-plugin-svelte@6.2.1': + resolution: {integrity: sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -4715,6 +4760,10 @@ packages: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -5063,6 +5112,9 @@ packages: peerDependencies: typescript: ^5.4.4 + devalue@5.5.0: + resolution: {integrity: sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -5545,6 +5597,9 @@ packages: jiti: optional: true + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + esm-utils@4.4.2: resolution: {integrity: sha512-oG7oQZRniJEUSRYzdeWHOAe3n6mW5lNouDFm2b7pfPounjyuSaJSTVybDuiMnBizALdOBfM1r0QKlDh4psOY9Q==} @@ -5568,6 +5623,9 @@ packages: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} + esrap@2.2.1: + resolution: {integrity: sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -6586,6 +6644,9 @@ packages: is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -6951,6 +7012,9 @@ packages: resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} engines: {node: '>=14'} + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -7396,6 +7460,10 @@ packages: resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} engines: {node: '>=10'} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -8669,6 +8737,10 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -8846,6 +8918,10 @@ packages: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -9132,6 +9208,10 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svelte@5.45.5: + resolution: {integrity: sha512-2074U+vObO5Zs8/qhxtBwdi6ZXNIhEBTzNmUFjiZexLxTdt9vq96D/0pnQELl6YcpLMD7pZ2dhXKByfGS8SAdg==} + engines: {node: '>=18'} + swr@2.3.4: resolution: {integrity: sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg==} peerDependencies: @@ -9309,6 +9389,10 @@ packages: toml@3.0.0: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + touch@3.1.1: resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true @@ -10107,6 +10191,9 @@ packages: resolution: {integrity: sha512-rY2A2lSF7zC+l7HH9Mq+83D1dLlsPnEvy8jTouzaptDZM6geqZ3aJe/b7ULCwRURPtWV3vbDjA2DDMdoBol0HQ==} engines: {node: '>=18'} + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -10510,7 +10597,7 @@ snapshots: '@clerk/clerk-react': 5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@clerk/shared': 3.19.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@clerk/types': 4.75.0 - next: 15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + next: 15.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) server-only: 0.0.1 @@ -11263,6 +11350,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/source-map@0.3.11': @@ -11646,6 +11738,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@polka/url@1.0.0-next.29': {} + '@poppinss/colors@4.1.5': dependencies: kleur: 4.1.5 @@ -13028,6 +13122,50 @@ snapshots: - bufferutil - utf-8-validate + '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)': + dependencies: + acorn: 8.15.0 + + '@sveltejs/kit@2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1))': + dependencies: + '@standard-schema/spec': 1.0.0 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) + '@types/cookie': 0.6.0 + acorn: 8.15.0 + cookie: 0.6.0 + devalue: 5.5.0 + esm-env: 1.2.2 + kleur: 4.1.5 + magic-string: 0.30.17 + mrmime: 2.0.1 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.2 + svelte: 5.45.5 + vite: 7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1) + + '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1))': + dependencies: + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) + debug: 4.4.1(supports-color@5.5.0) + svelte: 5.45.5 + vite: 7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) + debug: 4.4.1(supports-color@5.5.0) + deepmerge: 4.3.1 + magic-string: 0.30.17 + svelte: 5.45.5 + vite: 7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) + transitivePeerDependencies: + - supports-color + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -14484,13 +14622,13 @@ snapshots: - react-dom - utf-8-validate - autumn-js@0.0.115(better-auth@1.3.34(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(better-call@1.0.13)(react@19.1.1): + autumn-js@0.0.115(better-auth@1.3.34(@sveltejs/kit@2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(svelte@5.45.5))(better-call@1.0.13)(react@19.1.1): dependencies: rou3: 0.6.3 swr: 2.3.6(react@19.1.1) zod: 3.25.76 optionalDependencies: - better-auth: 1.3.34(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + better-auth: 1.3.34(@sveltejs/kit@2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(svelte@5.45.5) better-call: 1.0.13 react: 19.1.1 @@ -14585,7 +14723,7 @@ snapshots: bcp-47-match@2.0.3: {} - better-auth@1.3.34(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + better-auth@1.3.34(@sveltejs/kit@2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(svelte@5.45.5): dependencies: '@better-auth/core': 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.5)(nanostores@1.0.1) '@better-auth/telemetry': 1.3.34(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.5)(nanostores@1.0.1) @@ -14602,12 +14740,13 @@ snapshots: nanostores: 1.0.1 zod: 4.1.5 optionalDependencies: - next: 15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optional: true + '@sveltejs/kit': 2.49.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)))(svelte@5.45.5)(vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)) + next: 15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + svelte: 5.45.5 - better-auth@1.3.34(next@15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + better-auth@1.3.34(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@better-auth/core': 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.5)(nanostores@1.0.1) '@better-auth/telemetry': 1.3.34(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.5)(nanostores@1.0.1) @@ -14624,9 +14763,10 @@ snapshots: nanostores: 1.0.1 zod: 4.1.5 optionalDependencies: - next: 15.3.4(@babel/core@7.28.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + next: 15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optional: true better-auth@1.3.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(zod@4.0.17): dependencies: @@ -15115,9 +15255,9 @@ snapshots: convert-to-spaces@2.0.1: {} - convex-helpers@0.1.104(@standard-schema/spec@1.0.0)(convex@1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1))(hono@4.9.1)(react@19.1.1)(typescript@5.5.4)(zod@4.1.5): + convex-helpers@0.1.104(@standard-schema/spec@1.0.0)(convex@1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1))(hono@4.9.1)(react@19.1.1)(typescript@5.5.4)(zod@4.1.5): dependencies: - convex: 1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1) + convex: 1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) optionalDependencies: '@standard-schema/spec': 1.0.0 hono: 4.9.1 @@ -15125,9 +15265,9 @@ snapshots: typescript: 5.5.4 zod: 4.1.5 - convex-test@0.0.37(convex@1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1)): + convex-test@0.0.37(convex@1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)): dependencies: - convex: 1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1) + convex: 1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) convex@1.25.4(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): dependencies: @@ -15138,7 +15278,7 @@ snapshots: '@clerk/clerk-react': 5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 - convex@1.29.3(@clerk/clerk-react@5.45.0(react@19.1.1))(react@19.1.1): + convex@1.29.3(@clerk/clerk-react@5.45.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): dependencies: esbuild: 0.25.4 prettier: 3.6.2 @@ -15152,6 +15292,8 @@ snapshots: cookie-signature@1.2.2: {} + cookie@0.6.0: {} + cookie@0.7.2: {} cookie@1.0.2: {} @@ -15448,6 +15590,8 @@ snapshots: transitivePeerDependencies: - supports-color + devalue@5.5.0: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -15834,7 +15978,7 @@ snapshots: '@typescript-eslint/parser': 7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.29.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.29.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.29.0(jiti@2.5.1)) @@ -15854,7 +15998,7 @@ snapshots: '@typescript-eslint/parser': 7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.29.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.29.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.29.0(jiti@2.5.1)) @@ -15900,7 +16044,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1(supports-color@5.5.0) @@ -15932,14 +16076,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.29.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color @@ -15988,7 +16132,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.29.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.29.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)))(eslint@9.29.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16268,6 +16412,8 @@ snapshots: transitivePeerDependencies: - supports-color + esm-env@1.2.2: {} + esm-utils@4.4.2: dependencies: import-meta-resolve: 4.1.0 @@ -16293,6 +16439,10 @@ snapshots: dependencies: estraverse: 5.3.0 + esrap@2.2.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -16712,7 +16862,7 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-mdx@11.7.5(acorn@8.15.0)(fumadocs-core@15.6.10(@types/react@18.3.23)(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-router@7.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1))(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(vite@7.1.5(@types/node@20.19.10)(jiti@2.5.1)): + fumadocs-mdx@11.7.5(acorn@8.15.0)(fumadocs-core@15.6.10(@types/react@18.3.23)(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react-router@7.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1))(next@15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(vite@7.1.5(@types/node@20.19.10)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1)): dependencies: '@mdx-js/mdx': 3.1.0(acorn@8.15.0) '@standard-schema/spec': 1.0.0 @@ -16730,7 +16880,7 @@ snapshots: optionalDependencies: next: 15.3.4(@babel/core@7.28.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - vite: 7.1.5(@types/node@20.19.10)(jiti@2.5.1) + vite: 7.1.5(@types/node@20.19.10)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1) transitivePeerDependencies: - acorn - supports-color @@ -17477,6 +17627,10 @@ snapshots: dependencies: '@types/estree': 1.0.8 + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -17788,6 +17942,8 @@ snapshots: pkg-types: 2.2.0 quansync: 0.2.10 + locate-character@3.0.0: {} + locate-path@3.0.0: dependencies: p-locate: 3.0.0 @@ -18475,6 +18631,8 @@ snapshots: mrmime@1.0.1: {} + mrmime@2.0.1: {} + ms@2.1.3: {} msw@2.10.4(@types/node@18.17.0)(typescript@5.5.4): @@ -18618,6 +18776,31 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@15.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + '@next/env': 15.3.4 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001734 + postcss: 8.4.31 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.1.1) + optionalDependencies: + '@next/swc-darwin-arm64': 15.3.4 + '@next/swc-darwin-x64': 15.3.4 + '@next/swc-linux-arm64-gnu': 15.3.4 + '@next/swc-linux-arm64-musl': 15.3.4 + '@next/swc-linux-x64-gnu': 15.3.4 + '@next/swc-linux-x64-musl': 15.3.4 + '@next/swc-win32-arm64-msvc': 15.3.4 + '@next/swc-win32-x64-msvc': 15.3.4 + sharp: 0.34.3 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + nitropack@2.12.4(@netlify/blobs@9.1.2)(better-sqlite3@12.2.0)(rolldown@1.0.0-beta.34): dependencies: '@cloudflare/kv-asset-handler': 0.4.0 @@ -20083,6 +20266,10 @@ snapshots: dependencies: tslib: 2.8.1 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -20349,6 +20536,12 @@ snapshots: dependencies: semver: 7.7.2 + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + sisteransi@1.0.5: {} slash@3.0.0: {} @@ -20652,6 +20845,24 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svelte@5.45.5: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + devalue: 5.5.0 + esm-env: 1.2.2 + esrap: 2.2.1 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.17 + zimmerframe: 1.1.4 + swr@2.3.4(react@19.1.1): dependencies: dequal: 2.0.3 @@ -20876,6 +21087,8 @@ snapshots: toml@3.0.0: {} + totalist@3.0.1: {} + touch@3.1.1: {} tough-cookie@4.1.4: @@ -21481,7 +21694,7 @@ snapshots: tsx: 4.20.4 yaml: 2.8.1 - vite@7.1.5(@types/node@20.19.10)(jiti@2.5.1): + vite@7.1.5(@types/node@20.19.10)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -21493,6 +21706,10 @@ snapshots: '@types/node': 20.19.10 fsevents: 2.3.3 jiti: 2.5.1 + lightningcss: 1.30.1 + terser: 5.43.1 + tsx: 4.20.4 + yaml: 2.8.1 optional: true vite@7.1.5(@types/node@22.17.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.4)(yaml@2.8.1): @@ -21898,6 +22115,8 @@ snapshots: cookie: 1.0.2 youch-core: 0.3.3 + zimmerframe@1.1.4: {} + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2