@raideno/convex-stripe 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -2428,6 +2428,114 @@ defineSchema({
2428
2428
  contentType: v.optional(v.string())
2429
2429
  })
2430
2430
  });
2431
+ function getDefaultExportFromCjs(x) {
2432
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
2433
+ }
2434
+ var cjs;
2435
+ var hasRequiredCjs;
2436
+ function requireCjs() {
2437
+ if (hasRequiredCjs) return cjs;
2438
+ hasRequiredCjs = 1;
2439
+ var isMergeableObject = function isMergeableObject2(value) {
2440
+ return isNonNullObject(value) && !isSpecial2(value);
2441
+ };
2442
+ function isNonNullObject(value) {
2443
+ return !!value && typeof value === "object";
2444
+ }
2445
+ function isSpecial2(value) {
2446
+ var stringValue = Object.prototype.toString.call(value);
2447
+ return stringValue === "[object RegExp]" || stringValue === "[object Date]" || isReactElement(value);
2448
+ }
2449
+ var canUseSymbol = typeof Symbol === "function" && Symbol.for;
2450
+ var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for("react.element") : 60103;
2451
+ function isReactElement(value) {
2452
+ return value.$$typeof === REACT_ELEMENT_TYPE;
2453
+ }
2454
+ function emptyTarget(val) {
2455
+ return Array.isArray(val) ? [] : {};
2456
+ }
2457
+ function cloneUnlessOtherwiseSpecified(value, options) {
2458
+ return options.clone !== false && options.isMergeableObject(value) ? deepmerge2(emptyTarget(value), value, options) : value;
2459
+ }
2460
+ function defaultArrayMerge(target, source, options) {
2461
+ return target.concat(source).map(function(element) {
2462
+ return cloneUnlessOtherwiseSpecified(element, options);
2463
+ });
2464
+ }
2465
+ function getMergeFunction(key, options) {
2466
+ if (!options.customMerge) {
2467
+ return deepmerge2;
2468
+ }
2469
+ var customMerge = options.customMerge(key);
2470
+ return typeof customMerge === "function" ? customMerge : deepmerge2;
2471
+ }
2472
+ function getEnumerableOwnPropertySymbols(target) {
2473
+ return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) {
2474
+ return Object.propertyIsEnumerable.call(target, symbol);
2475
+ }) : [];
2476
+ }
2477
+ function getKeys(target) {
2478
+ return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target));
2479
+ }
2480
+ function propertyIsOnObject(object, property) {
2481
+ try {
2482
+ return property in object;
2483
+ } catch (_) {
2484
+ return false;
2485
+ }
2486
+ }
2487
+ function propertyIsUnsafe(target, key) {
2488
+ return propertyIsOnObject(target, key) && !(Object.hasOwnProperty.call(target, key) && Object.propertyIsEnumerable.call(target, key));
2489
+ }
2490
+ function mergeObject(target, source, options) {
2491
+ var destination = {};
2492
+ if (options.isMergeableObject(target)) {
2493
+ getKeys(target).forEach(function(key) {
2494
+ destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
2495
+ });
2496
+ }
2497
+ getKeys(source).forEach(function(key) {
2498
+ if (propertyIsUnsafe(target, key)) {
2499
+ return;
2500
+ }
2501
+ if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
2502
+ destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
2503
+ } else {
2504
+ destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
2505
+ }
2506
+ });
2507
+ return destination;
2508
+ }
2509
+ function deepmerge2(target, source, options) {
2510
+ options = options || {};
2511
+ options.arrayMerge = options.arrayMerge || defaultArrayMerge;
2512
+ options.isMergeableObject = options.isMergeableObject || isMergeableObject;
2513
+ options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
2514
+ var sourceIsArray = Array.isArray(source);
2515
+ var targetIsArray = Array.isArray(target);
2516
+ var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
2517
+ if (!sourceAndTargetTypesMatch) {
2518
+ return cloneUnlessOtherwiseSpecified(source, options);
2519
+ } else if (sourceIsArray) {
2520
+ return options.arrayMerge(target, source, options);
2521
+ } else {
2522
+ return mergeObject(target, source, options);
2523
+ }
2524
+ }
2525
+ deepmerge2.all = function deepmergeAll(array, options) {
2526
+ if (!Array.isArray(array)) {
2527
+ throw new Error("first argument should be an array");
2528
+ }
2529
+ return array.reduce(function(prev, next) {
2530
+ return deepmerge2(prev, next, options);
2531
+ }, {});
2532
+ };
2533
+ var deepmerge_1 = deepmerge2;
2534
+ cjs = deepmerge_1;
2535
+ return cjs;
2536
+ }
2537
+ var cjsExports = requireCjs();
2538
+ const deepmerge = /* @__PURE__ */ getDefaultExportFromCjs(cjsExports);
2431
2539
  class Logger {
2432
2540
  debug_;
2433
2541
  constructor(debug) {
@@ -2448,1087 +2556,152 @@ class Logger {
2448
2556
  }
2449
2557
  }
2450
2558
  }
2451
- const DEFAULT_PATH = "/stripe/webhook";
2452
- const DEFAULT_DESCRIPTION = "Convex Stripe Webhook Endpoint";
2453
- const DEFAULT_METADATA = {};
2454
- const DEFAULT_DETACHED = false;
2455
- const DEFAULT_CATALOG_METADATA_KEY = "convex_stripe_key";
2456
- const DEFAULT_CATALOG_BEHAVIOR_ON_EXISTING = "update";
2457
- const DEFAULT_CATALOG_BEHAVIOR_ON_MISSING_KEY = "create";
2458
- const normalizeConfiguration = (config) => {
2459
- return {
2460
- // TODO: should be on the bottom no ?
2461
- ...config,
2462
- redirectTtlMs: 15 * 60 * 1e3,
2463
- detached: DEFAULT_DETACHED,
2464
- catalog: {
2465
- products: config.catalog?.products || [],
2466
- prices: config.catalog?.prices || [],
2467
- metadataKey: config.catalog?.metadataKey || DEFAULT_CATALOG_METADATA_KEY,
2468
- behavior: {
2469
- onExisting: config.catalog?.behavior?.onExisting || DEFAULT_CATALOG_BEHAVIOR_ON_EXISTING,
2470
- onMissingKey: config.catalog?.behavior?.onMissingKey || DEFAULT_CATALOG_BEHAVIOR_ON_MISSING_KEY
2471
- }
2472
- },
2473
- sync: {
2474
- stripeAccounts: true,
2475
- stripeCapabilities: true,
2476
- stripeTransfers: true,
2477
- stripeCoupons: true,
2478
- stripeCustomers: true,
2479
- stripePrices: true,
2480
- stripeProducts: true,
2481
- stripePromotionCodes: true,
2482
- stripeSubscriptions: true,
2483
- stripePayouts: true,
2484
- stripeCheckoutSessions: true,
2485
- stripePaymentIntents: true,
2486
- stripeRefunds: true,
2487
- stripeInvoices: true,
2488
- stripeReviews: true,
2489
- stripeCharges: true,
2490
- stripeCreditNotes: true,
2491
- stripeDisputes: true,
2492
- stripeEarlyFraudWarnings: true,
2493
- stripePaymentMethods: true,
2494
- stripePlans: true,
2495
- stripeSetupIntents: true,
2496
- stripeSubscriptionSchedules: true,
2497
- stripeTaxIds: true,
2498
- stripeMandates: true,
2499
- stripeBillingPortalConfigurations: true
2500
- },
2501
- webhook: {
2502
- path: config.webhook?.path || DEFAULT_PATH,
2503
- description: config.webhook?.description || DEFAULT_DESCRIPTION,
2504
- metadata: config.webhook?.metadata || DEFAULT_METADATA
2559
+ const AccountStripeToConvex = (account) => {
2560
+ const object = {
2561
+ id: account.id,
2562
+ object: account.object,
2563
+ business_type: account.business_type,
2564
+ capabilities: account.capabilities ?? null,
2565
+ company: account.company ?? null,
2566
+ country: account.country,
2567
+ email: account.email,
2568
+ individual: account.individual ?? null,
2569
+ metadata: account.metadata ?? null,
2570
+ requirements: account.requirements ?? null,
2571
+ tos_acceptance: account.tos_acceptance,
2572
+ type: account.type,
2573
+ // More attributes
2574
+ business_profile: account.business_profile ?? null,
2575
+ charges_enabled: account.charges_enabled,
2576
+ controller: account.controller ?? null,
2577
+ created: account.created,
2578
+ default_currency: account.default_currency,
2579
+ details_submitted: account.details_submitted,
2580
+ external_accounts: account.external_accounts ?? null,
2581
+ future_requirements: account.future_requirements ?? null,
2582
+ groups: account.groups ?? null,
2583
+ // Preview feature
2584
+ payouts_enabled: account.payouts_enabled,
2585
+ settings: account.settings ?? null
2586
+ };
2587
+ return object;
2588
+ };
2589
+ const AccountSchema = {
2590
+ id: v.string(),
2591
+ object: v.string(),
2592
+ business_type: v.optional(
2593
+ v.union(
2594
+ v.literal("company"),
2595
+ v.literal("government_entity"),
2596
+ // US only
2597
+ v.literal("individual"),
2598
+ v.literal("non_profit"),
2599
+ v.null()
2600
+ )
2601
+ ),
2602
+ // capabilities: very wide set of keys; keep as any for now
2603
+ // TODO: model capability keys you care about as v.optional(v.union(...))
2604
+ capabilities: v.optional(v.any()),
2605
+ // company: large nested structure with many optional fields
2606
+ // TODO: model company subfields as needed
2607
+ company: v.optional(v.any()),
2608
+ country: v.optional(v.string()),
2609
+ email: v.optional(nullablestring()),
2610
+ // individual: only present when business_type = "individual"
2611
+ // TODO: model individual subfields as needed
2612
+ individual: v.optional(v.any()),
2613
+ metadata: v.optional(v.union(metadata(), v.null())),
2614
+ // requirements: complex nested structure
2615
+ // TODO: model requirements subfields as needed
2616
+ requirements: v.optional(v.any()),
2617
+ // tos_acceptance exists (not nullable in Stripe docs), but fields can be null
2618
+ // TODO: if you want strict typing, model the subfields
2619
+ tos_acceptance: v.any(),
2620
+ type: v.union(
2621
+ v.literal("custom"),
2622
+ v.literal("express"),
2623
+ v.literal("none"),
2624
+ v.literal("standard")
2625
+ ),
2626
+ // More attributes
2627
+ // TODO: model business_profile subfields as needed
2628
+ business_profile: v.optional(v.any()),
2629
+ charges_enabled: v.boolean(),
2630
+ // TODO: model controller subfields as needed
2631
+ controller: v.optional(v.any()),
2632
+ created: v.optional(v.number()),
2633
+ default_currency: v.optional(v.string()),
2634
+ details_submitted: v.boolean(),
2635
+ // TODO: model external_accounts list object as needed
2636
+ external_accounts: v.optional(v.any()),
2637
+ // TODO: model future_requirements subfields as needed
2638
+ future_requirements: v.optional(v.any()),
2639
+ // Preview feature (expandable)
2640
+ // TODO: model groups if you rely on it
2641
+ groups: v.optional(v.any()),
2642
+ payouts_enabled: v.boolean(),
2643
+ // TODO: settings is large
2644
+ settings: v.optional(v.any())
2645
+ };
2646
+ v.object(AccountSchema);
2647
+ const BillingPortalConfigurationStripeToConvex = (configuration) => {
2648
+ const object = {
2649
+ id: configuration.id,
2650
+ object: configuration.object,
2651
+ active: configuration.active,
2652
+ application: typeof configuration.application === "string" ? configuration.application : null,
2653
+ business_profile: {
2654
+ headline: configuration.business_profile.headline,
2655
+ privacy_policy_url: configuration.business_profile.privacy_policy_url,
2656
+ terms_of_service_url: configuration.business_profile.terms_of_service_url
2505
2657
  },
2506
- portal: config.portal || {
2507
- business_profile: {
2508
- headline: void 0,
2509
- privacy_policy_url: void 0,
2510
- terms_of_service_url: void 0
2658
+ created: configuration.created,
2659
+ default_return_url: configuration.default_return_url,
2660
+ features: {
2661
+ customer_update: {
2662
+ allowed_updated: configuration.features.customer_update.allowed_updates,
2663
+ enabled: configuration.features.customer_update.enabled
2511
2664
  },
2512
- features: {
2513
- customer_update: {
2514
- enabled: true,
2515
- allowed_updates: ["email", "address", "shipping", "phone", "name"]
2516
- },
2517
- invoice_history: {
2518
- enabled: true
2519
- },
2520
- payment_method_update: {
2521
- enabled: true
2522
- },
2523
- subscription_cancel: {
2524
- enabled: true,
2525
- mode: "at_period_end",
2526
- cancellation_reason: {
2527
- enabled: true,
2528
- options: [
2529
- "too_expensive",
2530
- "missing_features",
2531
- "switched_service",
2532
- "unused",
2533
- "customer_service",
2534
- "too_complex",
2535
- "low_quality",
2536
- "other"
2537
- ]
2538
- }
2665
+ invoice_history: {
2666
+ enabled: configuration.features.invoice_history.enabled
2667
+ },
2668
+ payment_method_update: {
2669
+ enabled: configuration.features.payment_method_update.enabled
2670
+ // payment_method_configuration:
2671
+ // configuration.features.payment_method_update.enabled,
2672
+ },
2673
+ subscription_cancel: {
2674
+ cancellation_reason: {
2675
+ enabled: configuration.features.subscription_cancel.cancellation_reason.enabled,
2676
+ options: configuration.features.subscription_cancel.cancellation_reason.options
2539
2677
  },
2540
- subscription_update: {
2541
- enabled: false,
2542
- default_allowed_updates: [],
2543
- proration_behavior: "none",
2544
- products: []
2678
+ enabled: configuration.features.subscription_cancel.enabled,
2679
+ mode: configuration.features.subscription_cancel.mode,
2680
+ proration_behavior: configuration.features.subscription_cancel.proration_behavior
2681
+ },
2682
+ subscription_update: {
2683
+ default_allowed_updates: configuration.features.subscription_update.default_allowed_updates,
2684
+ enabled: configuration.features.subscription_update.enabled,
2685
+ products: configuration.features.subscription_update.products,
2686
+ proration_behavior: configuration.features.subscription_update.proration_behavior,
2687
+ schedule_at_period_end: {
2688
+ conditions: configuration.features.subscription_update.schedule_at_period_end.conditions
2545
2689
  }
2690
+ // trial_updated_behavior:
2691
+ // configuration.features.subscription_update.trial_updated_behavior,
2546
2692
  }
2547
- }
2548
- };
2549
- };
2550
- const normalizeOptions = (options) => {
2551
- return {
2552
- ...options,
2553
- store: options.store || "store",
2554
- debug: options.debug || false,
2555
- logger: options.logger || new Logger(options.debug || false),
2556
- base: options.base || "stripe"
2693
+ },
2694
+ is_default: configuration.is_default,
2695
+ livemode: configuration.livemode,
2696
+ login_page: {
2697
+ enabled: configuration.login_page.enabled,
2698
+ url: configuration.login_page.url
2699
+ },
2700
+ metadata: configuration.metadata,
2701
+ name: configuration.name,
2702
+ updated: configuration.updated
2557
2703
  };
2558
- };
2559
- const defineActionCallableFunction = (spec) => spec;
2560
- const defineActionImplementation = (spec) => spec;
2561
- const defineMutationImplementation = (spec) => spec;
2562
- const nullablestring = () => v.union(v.string(), v.null());
2563
- const nullableboolean = () => v.union(v.boolean(), v.null());
2564
- const nullablenumber = () => v.union(v.number(), v.null());
2565
- const metadata = () => v.record(v.string(), v.union(v.string(), v.number(), v.null()));
2566
- const optionalnullableobject = (object) => v.optional(v.union(v.object(object), v.null()));
2567
- const optionalany = () => v.optional(v.any());
2568
- async function deleteById(context, table, indexName, idField, idValue) {
2569
- const existing = await context.db.query(table).withIndex(indexName, (q) => q.eq(idField, idValue)).unique();
2570
- if (existing) {
2571
- await context.db.delete(existing._id);
2572
- return true;
2573
- }
2574
- return false;
2575
- }
2576
- async function selectAll(context, table) {
2577
- return await context.db.query(table).collect();
2578
- }
2579
- async function selectById(context, table, id) {
2580
- return await context.db.get(id);
2581
- }
2582
- async function selectOne(context, table, indexName, field, value) {
2583
- return await context.db.query(table).withIndex(indexName, (q) => q.eq(field, value)).unique();
2584
- }
2585
- async function upsert(context, table, indexName, idField, data) {
2586
- const existing = await context.db.query(table).withIndex(indexName, (q) => q.eq(idField, data[idField])).unique();
2587
- if (existing) {
2588
- await context.db.patch(existing._id, {
2589
- ...data,
2590
- lastSyncedAt: Date.now()
2591
- });
2592
- return existing._id;
2593
- } else {
2594
- return await context.db.insert(table, {
2595
- ...data,
2596
- lastSyncedAt: Date.now()
2597
- });
2598
- }
2599
- }
2600
- async function insert(context, table, data) {
2601
- return await context.db.insert(table, {
2602
- ...data,
2603
- lastSyncedAt: Date.now()
2604
- });
2605
- }
2606
- const StoreImplementation = defineMutationImplementation({
2607
- name: "store",
2608
- args: {
2609
- operation: v.string(),
2610
- table: v.string(),
2611
- indexName: v.optional(v.string()),
2612
- idField: v.optional(v.string()),
2613
- data: v.optional(v.any()),
2614
- idValue: v.optional(v.any()),
2615
- field: v.optional(v.string()),
2616
- value: v.optional(v.any()),
2617
- id: v.optional(v.any())
2618
- },
2619
- handler: async (context, args, configuration) => {
2620
- const allowed = /* @__PURE__ */ new Set([
2621
- "upsert",
2622
- "insert",
2623
- "deleteById",
2624
- "selectOne",
2625
- "selectById",
2626
- "selectAll"
2627
- ]);
2628
- if (!allowed.has(args.operation)) {
2629
- throw new Error(`Unknown op "${args.operation}"`);
2630
- }
2631
- const table = args.table;
2632
- switch (args.operation) {
2633
- case "upsert": {
2634
- if (!args.indexName) {
2635
- throw new Error('Missing "indexName" for upsert');
2636
- }
2637
- if (!args.idField) {
2638
- throw new Error('Missing "idField" for upsert');
2639
- }
2640
- if (args.data == null) {
2641
- throw new Error('Missing "data" for upsert');
2642
- }
2643
- const upsertIndexName = args.indexName;
2644
- const upsertIdField = args.idField;
2645
- const upsertData = args.data;
2646
- const id = await upsert(
2647
- context,
2648
- table,
2649
- upsertIndexName,
2650
- upsertIdField,
2651
- upsertData
2652
- );
2653
- if (configuration.callback && configuration.callback.unstable__afterChange)
2654
- try {
2655
- await configuration.callback.unstable__afterChange(
2656
- context,
2657
- "upsert",
2658
- // TODO: remove any
2659
- { table }
2660
- );
2661
- } catch (error) {
2662
- console.error("[unstable__afterChange]:", error);
2663
- }
2664
- return { id };
2665
- }
2666
- case "insert": {
2667
- if (args.data == null) {
2668
- throw new Error('Missing "data" for insert');
2669
- }
2670
- const insertData = args.data;
2671
- const id = await insert(context, table, insertData);
2672
- if (configuration.callback && configuration.callback.unstable__afterChange)
2673
- try {
2674
- await configuration.callback.unstable__afterChange(
2675
- context,
2676
- "insert",
2677
- // TODO: remove any
2678
- { table }
2679
- );
2680
- } catch (error) {
2681
- console.error("[unstable__afterChange]:", error);
2682
- }
2683
- return { id };
2684
- }
2685
- case "deleteById": {
2686
- if (!args.indexName) {
2687
- throw new Error('Missing "indexName" for deleteById');
2688
- }
2689
- if (!args.idField) {
2690
- throw new Error('Missing "idField" for deleteById');
2691
- }
2692
- if (typeof args.idValue === "undefined") {
2693
- throw new Error('Missing "idValue" for deleteById');
2694
- }
2695
- const deleteByIdIndexName = args.indexName;
2696
- const deleteByIdIdField = args.idField;
2697
- const deleteByIdIdValue = args.idValue;
2698
- const deleted = await deleteById(
2699
- context,
2700
- table,
2701
- deleteByIdIndexName,
2702
- deleteByIdIdField,
2703
- deleteByIdIdValue
2704
- );
2705
- if (configuration.callback && configuration.callback.unstable__afterChange)
2706
- try {
2707
- await configuration.callback.unstable__afterChange(
2708
- context,
2709
- "delete",
2710
- // TODO: remove any
2711
- { table }
2712
- );
2713
- } catch (error) {
2714
- console.error("[unstable__afterChange]:", error);
2715
- }
2716
- return { deleted };
2717
- }
2718
- case "selectOne": {
2719
- if (!args.indexName) {
2720
- throw new Error('Missing "indexName" for selectOne');
2721
- }
2722
- if (!args.field) {
2723
- throw new Error('Missing "field" for selectOne');
2724
- }
2725
- if (typeof args.value === "undefined") {
2726
- throw new Error('Missing "value" for selectOne');
2727
- }
2728
- const selectOneIndexName = args.indexName;
2729
- const selectOneField = args.field;
2730
- const selectOneValue = args.value;
2731
- const doc = await selectOne(
2732
- context,
2733
- table,
2734
- selectOneIndexName,
2735
- selectOneField,
2736
- selectOneValue
2737
- );
2738
- return { doc };
2739
- }
2740
- case "selectById": {
2741
- if (args.id == null) {
2742
- throw new Error('Missing "id" for selectById');
2743
- }
2744
- const doc = await selectById(context, table, args.id);
2745
- return { doc };
2746
- }
2747
- case "selectAll": {
2748
- const docs = await selectAll(context, table);
2749
- return { docs };
2750
- }
2751
- }
2752
- }
2753
- });
2754
- async function storeDispatchTyped(args, context, configuration, options) {
2755
- return await context.runMutation(
2756
- `${options.base}:${options.store}`,
2757
- args
2758
- );
2759
- }
2760
- const CreateAccountImplementation = defineActionCallableFunction({
2761
- name: "createAccount",
2762
- handler: async (context, args, stripeOptions, configuration, options) => {
2763
- const stripe = new Stripe(configuration.stripe.secret_key, {
2764
- apiVersion: "2025-08-27.basil"
2765
- });
2766
- const stripeAccount = (await storeDispatchTyped(
2767
- {
2768
- operation: "selectOne",
2769
- table: "stripeAccounts",
2770
- indexName: "byEntityId",
2771
- field: "entityId",
2772
- value: args.entityId
2773
- },
2774
- context,
2775
- configuration,
2776
- options
2777
- )).doc;
2778
- if (stripeAccount) {
2779
- return stripeAccount;
2780
- } else {
2781
- const account = await stripe.accounts.create(
2782
- {
2783
- ...{
2784
- ...args,
2785
- entityId: void 0
2786
- },
2787
- metadata: {
2788
- ...args.metadata || {},
2789
- entityId: args.entityId
2790
- }
2791
- },
2792
- Object.keys(stripeOptions).length === 0 ? void 0 : stripeOptions
2793
- );
2794
- const data = {
2795
- entityId: args.entityId,
2796
- accountId: account.id,
2797
- stripe: {
2798
- id: account.id,
2799
- object: account.object,
2800
- business_type: account.business_type,
2801
- capabilities: account.capabilities,
2802
- company: account.company,
2803
- country: account.country,
2804
- email: account.email,
2805
- individual: account.individual,
2806
- metadata: account.metadata,
2807
- requirements: account.requirements,
2808
- tos_acceptance: account.tos_acceptance,
2809
- type: account.type,
2810
- business_profile: account.business_profile,
2811
- charges_enabled: account.charges_enabled,
2812
- controller: account.controller,
2813
- created: account.created,
2814
- default_currency: account.default_currency,
2815
- details_submitted: account.details_submitted,
2816
- external_accounts: account.external_accounts,
2817
- future_requirements: account.future_requirements,
2818
- groups: account.groups,
2819
- payouts_enabled: account.payouts_enabled,
2820
- settings: account.settings
2821
- },
2822
- lastSyncedAt: Date.now()
2823
- };
2824
- const response = await storeDispatchTyped(
2825
- {
2826
- operation: "upsert",
2827
- table: "stripeAccounts",
2828
- indexName: "byEntityId",
2829
- idField: "entityId",
2830
- data
2831
- },
2832
- context,
2833
- configuration,
2834
- options
2835
- );
2836
- return {
2837
- _id: response.id,
2838
- ...data,
2839
- _creationTime: (/* @__PURE__ */ new Date()).getTime()
2840
- };
2841
- }
2842
- }
2843
- });
2844
- function defineRedirectHandler(handler) {
2845
- return handler;
2846
- }
2847
- const PayReturnImplementation$1 = defineRedirectHandler({
2848
- origins: ["create-account-link-return", "create-account-link-refresh"],
2849
- data: {
2850
- accountId: v.string()
2851
- },
2852
- handle: async (origin, context, data, configuration, options) => {
2853
- }
2854
- });
2855
- const __vite_glob_0_0$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2856
- __proto__: null,
2857
- PayReturnImplementation: PayReturnImplementation$1
2858
- }, Symbol.toStringTag, { value: "Module" }));
2859
- const SubscriptionStripeToConvex = (subscription) => {
2860
- const object = {
2861
- ...subscription
2862
- };
2863
- return object;
2864
- };
2865
- v.any();
2866
- const SubscriptionObject = v.any();
2867
- const SubscriptionSyncImplementation = defineActionImplementation({
2868
- args: v.object({
2869
- customerId: v.string(),
2870
- accountId: v.optional(v.string())
2871
- }),
2872
- name: "syncSubscription",
2873
- handler: async (context, args, configuration, options) => {
2874
- const stripe = new Stripe(configuration.stripe.secret_key, {
2875
- apiVersion: "2025-08-27.basil"
2876
- });
2877
- const customerId = args.customerId;
2878
- const subscriptions = await stripe.subscriptions.list(
2879
- {
2880
- customer: customerId,
2881
- limit: 1,
2882
- status: "all",
2883
- expand: ["data.default_payment_method"]
2884
- },
2885
- { stripeAccount: args.accountId }
2886
- );
2887
- if (subscriptions.data.length === 0) {
2888
- await storeDispatchTyped(
2889
- {
2890
- operation: "upsert",
2891
- table: "stripeSubscriptions",
2892
- indexName: "byCustomerId",
2893
- idField: "customerId",
2894
- data: {
2895
- subscriptionId: null,
2896
- customerId,
2897
- stripe: null,
2898
- lastSyncedAt: Date.now(),
2899
- accountId: args.accountId
2900
- }
2901
- },
2902
- context,
2903
- configuration,
2904
- options
2905
- );
2906
- return null;
2907
- }
2908
- const subscription = subscriptions.data[0];
2909
- await storeDispatchTyped(
2910
- {
2911
- operation: "upsert",
2912
- table: "stripeSubscriptions",
2913
- indexName: "byCustomerId",
2914
- idField: "customerId",
2915
- data: {
2916
- accountId: args.accountId,
2917
- subscriptionId: subscription.id,
2918
- customerId,
2919
- stripe: SubscriptionStripeToConvex(subscription),
2920
- lastSyncedAt: Date.now()
2921
- }
2922
- },
2923
- context,
2924
- configuration,
2925
- options
2926
- );
2927
- return subscription;
2928
- }
2929
- });
2930
- const PayReturnImplementation = defineRedirectHandler({
2931
- origins: ["pay-cancel", "pay-success", "pay-return"],
2932
- data: {
2933
- accountId: v.optional(v.string()),
2934
- entityId: v.string(),
2935
- customerId: v.string(),
2936
- referenceId: v.string()
2937
- },
2938
- handle: async (origin, context, data, configuration, options) => {
2939
- const customer = await storeDispatchTyped(
2940
- {
2941
- operation: "selectOne",
2942
- table: "stripeCustomers",
2943
- indexName: "byEntityId",
2944
- field: "entityId",
2945
- value: data.entityId
2946
- },
2947
- context,
2948
- configuration,
2949
- options
2950
- );
2951
- const customerId = customer?.doc?.customerId || null;
2952
- if (customerId) {
2953
- await SubscriptionSyncImplementation.handler(
2954
- context,
2955
- { customerId, accountId: data.accountId },
2956
- configuration,
2957
- options
2958
- );
2959
- } else {
2960
- options.logger.warn(
2961
- "Potential redirect abuse detected. No customerId associated with provided entityId " + data.entityId
2962
- );
2963
- }
2964
- }
2965
- });
2966
- const __vite_glob_0_1$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2967
- __proto__: null,
2968
- PayReturnImplementation
2969
- }, Symbol.toStringTag, { value: "Module" }));
2970
- const PortalReturnImplementation = defineRedirectHandler({
2971
- origins: ["portal-return"],
2972
- data: {
2973
- accountId: v.optional(v.string()),
2974
- entityId: v.string()
2975
- },
2976
- handle: async (origin, context, data, configuration, options) => {
2977
- const customer = await storeDispatchTyped(
2978
- {
2979
- operation: "selectOne",
2980
- table: "stripeCustomers",
2981
- indexName: "byEntityId",
2982
- field: "entityId",
2983
- value: data.entityId
2984
- },
2985
- context,
2986
- configuration,
2987
- options
2988
- );
2989
- const customerId = customer?.doc?.customerId || null;
2990
- if (customerId) {
2991
- await SubscriptionSyncImplementation.handler(
2992
- context,
2993
- { customerId, accountId: data.accountId },
2994
- configuration,
2995
- options
2996
- );
2997
- } else {
2998
- options.logger.warn(
2999
- "Potential redirect abuse detected. No customerId associated with provided entityId " + data.entityId
3000
- );
3001
- }
3002
- }
3003
- });
3004
- const __vite_glob_0_2$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3005
- __proto__: null,
3006
- PortalReturnImplementation
3007
- }, Symbol.toStringTag, { value: "Module" }));
3008
- const SubscribeReturnImplementation = defineRedirectHandler({
3009
- origins: ["subscribe-cancel", "subscribe-success", "subscribe-return"],
3010
- data: {
3011
- accountId: v.optional(v.string()),
3012
- entityId: v.string()
3013
- },
3014
- handle: async (origin, context, data, configuration, options) => {
3015
- const customer = await storeDispatchTyped(
3016
- {
3017
- operation: "selectOne",
3018
- table: "stripeCustomers",
3019
- indexName: "byEntityId",
3020
- field: "entityId",
3021
- value: data.entityId
3022
- },
3023
- context,
3024
- configuration,
3025
- options
3026
- );
3027
- const customerId = customer?.doc?.customerId || null;
3028
- if (customerId) {
3029
- await SubscriptionSyncImplementation.handler(
3030
- context,
3031
- { customerId, accountId: data.accountId },
3032
- configuration,
3033
- options
3034
- );
3035
- } else {
3036
- options.logger.warn(
3037
- "Potential redirect abuse detected. No customerId associated with provided entityId " + data.entityId
3038
- );
3039
- }
3040
- }
3041
- });
3042
- const __vite_glob_0_3$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3043
- __proto__: null,
3044
- SubscribeReturnImplementation
3045
- }, Symbol.toStringTag, { value: "Module" }));
3046
- const HANDLERS_MODULES$2 = Object.values(
3047
- [
3048
- __vite_glob_0_0$2,
3049
- __vite_glob_0_1$2,
3050
- __vite_glob_0_2$2,
3051
- __vite_glob_0_3$2
3052
- ]
3053
- );
3054
- if (HANDLERS_MODULES$2.some((handler) => Object.keys(handler).length > 1))
3055
- throw new Error(
3056
- "Each redirect handler file should only have one export / default export"
3057
- );
3058
- const REDIRECT_HANDLERS = HANDLERS_MODULES$2.map(
3059
- (exports$1) => Object.values(exports$1)[0]
3060
- );
3061
- if (REDIRECT_HANDLERS.some(
3062
- (handler) => !["origins", "data", "handle"].every((key) => key in handler)
3063
- ))
3064
- throw new Error(
3065
- "Each redirect handler file should export a valid implementation"
3066
- );
3067
- const originToHandlers = /* @__PURE__ */ new Map();
3068
- REDIRECT_HANDLERS.forEach((handler, handlerIndex) => {
3069
- handler.origins.forEach((origin) => {
3070
- if (originToHandlers.has(origin)) {
3071
- throw new Error(
3072
- `Origin "${origin}" is used by multiple handlers (handler indices: ${originToHandlers.get(origin)}, ${handlerIndex})`
3073
- );
3074
- }
3075
- originToHandlers.set(origin, handlerIndex);
3076
- });
3077
- });
3078
- function backendBaseUrl(configuration) {
3079
- return process.env.CONVEX_SITE_URL;
3080
- }
3081
- function toBase64Url(input) {
3082
- const buffer = typeof input === "string" ? new TextEncoder().encode(input) : new Uint8Array(input);
3083
- let binary = "";
3084
- for (let i = 0; i < buffer.length; i++) {
3085
- binary += String.fromCharCode(buffer[i]);
3086
- }
3087
- const base64 = btoa(binary);
3088
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
3089
- }
3090
- function fromBase64Url(input) {
3091
- const b64 = input.replace(/-/g, "+").replace(/_/g, "/");
3092
- const padding = b64.length % 4 === 0 ? 0 : 4 - b64.length % 4;
3093
- const padded = b64 + "=".repeat(padding);
3094
- const binary = atob(padded);
3095
- const bytes = new Uint8Array(binary.length);
3096
- for (let i = 0; i < binary.length; i++) {
3097
- bytes[i] = binary.charCodeAt(i);
3098
- }
3099
- return bytes;
3100
- }
3101
- async function signData(secret, data) {
3102
- const encoder = new TextEncoder();
3103
- const keyData = encoder.encode(secret);
3104
- const messageData = encoder.encode(data);
3105
- const key = await crypto.subtle.importKey(
3106
- "raw",
3107
- keyData,
3108
- { name: "HMAC", hash: "SHA-256" },
3109
- false,
3110
- ["sign"]
3111
- );
3112
- return await crypto.subtle.sign("HMAC", key, messageData);
3113
- }
3114
- async function timingSafeEqual(a, b) {
3115
- if (a.byteLength !== b.byteLength) {
3116
- return false;
3117
- }
3118
- const aArray = new Uint8Array(a);
3119
- const bArray = new Uint8Array(b);
3120
- let result = 0;
3121
- for (let i = 0; i < aArray.length; i++) {
3122
- result |= aArray[i] ^ bArray[i];
3123
- }
3124
- return result === 0;
3125
- }
3126
- async function buildSignedReturnUrl({
3127
- configuration,
3128
- origin,
3129
- failureUrl,
3130
- targetUrl,
3131
- data
3132
- }) {
3133
- const payload = {
3134
- origin,
3135
- data,
3136
- targetUrl,
3137
- failureUrl,
3138
- exp: Date.now() + configuration.redirectTtlMs
3139
- };
3140
- const data_ = toBase64Url(JSON.stringify(payload));
3141
- const expected = await signData(
3142
- configuration.stripe.account_webhook_secret,
3143
- data_
3144
- );
3145
- const signature = toBase64Url(expected);
3146
- const base = `${backendBaseUrl()}/stripe/return/${origin}`;
3147
- const url = new URL(base);
3148
- url.searchParams.set("data", data_);
3149
- url.searchParams.set("signature", signature);
3150
- return url.toString();
3151
- }
3152
- async function decodeSignedPayload({
3153
- secret,
3154
- data,
3155
- signature
3156
- }) {
3157
- try {
3158
- const expected = await signData(secret, data);
3159
- const provided = fromBase64Url(signature);
3160
- if (provided.byteLength !== expected.byteLength) {
3161
- return { error: "Invalid signature length" };
3162
- }
3163
- const isValid = await timingSafeEqual(provided.buffer, expected);
3164
- if (!isValid) {
3165
- return { error: "Invalid signature" };
3166
- }
3167
- const decodedBytes = fromBase64Url(data);
3168
- const decoder = new TextDecoder();
3169
- const decodedPayload = JSON.parse(
3170
- decoder.decode(decodedBytes)
3171
- );
3172
- return { data: decodedPayload };
3173
- } catch (err) {
3174
- return { error: "Invalid token" };
3175
- }
3176
- }
3177
- REDIRECT_HANDLERS.map(
3178
- (handler) => handler.origins
3179
- ).flat();
3180
- const redirectImplementation = async (configuration, options, context, request) => {
3181
- const url = new URL(request.url);
3182
- const segments = url.pathname.split("/").filter(Boolean);
3183
- const origin_ = segments[segments.length - 1];
3184
- if (!origin_ || !REDIRECT_HANDLERS.map((handler) => handler.origins).flat().includes(origin_)) {
3185
- return new Response("Invalid return origin", { status: 400 });
3186
- }
3187
- const origin = origin_;
3188
- const data = url.searchParams.get("data");
3189
- const signature = url.searchParams.get("signature");
3190
- if (!data || !signature) {
3191
- return new Response("Missing signature", { status: 400 });
3192
- }
3193
- const response = await decodeSignedPayload({
3194
- secret: configuration.stripe.account_webhook_secret,
3195
- data,
3196
- signature
3197
- });
3198
- if (response.error) {
3199
- return new Response(response.error, { status: 400 });
3200
- }
3201
- const decoded = response.data;
3202
- if (decoded.origin !== origin) {
3203
- if (decoded.failureUrl) {
3204
- const failureUrl = new URL(decoded.failureUrl);
3205
- failureUrl.searchParams.set("reason", "origin_mismatch");
3206
- return new Response(null, {
3207
- status: 302,
3208
- headers: { Location: failureUrl.toString() }
3209
- });
3210
- }
3211
- return new Response("Origin mismatch", { status: 400 });
3212
- }
3213
- if (!decoded.exp || Date.now() > decoded.exp) {
3214
- if (decoded.failureUrl) {
3215
- const failureUrl = new URL(decoded.failureUrl);
3216
- failureUrl.searchParams.set("reason", "link_expired");
3217
- return new Response(null, {
3218
- status: 302,
3219
- headers: { Location: failureUrl.toString() }
3220
- });
3221
- }
3222
- return new Response("Link expired", { status: 400 });
3223
- }
3224
- if (typeof decoded.targetUrl !== "string" || decoded.targetUrl.length === 0) {
3225
- if (decoded.failureUrl) {
3226
- const failureUrl = new URL(decoded.failureUrl);
3227
- failureUrl.searchParams.set("reason", "invalid_target");
3228
- return new Response(null, {
3229
- status: 302,
3230
- headers: { Location: failureUrl.toString() }
3231
- });
3232
- }
3233
- return new Response("Invalid target", { status: 400 });
3234
- }
3235
- for (const handler of REDIRECT_HANDLERS) {
3236
- if (handler.origins.includes(origin)) {
3237
- try {
3238
- await handler.handle(
3239
- origin,
3240
- context,
3241
- decoded.data,
3242
- configuration,
3243
- options
3244
- );
3245
- } catch (error) {
3246
- options.logger.error(`[STRIPE RETURN ${origin}](Error): ${error}`);
3247
- }
3248
- return new Response(null, {
3249
- status: 302,
3250
- headers: { Location: decoded.targetUrl }
3251
- });
3252
- }
3253
- }
3254
- return new Response(null, {
3255
- status: 302,
3256
- headers: { Location: decoded.targetUrl }
3257
- });
3258
- };
3259
- const CreateAccountLinkImplementation = defineActionCallableFunction({
3260
- name: "createAccountLink",
3261
- handler: async (context, args, stripeOptions, configuration, options) => {
3262
- const stripe = new Stripe(configuration.stripe.secret_key, {
3263
- apiVersion: "2025-08-27.basil"
3264
- });
3265
- const refreshUrl = await buildSignedReturnUrl({
3266
- configuration,
3267
- origin: "create-account-link-refresh",
3268
- data: {
3269
- accountId: args.account
3270
- },
3271
- failureUrl: args.failure_url,
3272
- targetUrl: args.refresh_url
3273
- });
3274
- const returnUrl = await buildSignedReturnUrl({
3275
- configuration,
3276
- origin: "create-account-link-return",
3277
- data: {
3278
- accountId: args.account
3279
- },
3280
- failureUrl: args.failure_url,
3281
- targetUrl: args.return_url
3282
- });
3283
- const accountLink = await stripe.accountLinks.create(
3284
- {
3285
- ...{
3286
- ...args
3287
- },
3288
- account: args.account,
3289
- refresh_url: refreshUrl,
3290
- return_url: returnUrl
3291
- },
3292
- Object.keys(stripeOptions).length === 0 ? void 0 : stripeOptions
3293
- );
3294
- return accountLink;
3295
- }
3296
- });
3297
- const CreateCustomerImplementation = defineActionCallableFunction({
3298
- name: "createCustomer",
3299
- handler: async (context, args, stripeOptions, configuration, options) => {
3300
- const stripe = new Stripe(configuration.stripe.secret_key, {
3301
- apiVersion: "2025-08-27.basil"
3302
- });
3303
- const stripeCustomer = (await storeDispatchTyped(
3304
- {
3305
- operation: "selectOne",
3306
- table: "stripeCustomers",
3307
- indexName: "byEntityId",
3308
- field: "entityId",
3309
- value: args.entityId
3310
- },
3311
- context,
3312
- configuration,
3313
- options
3314
- )).doc;
3315
- if (stripeCustomer) {
3316
- return stripeCustomer;
3317
- } else {
3318
- const customer = await stripe.customers.create(
3319
- {
3320
- ...{
3321
- ...args,
3322
- entityId: void 0
3323
- },
3324
- metadata: {
3325
- ...args.metadata || {},
3326
- entityId: args.entityId
3327
- }
3328
- },
3329
- Object.keys(stripeOptions).length === 0 ? void 0 : stripeOptions
3330
- );
3331
- const data = {
3332
- entityId: args.entityId,
3333
- customerId: customer.id,
3334
- stripe: {
3335
- id: customer.id,
3336
- address: customer.address,
3337
- description: customer.description,
3338
- email: customer.email,
3339
- metadata: customer.metadata,
3340
- name: customer.name,
3341
- phone: customer.phone,
3342
- shipping: customer.shipping,
3343
- tax: customer.tax,
3344
- object: customer.object,
3345
- balance: customer.balance,
3346
- cash_balance: customer.cash_balance,
3347
- created: customer.created,
3348
- currency: customer.currency,
3349
- default_source: typeof customer.default_source === "string" ? customer.default_source : customer.default_source?.id,
3350
- delinquent: customer.delinquent,
3351
- discount: customer.discount,
3352
- invoice_credit_balance: customer.invoice_credit_balance,
3353
- invoice_prefix: customer.invoice_prefix,
3354
- invoice_settings: customer.invoice_settings,
3355
- livemode: customer.livemode,
3356
- next_invoice_sequence: customer.next_invoice_sequence,
3357
- preferred_locales: customer.preferred_locales,
3358
- sources: customer.sources,
3359
- subscriptions: customer.subscriptions,
3360
- tax_exempt: customer.tax_exempt,
3361
- tax_ids: customer.tax_ids,
3362
- test_clock: typeof customer.test_clock === "string" ? customer.test_clock : customer.test_clock?.id
3363
- },
3364
- lastSyncedAt: Date.now()
3365
- };
3366
- const response = await storeDispatchTyped(
3367
- {
3368
- operation: "upsert",
3369
- table: "stripeCustomers",
3370
- indexName: "byEntityId",
3371
- idField: "entityId",
3372
- data
3373
- },
3374
- context,
3375
- configuration,
3376
- options
3377
- );
3378
- return {
3379
- _id: response.id,
3380
- ...data,
3381
- _creationTime: (/* @__PURE__ */ new Date()).getTime()
3382
- };
3383
- }
3384
- }
3385
- });
3386
- const AccountStripeToConvex = (account) => {
3387
- const object = {
3388
- id: account.id,
3389
- object: account.object,
3390
- business_type: account.business_type,
3391
- capabilities: account.capabilities ?? null,
3392
- company: account.company ?? null,
3393
- country: account.country,
3394
- email: account.email,
3395
- individual: account.individual ?? null,
3396
- metadata: account.metadata ?? null,
3397
- requirements: account.requirements ?? null,
3398
- tos_acceptance: account.tos_acceptance,
3399
- type: account.type,
3400
- // More attributes
3401
- business_profile: account.business_profile ?? null,
3402
- charges_enabled: account.charges_enabled,
3403
- controller: account.controller ?? null,
3404
- created: account.created,
3405
- default_currency: account.default_currency,
3406
- details_submitted: account.details_submitted,
3407
- external_accounts: account.external_accounts ?? null,
3408
- future_requirements: account.future_requirements ?? null,
3409
- groups: account.groups ?? null,
3410
- // Preview feature
3411
- payouts_enabled: account.payouts_enabled,
3412
- settings: account.settings ?? null
3413
- };
3414
- return object;
3415
- };
3416
- const AccountSchema = {
3417
- id: v.string(),
3418
- object: v.string(),
3419
- business_type: v.optional(
3420
- v.union(
3421
- v.literal("company"),
3422
- v.literal("government_entity"),
3423
- // US only
3424
- v.literal("individual"),
3425
- v.literal("non_profit"),
3426
- v.null()
3427
- )
3428
- ),
3429
- // capabilities: very wide set of keys; keep as any for now
3430
- // TODO: model capability keys you care about as v.optional(v.union(...))
3431
- capabilities: v.optional(v.any()),
3432
- // company: large nested structure with many optional fields
3433
- // TODO: model company subfields as needed
3434
- company: v.optional(v.any()),
3435
- country: v.optional(v.string()),
3436
- email: v.optional(nullablestring()),
3437
- // individual: only present when business_type = "individual"
3438
- // TODO: model individual subfields as needed
3439
- individual: v.optional(v.any()),
3440
- metadata: v.optional(v.union(metadata(), v.null())),
3441
- // requirements: complex nested structure
3442
- // TODO: model requirements subfields as needed
3443
- requirements: v.optional(v.any()),
3444
- // tos_acceptance exists (not nullable in Stripe docs), but fields can be null
3445
- // TODO: if you want strict typing, model the subfields
3446
- tos_acceptance: v.any(),
3447
- type: v.union(
3448
- v.literal("custom"),
3449
- v.literal("express"),
3450
- v.literal("none"),
3451
- v.literal("standard")
3452
- ),
3453
- // More attributes
3454
- // TODO: model business_profile subfields as needed
3455
- business_profile: v.optional(v.any()),
3456
- charges_enabled: v.boolean(),
3457
- // TODO: model controller subfields as needed
3458
- controller: v.optional(v.any()),
3459
- created: v.optional(v.number()),
3460
- default_currency: v.optional(v.string()),
3461
- details_submitted: v.boolean(),
3462
- // TODO: model external_accounts list object as needed
3463
- external_accounts: v.optional(v.any()),
3464
- // TODO: model future_requirements subfields as needed
3465
- future_requirements: v.optional(v.any()),
3466
- // Preview feature (expandable)
3467
- // TODO: model groups if you rely on it
3468
- groups: v.optional(v.any()),
3469
- payouts_enabled: v.boolean(),
3470
- // TODO: settings is large
3471
- settings: v.optional(v.any())
3472
- };
3473
- v.object(AccountSchema);
3474
- const BillingPortalConfigurationStripeToConvex = (configuration) => {
3475
- const object = {
3476
- id: configuration.id,
3477
- object: configuration.object,
3478
- active: configuration.active,
3479
- application: typeof configuration.application === "string" ? configuration.application : null,
3480
- business_profile: {
3481
- headline: configuration.business_profile.headline,
3482
- privacy_policy_url: configuration.business_profile.privacy_policy_url,
3483
- terms_of_service_url: configuration.business_profile.terms_of_service_url
3484
- },
3485
- created: configuration.created,
3486
- default_return_url: configuration.default_return_url,
3487
- features: {
3488
- customer_update: {
3489
- allowed_updated: configuration.features.customer_update.allowed_updates,
3490
- enabled: configuration.features.customer_update.enabled
3491
- },
3492
- invoice_history: {
3493
- enabled: configuration.features.invoice_history.enabled
3494
- },
3495
- payment_method_update: {
3496
- enabled: configuration.features.payment_method_update.enabled
3497
- // payment_method_configuration:
3498
- // configuration.features.payment_method_update.enabled,
3499
- },
3500
- subscription_cancel: {
3501
- cancellation_reason: {
3502
- enabled: configuration.features.subscription_cancel.cancellation_reason.enabled,
3503
- options: configuration.features.subscription_cancel.cancellation_reason.options
3504
- },
3505
- enabled: configuration.features.subscription_cancel.enabled,
3506
- mode: configuration.features.subscription_cancel.mode,
3507
- proration_behavior: configuration.features.subscription_cancel.proration_behavior
3508
- },
3509
- subscription_update: {
3510
- default_allowed_updates: configuration.features.subscription_update.default_allowed_updates,
3511
- enabled: configuration.features.subscription_update.enabled,
3512
- products: configuration.features.subscription_update.products,
3513
- proration_behavior: configuration.features.subscription_update.proration_behavior,
3514
- schedule_at_period_end: {
3515
- conditions: configuration.features.subscription_update.schedule_at_period_end.conditions
3516
- }
3517
- // trial_updated_behavior:
3518
- // configuration.features.subscription_update.trial_updated_behavior,
3519
- }
3520
- },
3521
- is_default: configuration.is_default,
3522
- livemode: configuration.livemode,
3523
- login_page: {
3524
- enabled: configuration.login_page.enabled,
3525
- url: configuration.login_page.url
3526
- },
3527
- metadata: configuration.metadata,
3528
- name: configuration.name,
3529
- updated: configuration.updated
3530
- };
3531
- return object;
2704
+ return object;
3532
2705
  };
3533
2706
  const BillingPortalConfigurationSchema = {
3534
2707
  id: v.string(),
@@ -6030,6 +5203,14 @@ const SetupIntentSchema = {
6030
5203
  single_use_mandate: v.optional(nullablestring())
6031
5204
  };
6032
5205
  v.object(SetupIntentSchema);
5206
+ const SubscriptionStripeToConvex = (subscription) => {
5207
+ const object = {
5208
+ ...subscription
5209
+ };
5210
+ return object;
5211
+ };
5212
+ v.any();
5213
+ const SubscriptionObject = v.any();
6033
5214
  const SubscriptionScheduleStripeToConvex = (subscriptionSchedule) => {
6034
5215
  const object = {
6035
5216
  id: subscriptionSchedule.id,
@@ -6422,16 +5603,980 @@ const stripeTables = {
6422
5603
  stripe: v.object(CapabilitySchema),
6423
5604
  lastSyncedAt: v.number(),
6424
5605
  accountId: v.optional(v.string())
6425
- }).index("byAccountId", ["accountId"]).index(BY_STRIPE_ID_INDEX_NAME, ["capabilityId"])
5606
+ }).index("byAccountId", ["accountId"]).index(BY_STRIPE_ID_INDEX_NAME, ["capabilityId"])
5607
+ };
5608
+ defineSchema(stripeTables);
5609
+ const syncAllTables = () => Object.fromEntries(
5610
+ Object.keys(stripeTables).map((table) => [table, true])
5611
+ );
5612
+ const syncAllTablesExcept = (tables) => Object.fromEntries(
5613
+ Object.keys(stripeTables).map((table) => [
5614
+ table,
5615
+ !tables.includes(table)
5616
+ ])
5617
+ );
5618
+ const syncOnlyTables = (tables) => Object.fromEntries(
5619
+ Object.keys(stripeTables).map((table) => [
5620
+ table,
5621
+ tables.includes(table)
5622
+ ])
5623
+ );
5624
+ const DEFAULT_CONFIGURATION = {
5625
+ stripe: {
5626
+ version: "2025-08-27.basil",
5627
+ secret_key: "",
5628
+ account_webhook_secret: "",
5629
+ connect_webhook_secret: ""
5630
+ },
5631
+ redirectTtlMs: 15 * 60 * 1e3,
5632
+ detached: false,
5633
+ callbacks: {
5634
+ afterChange: async () => {
5635
+ }
5636
+ },
5637
+ sync: {
5638
+ catalog: {
5639
+ products: [],
5640
+ prices: [],
5641
+ metadataKey: "convex_stripe_key",
5642
+ behavior: {
5643
+ onExisting: "update",
5644
+ onMissingKey: "create"
5645
+ }
5646
+ },
5647
+ tables: {
5648
+ stripeAccounts: true,
5649
+ stripeCapabilities: true,
5650
+ stripeTransfers: true,
5651
+ stripeCoupons: true,
5652
+ stripeCustomers: true,
5653
+ stripePrices: true,
5654
+ stripeProducts: true,
5655
+ stripePromotionCodes: true,
5656
+ stripeSubscriptions: true,
5657
+ stripePayouts: true,
5658
+ stripeCheckoutSessions: true,
5659
+ stripePaymentIntents: true,
5660
+ stripeRefunds: true,
5661
+ stripeInvoices: true,
5662
+ stripeReviews: true,
5663
+ stripeCharges: true,
5664
+ stripeCreditNotes: true,
5665
+ stripeDisputes: true,
5666
+ stripeEarlyFraudWarnings: true,
5667
+ stripePaymentMethods: true,
5668
+ stripePlans: true,
5669
+ stripeSetupIntents: true,
5670
+ stripeSubscriptionSchedules: true,
5671
+ stripeTaxIds: true,
5672
+ stripeMandates: true,
5673
+ stripeBillingPortalConfigurations: true
5674
+ },
5675
+ webhooks: {
5676
+ account: {
5677
+ path: "/stripe/webhook",
5678
+ description: "Convex Stripe Webhook Endpoint",
5679
+ metadata: {}
5680
+ },
5681
+ connect: {
5682
+ path: "/stripe/webhook?connect=true",
5683
+ description: "Convex Stripe Webhook Endpoint",
5684
+ metadata: {}
5685
+ }
5686
+ },
5687
+ portal: {
5688
+ metadata: {},
5689
+ login_page: {
5690
+ enabled: true
5691
+ },
5692
+ default_return_url: "https://example.com/account",
5693
+ expand: ["business_profile"],
5694
+ name: "Customer Portal",
5695
+ business_profile: {
5696
+ headline: "",
5697
+ privacy_policy_url: "",
5698
+ terms_of_service_url: ""
5699
+ },
5700
+ features: {
5701
+ customer_update: {
5702
+ enabled: true,
5703
+ allowed_updates: ["email", "address", "shipping", "phone", "name"]
5704
+ },
5705
+ invoice_history: {
5706
+ enabled: true
5707
+ },
5708
+ payment_method_update: {
5709
+ enabled: true
5710
+ },
5711
+ subscription_cancel: {
5712
+ enabled: true,
5713
+ proration_behavior: "none",
5714
+ mode: "at_period_end",
5715
+ cancellation_reason: {
5716
+ enabled: true,
5717
+ options: [
5718
+ "too_expensive",
5719
+ "missing_features",
5720
+ "switched_service",
5721
+ "unused",
5722
+ "customer_service",
5723
+ "too_complex",
5724
+ "low_quality",
5725
+ "other"
5726
+ ]
5727
+ }
5728
+ },
5729
+ subscription_update: {
5730
+ enabled: false,
5731
+ schedule_at_period_end: {
5732
+ conditions: []
5733
+ },
5734
+ default_allowed_updates: [],
5735
+ proration_behavior: "none",
5736
+ products: []
5737
+ }
5738
+ }
5739
+ }
5740
+ }
5741
+ };
5742
+ const normalizeConfiguration = (config) => {
5743
+ return deepmerge(DEFAULT_CONFIGURATION, config);
5744
+ };
5745
+ const DEFAULT_OPTIONS = {
5746
+ store: "store",
5747
+ debug: false,
5748
+ logger: new Logger(false),
5749
+ base: "stripe"
5750
+ };
5751
+ const normalizeOptions = (options) => {
5752
+ return deepmerge(DEFAULT_OPTIONS, options);
5753
+ };
5754
+ const defineActionCallableFunction = (spec) => spec;
5755
+ const defineActionImplementation = (spec) => spec;
5756
+ const defineMutationImplementation = (spec) => spec;
5757
+ const nullablestring = () => v.union(v.string(), v.null());
5758
+ const nullableboolean = () => v.union(v.boolean(), v.null());
5759
+ const nullablenumber = () => v.union(v.number(), v.null());
5760
+ const metadata = () => v.record(v.string(), v.union(v.string(), v.number(), v.null()));
5761
+ const optionalnullableobject = (object) => v.optional(v.union(v.object(object), v.null()));
5762
+ const optionalany = () => v.optional(v.any());
5763
+ async function deleteById(context, table, indexName, idField, idValue) {
5764
+ const existing = await context.db.query(table).withIndex(indexName, (q) => q.eq(idField, idValue)).unique();
5765
+ if (existing) {
5766
+ await context.db.delete(existing._id);
5767
+ return true;
5768
+ }
5769
+ return false;
5770
+ }
5771
+ async function selectAll(context, table) {
5772
+ return await context.db.query(table).collect();
5773
+ }
5774
+ async function selectById(context, table, id) {
5775
+ return await context.db.get(id);
5776
+ }
5777
+ async function selectOne(context, table, indexName, field, value) {
5778
+ return await context.db.query(table).withIndex(indexName, (q) => q.eq(field, value)).unique();
5779
+ }
5780
+ async function upsert(context, table, indexName, idField, data) {
5781
+ const existing = await context.db.query(table).withIndex(indexName, (q) => q.eq(idField, data[idField])).unique();
5782
+ if (existing) {
5783
+ await context.db.patch(existing._id, {
5784
+ ...data,
5785
+ lastSyncedAt: Date.now()
5786
+ });
5787
+ return existing._id;
5788
+ } else {
5789
+ return await context.db.insert(table, {
5790
+ ...data,
5791
+ lastSyncedAt: Date.now()
5792
+ });
5793
+ }
5794
+ }
5795
+ async function insert(context, table, data) {
5796
+ return await context.db.insert(table, {
5797
+ ...data,
5798
+ lastSyncedAt: Date.now()
5799
+ });
5800
+ }
5801
+ const StoreImplementation = defineMutationImplementation({
5802
+ name: "store",
5803
+ args: {
5804
+ operation: v.string(),
5805
+ table: v.string(),
5806
+ indexName: v.optional(v.string()),
5807
+ idField: v.optional(v.string()),
5808
+ data: v.optional(v.any()),
5809
+ idValue: v.optional(v.any()),
5810
+ field: v.optional(v.string()),
5811
+ value: v.optional(v.any()),
5812
+ id: v.optional(v.any())
5813
+ },
5814
+ handler: async (context, args, configuration) => {
5815
+ const allowed = /* @__PURE__ */ new Set([
5816
+ "upsert",
5817
+ "insert",
5818
+ "deleteById",
5819
+ "selectOne",
5820
+ "selectById",
5821
+ "selectAll"
5822
+ ]);
5823
+ if (!allowed.has(args.operation)) {
5824
+ throw new Error(`Unknown op "${args.operation}"`);
5825
+ }
5826
+ const table = args.table;
5827
+ switch (args.operation) {
5828
+ case "upsert": {
5829
+ if (!args.indexName) {
5830
+ throw new Error('Missing "indexName" for upsert');
5831
+ }
5832
+ if (!args.idField) {
5833
+ throw new Error('Missing "idField" for upsert');
5834
+ }
5835
+ if (args.data == null) {
5836
+ throw new Error('Missing "data" for upsert');
5837
+ }
5838
+ const upsertIndexName = args.indexName;
5839
+ const upsertIdField = args.idField;
5840
+ const upsertData = args.data;
5841
+ const id = await upsert(
5842
+ context,
5843
+ table,
5844
+ upsertIndexName,
5845
+ upsertIdField,
5846
+ upsertData
5847
+ );
5848
+ if (configuration.callbacks && configuration.callbacks.afterChange)
5849
+ try {
5850
+ await configuration.callbacks.afterChange(
5851
+ context,
5852
+ "upsert",
5853
+ // TODO: remove any
5854
+ { table }
5855
+ );
5856
+ } catch (error) {
5857
+ console.error("[afterChange]:", error);
5858
+ }
5859
+ return { id };
5860
+ }
5861
+ case "insert": {
5862
+ if (args.data == null) {
5863
+ throw new Error('Missing "data" for insert');
5864
+ }
5865
+ const insertData = args.data;
5866
+ const id = await insert(context, table, insertData);
5867
+ if (configuration.callbacks && configuration.callbacks.afterChange)
5868
+ try {
5869
+ await configuration.callbacks.afterChange(
5870
+ context,
5871
+ "insert",
5872
+ // TODO: remove any
5873
+ { table }
5874
+ );
5875
+ } catch (error) {
5876
+ console.error("[afterChange]:", error);
5877
+ }
5878
+ return { id };
5879
+ }
5880
+ case "deleteById": {
5881
+ if (!args.indexName) {
5882
+ throw new Error('Missing "indexName" for deleteById');
5883
+ }
5884
+ if (!args.idField) {
5885
+ throw new Error('Missing "idField" for deleteById');
5886
+ }
5887
+ if (typeof args.idValue === "undefined") {
5888
+ throw new Error('Missing "idValue" for deleteById');
5889
+ }
5890
+ const deleteByIdIndexName = args.indexName;
5891
+ const deleteByIdIdField = args.idField;
5892
+ const deleteByIdIdValue = args.idValue;
5893
+ const deleted = await deleteById(
5894
+ context,
5895
+ table,
5896
+ deleteByIdIndexName,
5897
+ deleteByIdIdField,
5898
+ deleteByIdIdValue
5899
+ );
5900
+ if (configuration.callbacks && configuration.callbacks.afterChange)
5901
+ try {
5902
+ await configuration.callbacks.afterChange(
5903
+ context,
5904
+ "delete",
5905
+ // TODO: remove any
5906
+ { table }
5907
+ );
5908
+ } catch (error) {
5909
+ console.error("[afterChange]:", error);
5910
+ }
5911
+ return { deleted };
5912
+ }
5913
+ case "selectOne": {
5914
+ if (!args.indexName) {
5915
+ throw new Error('Missing "indexName" for selectOne');
5916
+ }
5917
+ if (!args.field) {
5918
+ throw new Error('Missing "field" for selectOne');
5919
+ }
5920
+ if (typeof args.value === "undefined") {
5921
+ throw new Error('Missing "value" for selectOne');
5922
+ }
5923
+ const selectOneIndexName = args.indexName;
5924
+ const selectOneField = args.field;
5925
+ const selectOneValue = args.value;
5926
+ const doc = await selectOne(
5927
+ context,
5928
+ table,
5929
+ selectOneIndexName,
5930
+ selectOneField,
5931
+ selectOneValue
5932
+ );
5933
+ return { doc };
5934
+ }
5935
+ case "selectById": {
5936
+ if (args.id == null) {
5937
+ throw new Error('Missing "id" for selectById');
5938
+ }
5939
+ const doc = await selectById(context, table, args.id);
5940
+ return { doc };
5941
+ }
5942
+ case "selectAll": {
5943
+ const docs = await selectAll(context, table);
5944
+ return { docs };
5945
+ }
5946
+ }
5947
+ }
5948
+ });
5949
+ async function storeDispatchTyped(args, context, configuration, options) {
5950
+ return await context.runMutation(
5951
+ `${options.base}:${options.store}`,
5952
+ args
5953
+ );
5954
+ }
5955
+ const CreateAccountImplementation = defineActionCallableFunction({
5956
+ name: "createAccount",
5957
+ handler: async (context, args, stripeOptions, configuration, options) => {
5958
+ const stripe = new Stripe(configuration.stripe.secret_key, {
5959
+ apiVersion: configuration.stripe.version
5960
+ });
5961
+ const stripeAccount = (await storeDispatchTyped(
5962
+ {
5963
+ operation: "selectOne",
5964
+ table: "stripeAccounts",
5965
+ indexName: "byEntityId",
5966
+ field: "entityId",
5967
+ value: args.entityId
5968
+ },
5969
+ context,
5970
+ configuration,
5971
+ options
5972
+ )).doc;
5973
+ if (stripeAccount) {
5974
+ return stripeAccount;
5975
+ } else {
5976
+ const account = await stripe.accounts.create(
5977
+ {
5978
+ ...{
5979
+ ...args,
5980
+ entityId: void 0
5981
+ },
5982
+ metadata: {
5983
+ ...args.metadata || {},
5984
+ entityId: args.entityId
5985
+ }
5986
+ },
5987
+ Object.keys(stripeOptions).length === 0 ? void 0 : stripeOptions
5988
+ );
5989
+ const data = {
5990
+ entityId: args.entityId,
5991
+ accountId: account.id,
5992
+ stripe: {
5993
+ id: account.id,
5994
+ object: account.object,
5995
+ business_type: account.business_type,
5996
+ capabilities: account.capabilities,
5997
+ company: account.company,
5998
+ country: account.country,
5999
+ email: account.email,
6000
+ individual: account.individual,
6001
+ metadata: account.metadata,
6002
+ requirements: account.requirements,
6003
+ tos_acceptance: account.tos_acceptance,
6004
+ type: account.type,
6005
+ business_profile: account.business_profile,
6006
+ charges_enabled: account.charges_enabled,
6007
+ controller: account.controller,
6008
+ created: account.created,
6009
+ default_currency: account.default_currency,
6010
+ details_submitted: account.details_submitted,
6011
+ external_accounts: account.external_accounts,
6012
+ future_requirements: account.future_requirements,
6013
+ groups: account.groups,
6014
+ payouts_enabled: account.payouts_enabled,
6015
+ settings: account.settings
6016
+ },
6017
+ lastSyncedAt: Date.now()
6018
+ };
6019
+ const response = await storeDispatchTyped(
6020
+ {
6021
+ operation: "upsert",
6022
+ table: "stripeAccounts",
6023
+ indexName: "byEntityId",
6024
+ idField: "entityId",
6025
+ data
6026
+ },
6027
+ context,
6028
+ configuration,
6029
+ options
6030
+ );
6031
+ return {
6032
+ _id: response.id,
6033
+ ...data,
6034
+ _creationTime: (/* @__PURE__ */ new Date()).getTime()
6035
+ };
6036
+ }
6037
+ }
6038
+ });
6039
+ function defineRedirectHandler(handler) {
6040
+ return handler;
6041
+ }
6042
+ const CreateAccountReturnImplementation = defineRedirectHandler({
6043
+ origins: ["create-account-link-return", "create-account-link-refresh"],
6044
+ data: {
6045
+ accountId: v.string()
6046
+ },
6047
+ handle: async (origin, context, data, configuration, options) => {
6048
+ }
6049
+ });
6050
+ const __vite_glob_0_0$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
6051
+ __proto__: null,
6052
+ CreateAccountReturnImplementation
6053
+ }, Symbol.toStringTag, { value: "Module" }));
6054
+ const SubscriptionSyncImplementation = defineActionImplementation({
6055
+ args: v.object({
6056
+ customerId: v.string(),
6057
+ accountId: v.optional(v.string())
6058
+ }),
6059
+ name: "syncSubscription",
6060
+ handler: async (context, args, configuration, options) => {
6061
+ const stripe = new Stripe(configuration.stripe.secret_key, {
6062
+ apiVersion: configuration.stripe.version
6063
+ });
6064
+ const customerId = args.customerId;
6065
+ const subscriptions = await stripe.subscriptions.list(
6066
+ {
6067
+ customer: customerId,
6068
+ limit: 1,
6069
+ status: "all",
6070
+ expand: ["data.default_payment_method"]
6071
+ },
6072
+ { stripeAccount: args.accountId }
6073
+ );
6074
+ if (subscriptions.data.length === 0) {
6075
+ await storeDispatchTyped(
6076
+ {
6077
+ operation: "upsert",
6078
+ table: "stripeSubscriptions",
6079
+ indexName: "byCustomerId",
6080
+ idField: "customerId",
6081
+ data: {
6082
+ subscriptionId: null,
6083
+ customerId,
6084
+ stripe: null,
6085
+ lastSyncedAt: Date.now(),
6086
+ accountId: args.accountId
6087
+ }
6088
+ },
6089
+ context,
6090
+ configuration,
6091
+ options
6092
+ );
6093
+ return null;
6094
+ }
6095
+ const subscription = subscriptions.data[0];
6096
+ await storeDispatchTyped(
6097
+ {
6098
+ operation: "upsert",
6099
+ table: "stripeSubscriptions",
6100
+ indexName: "byCustomerId",
6101
+ idField: "customerId",
6102
+ data: {
6103
+ accountId: args.accountId,
6104
+ subscriptionId: subscription.id,
6105
+ customerId,
6106
+ stripe: SubscriptionStripeToConvex(subscription),
6107
+ lastSyncedAt: Date.now()
6108
+ }
6109
+ },
6110
+ context,
6111
+ configuration,
6112
+ options
6113
+ );
6114
+ return subscription;
6115
+ }
6116
+ });
6117
+ const PayReturnImplementation = defineRedirectHandler({
6118
+ origins: ["pay-cancel", "pay-success", "pay-return"],
6119
+ data: {
6120
+ accountId: v.optional(v.string()),
6121
+ entityId: v.string(),
6122
+ customerId: v.string(),
6123
+ referenceId: v.string()
6124
+ },
6125
+ handle: async (origin, context, data, configuration, options) => {
6126
+ const customer = await storeDispatchTyped(
6127
+ {
6128
+ operation: "selectOne",
6129
+ table: "stripeCustomers",
6130
+ indexName: "byEntityId",
6131
+ field: "entityId",
6132
+ value: data.entityId
6133
+ },
6134
+ context,
6135
+ configuration,
6136
+ options
6137
+ );
6138
+ const customerId = customer?.doc?.customerId || null;
6139
+ if (customerId) {
6140
+ await SubscriptionSyncImplementation.handler(
6141
+ context,
6142
+ { customerId, accountId: data.accountId },
6143
+ configuration,
6144
+ options
6145
+ );
6146
+ } else {
6147
+ options.logger.warn(
6148
+ "Potential redirect abuse detected. No customerId associated with provided entityId " + data.entityId
6149
+ );
6150
+ }
6151
+ }
6152
+ });
6153
+ const __vite_glob_0_1$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
6154
+ __proto__: null,
6155
+ PayReturnImplementation
6156
+ }, Symbol.toStringTag, { value: "Module" }));
6157
+ const PortalReturnImplementation = defineRedirectHandler({
6158
+ origins: ["portal-return"],
6159
+ data: {
6160
+ accountId: v.optional(v.string()),
6161
+ entityId: v.string()
6162
+ },
6163
+ handle: async (origin, context, data, configuration, options) => {
6164
+ const customer = await storeDispatchTyped(
6165
+ {
6166
+ operation: "selectOne",
6167
+ table: "stripeCustomers",
6168
+ indexName: "byEntityId",
6169
+ field: "entityId",
6170
+ value: data.entityId
6171
+ },
6172
+ context,
6173
+ configuration,
6174
+ options
6175
+ );
6176
+ const customerId = customer?.doc?.customerId || null;
6177
+ if (customerId) {
6178
+ await SubscriptionSyncImplementation.handler(
6179
+ context,
6180
+ { customerId, accountId: data.accountId },
6181
+ configuration,
6182
+ options
6183
+ );
6184
+ } else {
6185
+ options.logger.warn(
6186
+ "Potential redirect abuse detected. No customerId associated with provided entityId " + data.entityId
6187
+ );
6188
+ }
6189
+ }
6190
+ });
6191
+ const __vite_glob_0_2$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
6192
+ __proto__: null,
6193
+ PortalReturnImplementation
6194
+ }, Symbol.toStringTag, { value: "Module" }));
6195
+ const SubscribeReturnImplementation = defineRedirectHandler({
6196
+ origins: ["subscribe-cancel", "subscribe-success", "subscribe-return"],
6197
+ data: {
6198
+ accountId: v.optional(v.string()),
6199
+ entityId: v.string()
6200
+ },
6201
+ handle: async (origin, context, data, configuration, options) => {
6202
+ const customer = await storeDispatchTyped(
6203
+ {
6204
+ operation: "selectOne",
6205
+ table: "stripeCustomers",
6206
+ indexName: "byEntityId",
6207
+ field: "entityId",
6208
+ value: data.entityId
6209
+ },
6210
+ context,
6211
+ configuration,
6212
+ options
6213
+ );
6214
+ const customerId = customer?.doc?.customerId || null;
6215
+ if (customerId) {
6216
+ await SubscriptionSyncImplementation.handler(
6217
+ context,
6218
+ { customerId, accountId: data.accountId },
6219
+ configuration,
6220
+ options
6221
+ );
6222
+ } else {
6223
+ options.logger.warn(
6224
+ "Potential redirect abuse detected. No customerId associated with provided entityId " + data.entityId
6225
+ );
6226
+ }
6227
+ }
6228
+ });
6229
+ const __vite_glob_0_3$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
6230
+ __proto__: null,
6231
+ SubscribeReturnImplementation
6232
+ }, Symbol.toStringTag, { value: "Module" }));
6233
+ const HANDLERS_MODULES$2 = Object.values(
6234
+ [
6235
+ __vite_glob_0_0$2,
6236
+ __vite_glob_0_1$2,
6237
+ __vite_glob_0_2$2,
6238
+ __vite_glob_0_3$2
6239
+ ]
6240
+ );
6241
+ if (HANDLERS_MODULES$2.some((handler) => Object.keys(handler).length > 1))
6242
+ throw new Error(
6243
+ "Each redirect handler file should only have one export / default export"
6244
+ );
6245
+ const REDIRECT_HANDLERS = HANDLERS_MODULES$2.map(
6246
+ (exports$1) => Object.values(exports$1)[0]
6247
+ );
6248
+ if (REDIRECT_HANDLERS.some(
6249
+ (handler) => !["origins", "data", "handle"].every((key) => key in handler)
6250
+ ))
6251
+ throw new Error(
6252
+ "Each redirect handler file should export a valid implementation"
6253
+ );
6254
+ const originToHandlers = /* @__PURE__ */ new Map();
6255
+ REDIRECT_HANDLERS.forEach((handler, handlerIndex) => {
6256
+ handler.origins.forEach((origin) => {
6257
+ if (originToHandlers.has(origin)) {
6258
+ throw new Error(
6259
+ `Origin "${origin}" is used by multiple handlers (handler indices: ${originToHandlers.get(origin)}, ${handlerIndex})`
6260
+ );
6261
+ }
6262
+ originToHandlers.set(origin, handlerIndex);
6263
+ });
6264
+ });
6265
+ function backendBaseUrl(configuration) {
6266
+ return process.env.CONVEX_SITE_URL;
6267
+ }
6268
+ function toBase64Url(input) {
6269
+ const buffer = typeof input === "string" ? new TextEncoder().encode(input) : new Uint8Array(input);
6270
+ let binary = "";
6271
+ for (let i = 0; i < buffer.length; i++) {
6272
+ binary += String.fromCharCode(buffer[i]);
6273
+ }
6274
+ const base64 = btoa(binary);
6275
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
6276
+ }
6277
+ function fromBase64Url(input) {
6278
+ const b64 = input.replace(/-/g, "+").replace(/_/g, "/");
6279
+ const padding = b64.length % 4 === 0 ? 0 : 4 - b64.length % 4;
6280
+ const padded = b64 + "=".repeat(padding);
6281
+ const binary = atob(padded);
6282
+ const bytes = new Uint8Array(binary.length);
6283
+ for (let i = 0; i < binary.length; i++) {
6284
+ bytes[i] = binary.charCodeAt(i);
6285
+ }
6286
+ return bytes;
6287
+ }
6288
+ async function signData(secret, data) {
6289
+ const encoder = new TextEncoder();
6290
+ const keyData = encoder.encode(secret);
6291
+ const messageData = encoder.encode(data);
6292
+ const key = await crypto.subtle.importKey(
6293
+ "raw",
6294
+ keyData,
6295
+ { name: "HMAC", hash: "SHA-256" },
6296
+ false,
6297
+ ["sign"]
6298
+ );
6299
+ return await crypto.subtle.sign("HMAC", key, messageData);
6300
+ }
6301
+ async function timingSafeEqual(a, b) {
6302
+ if (a.byteLength !== b.byteLength) {
6303
+ return false;
6304
+ }
6305
+ const aArray = new Uint8Array(a);
6306
+ const bArray = new Uint8Array(b);
6307
+ let result = 0;
6308
+ for (let i = 0; i < aArray.length; i++) {
6309
+ result |= aArray[i] ^ bArray[i];
6310
+ }
6311
+ return result === 0;
6312
+ }
6313
+ async function buildSignedReturnUrl({
6314
+ configuration,
6315
+ origin,
6316
+ failureUrl,
6317
+ targetUrl,
6318
+ data
6319
+ }) {
6320
+ const payload = {
6321
+ origin,
6322
+ data,
6323
+ targetUrl,
6324
+ failureUrl,
6325
+ exp: Date.now() + configuration.redirectTtlMs
6326
+ };
6327
+ const data_ = toBase64Url(JSON.stringify(payload));
6328
+ const expected = await signData(
6329
+ configuration.stripe.account_webhook_secret,
6330
+ data_
6331
+ );
6332
+ const signature = toBase64Url(expected);
6333
+ const base = `${backendBaseUrl()}/stripe/return/${origin}`;
6334
+ const url = new URL(base);
6335
+ url.searchParams.set("data", data_);
6336
+ url.searchParams.set("signature", signature);
6337
+ return url.toString();
6338
+ }
6339
+ async function decodeSignedPayload({
6340
+ secret,
6341
+ data,
6342
+ signature
6343
+ }) {
6344
+ try {
6345
+ const expected = await signData(secret, data);
6346
+ const provided = fromBase64Url(signature);
6347
+ if (provided.byteLength !== expected.byteLength) {
6348
+ return { error: "Invalid signature length" };
6349
+ }
6350
+ const isValid = await timingSafeEqual(provided.buffer, expected);
6351
+ if (!isValid) {
6352
+ return { error: "Invalid signature" };
6353
+ }
6354
+ const decodedBytes = fromBase64Url(data);
6355
+ const decoder = new TextDecoder();
6356
+ const decodedPayload = JSON.parse(
6357
+ decoder.decode(decodedBytes)
6358
+ );
6359
+ return { data: decodedPayload };
6360
+ } catch (err) {
6361
+ return { error: "Invalid token" };
6362
+ }
6363
+ }
6364
+ REDIRECT_HANDLERS.map(
6365
+ (handler) => handler.origins
6366
+ ).flat();
6367
+ const redirectImplementation = async (configuration, options, context, request) => {
6368
+ const url = new URL(request.url);
6369
+ const segments = url.pathname.split("/").filter(Boolean);
6370
+ const origin_ = segments[segments.length - 1];
6371
+ if (!origin_ || !REDIRECT_HANDLERS.map((handler) => handler.origins).flat().includes(origin_)) {
6372
+ return new Response("Invalid return origin", { status: 400 });
6373
+ }
6374
+ const origin = origin_;
6375
+ const data = url.searchParams.get("data");
6376
+ const signature = url.searchParams.get("signature");
6377
+ if (!data || !signature) {
6378
+ return new Response("Missing signature", { status: 400 });
6379
+ }
6380
+ const response = await decodeSignedPayload({
6381
+ secret: configuration.stripe.account_webhook_secret,
6382
+ data,
6383
+ signature
6384
+ });
6385
+ if (response.error) {
6386
+ return new Response(response.error, { status: 400 });
6387
+ }
6388
+ const decoded = response.data;
6389
+ if (decoded.origin !== origin) {
6390
+ if (decoded.failureUrl) {
6391
+ const failureUrl = new URL(decoded.failureUrl);
6392
+ failureUrl.searchParams.set("reason", "origin_mismatch");
6393
+ return new Response(null, {
6394
+ status: 302,
6395
+ headers: { Location: failureUrl.toString() }
6396
+ });
6397
+ }
6398
+ return new Response("Origin mismatch", { status: 400 });
6399
+ }
6400
+ if (!decoded.exp || Date.now() > decoded.exp) {
6401
+ if (decoded.failureUrl) {
6402
+ const failureUrl = new URL(decoded.failureUrl);
6403
+ failureUrl.searchParams.set("reason", "link_expired");
6404
+ return new Response(null, {
6405
+ status: 302,
6406
+ headers: { Location: failureUrl.toString() }
6407
+ });
6408
+ }
6409
+ return new Response("Link expired", { status: 400 });
6410
+ }
6411
+ if (typeof decoded.targetUrl !== "string" || decoded.targetUrl.length === 0) {
6412
+ if (decoded.failureUrl) {
6413
+ const failureUrl = new URL(decoded.failureUrl);
6414
+ failureUrl.searchParams.set("reason", "invalid_target");
6415
+ return new Response(null, {
6416
+ status: 302,
6417
+ headers: { Location: failureUrl.toString() }
6418
+ });
6419
+ }
6420
+ return new Response("Invalid target", { status: 400 });
6421
+ }
6422
+ for (const handler of REDIRECT_HANDLERS) {
6423
+ if (handler.origins.includes(origin)) {
6424
+ try {
6425
+ await handler.handle(
6426
+ origin,
6427
+ context,
6428
+ decoded.data,
6429
+ configuration,
6430
+ options
6431
+ );
6432
+ } catch (error) {
6433
+ options.logger.error(`[STRIPE RETURN ${origin}](Error): ${error}`);
6434
+ }
6435
+ return new Response(null, {
6436
+ status: 302,
6437
+ headers: { Location: decoded.targetUrl }
6438
+ });
6439
+ }
6440
+ }
6441
+ return new Response(null, {
6442
+ status: 302,
6443
+ headers: { Location: decoded.targetUrl }
6444
+ });
6426
6445
  };
6427
- defineSchema(stripeTables);
6446
+ const CreateAccountLinkImplementation = defineActionCallableFunction({
6447
+ name: "createAccountLink",
6448
+ handler: async (context, args, stripeOptions, configuration, options) => {
6449
+ const stripe = new Stripe(configuration.stripe.secret_key, {
6450
+ apiVersion: configuration.stripe.version
6451
+ });
6452
+ const refreshUrl = await buildSignedReturnUrl({
6453
+ configuration,
6454
+ origin: "create-account-link-refresh",
6455
+ data: {
6456
+ accountId: args.account
6457
+ },
6458
+ failureUrl: args.failure_url,
6459
+ targetUrl: args.refresh_url
6460
+ });
6461
+ const returnUrl = await buildSignedReturnUrl({
6462
+ configuration,
6463
+ origin: "create-account-link-return",
6464
+ data: {
6465
+ accountId: args.account
6466
+ },
6467
+ failureUrl: args.failure_url,
6468
+ targetUrl: args.return_url
6469
+ });
6470
+ const accountLink = await stripe.accountLinks.create(
6471
+ {
6472
+ ...{
6473
+ ...args
6474
+ },
6475
+ account: args.account,
6476
+ refresh_url: refreshUrl,
6477
+ return_url: returnUrl
6478
+ },
6479
+ Object.keys(stripeOptions).length === 0 ? void 0 : stripeOptions
6480
+ );
6481
+ return accountLink;
6482
+ }
6483
+ });
6484
+ const CreateCustomerImplementation = defineActionCallableFunction({
6485
+ name: "createCustomer",
6486
+ handler: async (context, args, stripeOptions, configuration, options) => {
6487
+ const stripe = new Stripe(configuration.stripe.secret_key, {
6488
+ apiVersion: configuration.stripe.version
6489
+ });
6490
+ const stripeCustomer = (await storeDispatchTyped(
6491
+ {
6492
+ operation: "selectOne",
6493
+ table: "stripeCustomers",
6494
+ indexName: "byEntityId",
6495
+ field: "entityId",
6496
+ value: args.entityId
6497
+ },
6498
+ context,
6499
+ configuration,
6500
+ options
6501
+ )).doc;
6502
+ if (stripeCustomer) {
6503
+ return stripeCustomer;
6504
+ } else {
6505
+ const customer = await stripe.customers.create(
6506
+ {
6507
+ ...{
6508
+ ...args,
6509
+ entityId: void 0
6510
+ },
6511
+ metadata: {
6512
+ ...args.metadata || {},
6513
+ entityId: args.entityId
6514
+ }
6515
+ },
6516
+ Object.keys(stripeOptions).length === 0 ? void 0 : stripeOptions
6517
+ );
6518
+ const data = {
6519
+ entityId: args.entityId,
6520
+ customerId: customer.id,
6521
+ stripe: {
6522
+ id: customer.id,
6523
+ address: customer.address,
6524
+ description: customer.description,
6525
+ email: customer.email,
6526
+ metadata: customer.metadata,
6527
+ name: customer.name,
6528
+ phone: customer.phone,
6529
+ shipping: customer.shipping,
6530
+ tax: customer.tax,
6531
+ object: customer.object,
6532
+ balance: customer.balance,
6533
+ cash_balance: customer.cash_balance,
6534
+ created: customer.created,
6535
+ currency: customer.currency,
6536
+ default_source: typeof customer.default_source === "string" ? customer.default_source : customer.default_source?.id,
6537
+ delinquent: customer.delinquent,
6538
+ discount: customer.discount,
6539
+ invoice_credit_balance: customer.invoice_credit_balance,
6540
+ invoice_prefix: customer.invoice_prefix,
6541
+ invoice_settings: customer.invoice_settings,
6542
+ livemode: customer.livemode,
6543
+ next_invoice_sequence: customer.next_invoice_sequence,
6544
+ preferred_locales: customer.preferred_locales,
6545
+ sources: customer.sources,
6546
+ subscriptions: customer.subscriptions,
6547
+ tax_exempt: customer.tax_exempt,
6548
+ tax_ids: customer.tax_ids,
6549
+ test_clock: typeof customer.test_clock === "string" ? customer.test_clock : customer.test_clock?.id
6550
+ },
6551
+ lastSyncedAt: Date.now()
6552
+ };
6553
+ const response = await storeDispatchTyped(
6554
+ {
6555
+ operation: "upsert",
6556
+ table: "stripeCustomers",
6557
+ indexName: "byEntityId",
6558
+ idField: "entityId",
6559
+ data
6560
+ },
6561
+ context,
6562
+ configuration,
6563
+ options
6564
+ );
6565
+ return {
6566
+ _id: response.id,
6567
+ ...data,
6568
+ _creationTime: (/* @__PURE__ */ new Date()).getTime()
6569
+ };
6570
+ }
6571
+ }
6572
+ });
6428
6573
  const DEFAULT_CREATE_STRIPE_CUSTOMER_IF_MISSING$2 = true;
6429
6574
  const PayImplementation = defineActionCallableFunction({
6430
6575
  name: "pay",
6431
6576
  handler: async (context, args, stripeOptions, configuration, options) => {
6432
6577
  const createStripeCustomerIfMissing = args.createStripeCustomerIfMissing ?? DEFAULT_CREATE_STRIPE_CUSTOMER_IF_MISSING$2;
6433
6578
  const stripe = new Stripe(configuration.stripe.secret_key, {
6434
- apiVersion: "2025-08-27.basil"
6579
+ apiVersion: configuration.stripe.version
6435
6580
  });
6436
6581
  const stripeCustomer = await storeDispatchTyped(
6437
6582
  {
@@ -6570,7 +6715,7 @@ const PortalImplementation = defineActionCallableFunction({
6570
6715
  handler: async (context, args, stripeOptions, configuration, options) => {
6571
6716
  const createStripeCustomerIfMissing = args.createStripeCustomerIfMissing ?? DEFAULT_CREATE_STRIPE_CUSTOMER_IF_MISSING$1;
6572
6717
  const stripe = new Stripe(configuration.stripe.secret_key, {
6573
- apiVersion: "2025-08-27.basil"
6718
+ apiVersion: configuration.stripe.version
6574
6719
  });
6575
6720
  const stripeCustomer = await storeDispatchTyped(
6576
6721
  {
@@ -6636,7 +6781,7 @@ const SubscribeImplementation = defineActionCallableFunction({
6636
6781
  handler: async (context, args, stripeOptions, configuration, options) => {
6637
6782
  const createStripeCustomerIfMissing = args.createStripeCustomerIfMissing ?? DEFAULT_CREATE_STRIPE_CUSTOMER_IF_MISSING;
6638
6783
  const stripe = new Stripe(configuration.stripe.secret_key, {
6639
- apiVersion: "2025-08-27.basil"
6784
+ apiVersion: configuration.stripe.version
6640
6785
  });
6641
6786
  const stripeCustomer = await storeDispatchTyped(
6642
6787
  {
@@ -6864,12 +7009,12 @@ const SyncCatalogImplementation = defineActionImplementation({
6864
7009
  args: v.object({}),
6865
7010
  name: "syncCatalog",
6866
7011
  handler: async (context, args, configuration) => {
6867
- const catalog = configuration.catalog;
7012
+ const catalog = configuration.sync.catalog;
6868
7013
  const products = catalog.products || [];
6869
7014
  const prices = catalog.prices || [];
6870
7015
  if (products.length === 0 && prices.length === 0) return;
6871
7016
  const stripe = new Stripe(configuration.stripe.secret_key, {
6872
- apiVersion: "2025-08-27.basil"
7017
+ apiVersion: configuration.stripe.version
6873
7018
  });
6874
7019
  const metadataKey = catalog.metadataKey || "convex_stripe_key";
6875
7020
  const behavior = {
@@ -6976,22 +7121,10 @@ const AccountsSyncImplementation = defineActionImplementation({
6976
7121
  }),
6977
7122
  name: "accounts",
6978
7123
  handler: async (context, args, configuration, options) => {
6979
- if (configuration.sync.stripeAccounts !== true) return;
7124
+ if (configuration.sync.tables.stripeAccounts !== true) return;
6980
7125
  const stripe = new Stripe(configuration.stripe.secret_key, {
6981
- apiVersion: "2025-08-27.basil"
7126
+ apiVersion: configuration.stripe.version
6982
7127
  });
6983
- const localAccountsRes = await storeDispatchTyped(
6984
- {
6985
- operation: "selectAll",
6986
- table: "stripeAccounts"
6987
- },
6988
- context,
6989
- configuration,
6990
- options
6991
- );
6992
- new Map(
6993
- (localAccountsRes.docs || []).map((p) => [p.accountId, p])
6994
- );
6995
7128
  const accounts = await stripe.accounts.list({ limit: 100 }).autoPagingToArray({ limit: 1e4 });
6996
7129
  const stripeAccountIds = /* @__PURE__ */ new Set();
6997
7130
  for (const account of accounts) {
@@ -7031,25 +7164,11 @@ const BillingPortalConfigurationsSyncImplementation = defineActionImplementation
7031
7164
  }),
7032
7165
  name: "billingPortalConfigurations",
7033
7166
  handler: async (context, args, configuration, options) => {
7034
- if (configuration.sync.stripeBillingPortalConfigurations !== true) return;
7167
+ if (configuration.sync.tables.stripeBillingPortalConfigurations !== true)
7168
+ return;
7035
7169
  const stripe = new Stripe(configuration.stripe.secret_key, {
7036
- apiVersion: "2025-08-27.basil"
7170
+ apiVersion: configuration.stripe.version
7037
7171
  });
7038
- const localBillingPortalConfigurationsRes = await storeDispatchTyped(
7039
- {
7040
- operation: "selectAll",
7041
- table: "stripeBillingPortalConfigurations"
7042
- },
7043
- context,
7044
- configuration,
7045
- options
7046
- );
7047
- new Map(
7048
- (localBillingPortalConfigurationsRes.docs || []).map((p) => [
7049
- p.billingPortalConfigurationId,
7050
- p
7051
- ])
7052
- );
7053
7172
  const billingPortalConfigurations = await stripe.billingPortal.configurations.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7054
7173
  const stripeBillingPortalConfigurationIds = /* @__PURE__ */ new Set();
7055
7174
  for (const billingPortalConfiguration of billingPortalConfigurations) {
@@ -7086,22 +7205,10 @@ const CapabilitiesSyncImplementation = defineActionImplementation({
7086
7205
  }),
7087
7206
  name: "capabilities",
7088
7207
  handler: async (context, args, configuration, options) => {
7089
- if (configuration.sync.stripeCapabilities !== true) return;
7208
+ if (configuration.sync.tables.stripeCapabilities !== true) return;
7090
7209
  const stripe = new Stripe(configuration.stripe.secret_key, {
7091
- apiVersion: "2025-08-27.basil"
7210
+ apiVersion: configuration.stripe.version
7092
7211
  });
7093
- const localCapabilitiesRes = await storeDispatchTyped(
7094
- {
7095
- operation: "selectAll",
7096
- table: "stripeCapabilities"
7097
- },
7098
- context,
7099
- configuration,
7100
- options
7101
- );
7102
- new Map(
7103
- (localCapabilitiesRes.docs || []).map((p) => [p.capabilityId, p])
7104
- );
7105
7212
  const accounts = await stripe.accounts.list().autoPagingToArray({ limit: 1e4 });
7106
7213
  const stripeCapabilityIds = /* @__PURE__ */ new Set();
7107
7214
  for (const account of accounts) {
@@ -7139,22 +7246,10 @@ const ChargesSyncImplementation = defineActionImplementation({
7139
7246
  }),
7140
7247
  name: "charges",
7141
7248
  handler: async (context, args, configuration, options) => {
7142
- if (configuration.sync.stripeCharges !== true) return;
7249
+ if (configuration.sync.tables.stripeCharges !== true) return;
7143
7250
  const stripe = new Stripe(configuration.stripe.secret_key, {
7144
- apiVersion: "2025-08-27.basil"
7251
+ apiVersion: configuration.stripe.version
7145
7252
  });
7146
- const localChargesRes = await storeDispatchTyped(
7147
- {
7148
- operation: "selectAll",
7149
- table: "stripeCharges"
7150
- },
7151
- context,
7152
- configuration,
7153
- options
7154
- );
7155
- new Map(
7156
- (localChargesRes.docs || []).map((p) => [p.chargeId, p])
7157
- );
7158
7253
  const charges = await stripe.charges.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7159
7254
  const stripeChargeIds = /* @__PURE__ */ new Set();
7160
7255
  for (const charge of charges) {
@@ -7189,25 +7284,10 @@ const CheckoutSessionsSyncImplementation = defineActionImplementation({
7189
7284
  }),
7190
7285
  name: "checkoutSessions",
7191
7286
  handler: async (context, args, configuration, options) => {
7192
- if (configuration.sync.stripeCheckoutSessions !== true) return;
7287
+ if (configuration.sync.tables.stripeCheckoutSessions !== true) return;
7193
7288
  const stripe = new Stripe(configuration.stripe.secret_key, {
7194
- apiVersion: "2025-08-27.basil"
7289
+ apiVersion: configuration.stripe.version
7195
7290
  });
7196
- const localCheckoutSessionsRes = await storeDispatchTyped(
7197
- {
7198
- operation: "selectAll",
7199
- table: "stripeCheckoutSessions"
7200
- },
7201
- context,
7202
- configuration,
7203
- options
7204
- );
7205
- new Map(
7206
- (localCheckoutSessionsRes.docs || []).map((p) => [
7207
- p.checkoutSessionId,
7208
- p
7209
- ])
7210
- );
7211
7291
  const checkoutSessions = await stripe.checkout.sessions.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7212
7292
  const stripeCheckoutSessionIds = /* @__PURE__ */ new Set();
7213
7293
  for (const checkoutSession of checkoutSessions) {
@@ -7242,22 +7322,10 @@ const CouponsSyncImplementation = defineActionImplementation({
7242
7322
  }),
7243
7323
  name: "coupons",
7244
7324
  handler: async (context, args, configuration, options) => {
7245
- if (configuration.sync.stripeCoupons !== true) return;
7325
+ if (configuration.sync.tables.stripeCoupons !== true) return;
7246
7326
  const stripe = new Stripe(configuration.stripe.secret_key, {
7247
- apiVersion: "2025-08-27.basil"
7327
+ apiVersion: configuration.stripe.version
7248
7328
  });
7249
- const localCouponsRes = await storeDispatchTyped(
7250
- {
7251
- operation: "selectAll",
7252
- table: "stripeCoupons"
7253
- },
7254
- context,
7255
- configuration,
7256
- options
7257
- );
7258
- new Map(
7259
- (localCouponsRes.docs || []).map((p) => [p.couponId, p])
7260
- );
7261
7329
  const coupons = await stripe.coupons.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7262
7330
  const stripeCouponIds = /* @__PURE__ */ new Set();
7263
7331
  for (const coupon of coupons) {
@@ -7292,22 +7360,10 @@ const CreditNotesSyncImplementation = defineActionImplementation({
7292
7360
  }),
7293
7361
  name: "creditNotes",
7294
7362
  handler: async (context, args, configuration, options) => {
7295
- if (configuration.sync.stripeCreditNotes !== true) return;
7363
+ if (configuration.sync.tables.stripeCreditNotes !== true) return;
7296
7364
  const stripe = new Stripe(configuration.stripe.secret_key, {
7297
- apiVersion: "2025-08-27.basil"
7365
+ apiVersion: configuration.stripe.version
7298
7366
  });
7299
- const localCreditNotesRes = await storeDispatchTyped(
7300
- {
7301
- operation: "selectAll",
7302
- table: "stripeCreditNotes"
7303
- },
7304
- context,
7305
- configuration,
7306
- options
7307
- );
7308
- new Map(
7309
- (localCreditNotesRes.docs || []).map((p) => [p.creditNoteId, p])
7310
- );
7311
7367
  const creditNotes = await stripe.creditNotes.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7312
7368
  const stripeCreditNoteIds = /* @__PURE__ */ new Set();
7313
7369
  for (const creditNote of creditNotes) {
@@ -7342,22 +7398,10 @@ const CustomersSyncImplementation = defineActionImplementation({
7342
7398
  }),
7343
7399
  name: "customers",
7344
7400
  handler: async (context, args, configuration, options) => {
7345
- if (configuration.sync.stripeCustomers !== true) return;
7401
+ if (configuration.sync.tables.stripeCustomers !== true) return;
7346
7402
  const stripe = new Stripe(configuration.stripe.secret_key, {
7347
- apiVersion: "2025-08-27.basil"
7403
+ apiVersion: configuration.stripe.version
7348
7404
  });
7349
- const localCustomersRes = await storeDispatchTyped(
7350
- {
7351
- operation: "selectAll",
7352
- table: "stripeCustomers"
7353
- },
7354
- context,
7355
- configuration,
7356
- options
7357
- );
7358
- new Map(
7359
- (localCustomersRes.docs || []).map((p) => [p.customerId, p])
7360
- );
7361
7405
  const customers = await stripe.customers.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7362
7406
  const stripeCustomerIds = /* @__PURE__ */ new Set();
7363
7407
  for (const customer of customers) {
@@ -7398,22 +7442,10 @@ const DisputesSyncImplementation = defineActionImplementation({
7398
7442
  }),
7399
7443
  name: "disputes",
7400
7444
  handler: async (context, args, configuration, options) => {
7401
- if (configuration.sync.stripeDisputes !== true) return;
7445
+ if (configuration.sync.tables.stripeDisputes !== true) return;
7402
7446
  const stripe = new Stripe(configuration.stripe.secret_key, {
7403
- apiVersion: "2025-08-27.basil"
7447
+ apiVersion: configuration.stripe.version
7404
7448
  });
7405
- const localDisputesRes = await storeDispatchTyped(
7406
- {
7407
- operation: "selectAll",
7408
- table: "stripeDisputes"
7409
- },
7410
- context,
7411
- configuration,
7412
- options
7413
- );
7414
- new Map(
7415
- (localDisputesRes.docs || []).map((p) => [p.disputeId, p])
7416
- );
7417
7449
  const disputes = await stripe.disputes.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7418
7450
  const stripeDisputeIds = /* @__PURE__ */ new Set();
7419
7451
  for (const dispute of disputes) {
@@ -7448,25 +7480,10 @@ const EarlyFraudWarningsSyncImplementation = defineActionImplementation({
7448
7480
  }),
7449
7481
  name: "early_fraud_warnings",
7450
7482
  handler: async (context, args, configuration, options) => {
7451
- if (configuration.sync.stripeEarlyFraudWarnings !== true) return;
7483
+ if (configuration.sync.tables.stripeEarlyFraudWarnings !== true) return;
7452
7484
  const stripe = new Stripe(configuration.stripe.secret_key, {
7453
- apiVersion: "2025-08-27.basil"
7485
+ apiVersion: configuration.stripe.version
7454
7486
  });
7455
- const localEarlyFraudWarningsRes = await storeDispatchTyped(
7456
- {
7457
- operation: "selectAll",
7458
- table: "stripeEarlyFraudWarnings"
7459
- },
7460
- context,
7461
- configuration,
7462
- options
7463
- );
7464
- new Map(
7465
- (localEarlyFraudWarningsRes.docs || []).map((p) => [
7466
- p.earlyFraudWarningId,
7467
- p
7468
- ])
7469
- );
7470
7487
  const early_fraud_warnings = await stripe.radar.earlyFraudWarnings.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7471
7488
  const stripeEarlyFraudWarningIds = /* @__PURE__ */ new Set();
7472
7489
  for (const early_fraud_warning of early_fraud_warnings) {
@@ -7501,22 +7518,10 @@ const InvoicesSyncImplementation = defineActionImplementation({
7501
7518
  }),
7502
7519
  name: "invoices",
7503
7520
  handler: async (context, args, configuration, options) => {
7504
- if (configuration.sync.stripeInvoices !== true) return;
7521
+ if (configuration.sync.tables.stripeInvoices !== true) return;
7505
7522
  const stripe = new Stripe(configuration.stripe.secret_key, {
7506
- apiVersion: "2025-08-27.basil"
7523
+ apiVersion: configuration.stripe.version
7507
7524
  });
7508
- const localInvoicesRes = await storeDispatchTyped(
7509
- {
7510
- operation: "selectAll",
7511
- table: "stripeInvoices"
7512
- },
7513
- context,
7514
- configuration,
7515
- options
7516
- );
7517
- new Map(
7518
- (localInvoicesRes.docs || []).map((p) => [p.invoiceId, p])
7519
- );
7520
7525
  const invoices = await stripe.invoices.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7521
7526
  const stripeInvoiceIds = /* @__PURE__ */ new Set();
7522
7527
  for (const invoice of invoices) {
@@ -7558,22 +7563,10 @@ const PaymentIntentsSyncImplementation = defineActionImplementation({
7558
7563
  }),
7559
7564
  name: "paymentIntents",
7560
7565
  handler: async (context, args, configuration, options) => {
7561
- if (configuration.sync.stripePaymentIntents !== true) return;
7566
+ if (configuration.sync.tables.stripePaymentIntents !== true) return;
7562
7567
  const stripe = new Stripe(configuration.stripe.secret_key, {
7563
- apiVersion: "2025-08-27.basil"
7568
+ apiVersion: configuration.stripe.version
7564
7569
  });
7565
- const localPaymentIntentsRes = await storeDispatchTyped(
7566
- {
7567
- operation: "selectAll",
7568
- table: "stripePaymentIntents"
7569
- },
7570
- context,
7571
- configuration,
7572
- options
7573
- );
7574
- new Map(
7575
- (localPaymentIntentsRes.docs || []).map((p) => [p.paymentIntentId, p])
7576
- );
7577
7570
  const paymentIntents = await stripe.paymentIntents.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7578
7571
  const stripePaymentIntentIds = /* @__PURE__ */ new Set();
7579
7572
  for (const paymentIntent of paymentIntents) {
@@ -7608,22 +7601,10 @@ const PaymentMethodsSyncImplementation = defineActionImplementation({
7608
7601
  }),
7609
7602
  name: "paymentMethods",
7610
7603
  handler: async (context, args, configuration, options) => {
7611
- if (configuration.sync.stripePaymentMethods !== true) return;
7604
+ if (configuration.sync.tables.stripePaymentMethods !== true) return;
7612
7605
  const stripe = new Stripe(configuration.stripe.secret_key, {
7613
- apiVersion: "2025-08-27.basil"
7606
+ apiVersion: configuration.stripe.version
7614
7607
  });
7615
- const localPaymentMethodsRes = await storeDispatchTyped(
7616
- {
7617
- operation: "selectAll",
7618
- table: "stripePaymentMethods"
7619
- },
7620
- context,
7621
- configuration,
7622
- options
7623
- );
7624
- new Map(
7625
- (localPaymentMethodsRes.docs || []).map((p) => [p.paymentMethodId, p])
7626
- );
7627
7608
  const paymentMethods = await stripe.paymentMethods.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7628
7609
  const stripePaymentMethodIds = /* @__PURE__ */ new Set();
7629
7610
  for (const paymentMethod of paymentMethods) {
@@ -7658,22 +7639,10 @@ const PayoutsSyncImplementation = defineActionImplementation({
7658
7639
  }),
7659
7640
  name: "payouts",
7660
7641
  handler: async (context, args, configuration, options) => {
7661
- if (configuration.sync.stripePayouts !== true) return;
7642
+ if (configuration.sync.tables.stripePayouts !== true) return;
7662
7643
  const stripe = new Stripe(configuration.stripe.secret_key, {
7663
- apiVersion: "2025-08-27.basil"
7644
+ apiVersion: configuration.stripe.version
7664
7645
  });
7665
- const localPayoutsRes = await storeDispatchTyped(
7666
- {
7667
- operation: "selectAll",
7668
- table: "stripePayouts"
7669
- },
7670
- context,
7671
- configuration,
7672
- options
7673
- );
7674
- new Map(
7675
- (localPayoutsRes.docs || []).map((p) => [p.payoutId, p])
7676
- );
7677
7646
  const payouts = await stripe.payouts.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7678
7647
  const stripePayoutIds = /* @__PURE__ */ new Set();
7679
7648
  for (const payout of payouts) {
@@ -7708,22 +7677,10 @@ const PlansSyncImplementation = defineActionImplementation({
7708
7677
  }),
7709
7678
  name: "plans",
7710
7679
  handler: async (context, args, configuration, options) => {
7711
- if (configuration.sync.stripePlans !== true) return;
7680
+ if (configuration.sync.tables.stripePlans !== true) return;
7712
7681
  const stripe = new Stripe(configuration.stripe.secret_key, {
7713
- apiVersion: "2025-08-27.basil"
7682
+ apiVersion: configuration.stripe.version
7714
7683
  });
7715
- const localPlansRes = await storeDispatchTyped(
7716
- {
7717
- operation: "selectAll",
7718
- table: "stripePlans"
7719
- },
7720
- context,
7721
- configuration,
7722
- options
7723
- );
7724
- new Map(
7725
- (localPlansRes.docs || []).map((p) => [p.planId, p])
7726
- );
7727
7684
  const plans = await stripe.plans.list(
7728
7685
  { limit: 100, expand: ["data.product"] },
7729
7686
  { stripeAccount: args.accountId }
@@ -7761,22 +7718,10 @@ const PricesSyncImplementation = defineActionImplementation({
7761
7718
  }),
7762
7719
  name: "prices",
7763
7720
  handler: async (context, args, configuration, options) => {
7764
- if (configuration.sync.stripePrices !== true) return;
7721
+ if (configuration.sync.tables.stripePrices !== true) return;
7765
7722
  const stripe = new Stripe(configuration.stripe.secret_key, {
7766
- apiVersion: "2025-08-27.basil"
7723
+ apiVersion: configuration.stripe.version
7767
7724
  });
7768
- const localPricesRes = await storeDispatchTyped(
7769
- {
7770
- operation: "selectAll",
7771
- table: "stripePrices"
7772
- },
7773
- context,
7774
- configuration,
7775
- options
7776
- );
7777
- new Map(
7778
- (localPricesRes.docs || []).map((p) => [p.priceId, p])
7779
- );
7780
7725
  const prices = await stripe.prices.list(
7781
7726
  { limit: 100, expand: ["data.product"] },
7782
7727
  { stripeAccount: args.accountId }
@@ -7814,9 +7759,9 @@ const ProductsSyncImplementation = defineActionImplementation({
7814
7759
  }),
7815
7760
  name: "products",
7816
7761
  handler: async (context, args, configuration, options) => {
7817
- if (configuration.sync.stripeProducts !== true) return;
7762
+ if (configuration.sync.tables.stripeProducts !== true) return;
7818
7763
  const stripe = new Stripe(configuration.stripe.secret_key, {
7819
- apiVersion: "2025-08-27.basil"
7764
+ apiVersion: configuration.stripe.version
7820
7765
  });
7821
7766
  const localProductsResponse = await storeDispatchTyped(
7822
7767
  {
@@ -7868,22 +7813,10 @@ const PromotionCodesSyncImplementation = defineActionImplementation({
7868
7813
  }),
7869
7814
  name: "promotionCodes",
7870
7815
  handler: async (context, args, configuration, options) => {
7871
- if (configuration.sync.stripePromotionCodes !== true) return;
7816
+ if (configuration.sync.tables.stripePromotionCodes !== true) return;
7872
7817
  const stripe = new Stripe(configuration.stripe.secret_key, {
7873
- apiVersion: "2025-08-27.basil"
7818
+ apiVersion: configuration.stripe.version
7874
7819
  });
7875
- const localPromotionCodesRes = await storeDispatchTyped(
7876
- {
7877
- operation: "selectAll",
7878
- table: "stripePromotionCodes"
7879
- },
7880
- context,
7881
- configuration,
7882
- options
7883
- );
7884
- new Map(
7885
- (localPromotionCodesRes.docs || []).map((p) => [p.promotionCodeId, p])
7886
- );
7887
7820
  const promotionCodes = await stripe.promotionCodes.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7888
7821
  const stripePromotionCodeIds = /* @__PURE__ */ new Set();
7889
7822
  for (const promotionCode of promotionCodes) {
@@ -7918,22 +7851,10 @@ const RefundsSyncImplementation = defineActionImplementation({
7918
7851
  }),
7919
7852
  name: "refunds",
7920
7853
  handler: async (context, args, configuration, options) => {
7921
- if (configuration.sync.stripeRefunds !== true) return;
7854
+ if (configuration.sync.tables.stripeRefunds !== true) return;
7922
7855
  const stripe = new Stripe(configuration.stripe.secret_key, {
7923
- apiVersion: "2025-08-27.basil"
7856
+ apiVersion: configuration.stripe.version
7924
7857
  });
7925
- const localRefundsRes = await storeDispatchTyped(
7926
- {
7927
- operation: "selectAll",
7928
- table: "stripeRefunds"
7929
- },
7930
- context,
7931
- configuration,
7932
- options
7933
- );
7934
- new Map(
7935
- (localRefundsRes.docs || []).map((p) => [p.refundId, p])
7936
- );
7937
7858
  const refunds = await stripe.refunds.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7938
7859
  const stripeRefundIds = /* @__PURE__ */ new Set();
7939
7860
  for (const refund of refunds) {
@@ -7968,22 +7889,10 @@ const ReviewsSyncImplementation = defineActionImplementation({
7968
7889
  }),
7969
7890
  name: "reviews",
7970
7891
  handler: async (context, args, configuration, options) => {
7971
- if (configuration.sync.stripeReviews !== true) return;
7892
+ if (configuration.sync.tables.stripeReviews !== true) return;
7972
7893
  const stripe = new Stripe(configuration.stripe.secret_key, {
7973
- apiVersion: "2025-08-27.basil"
7894
+ apiVersion: configuration.stripe.version
7974
7895
  });
7975
- const localReviewsRes = await storeDispatchTyped(
7976
- {
7977
- operation: "selectAll",
7978
- table: "stripeReviews"
7979
- },
7980
- context,
7981
- configuration,
7982
- options
7983
- );
7984
- new Map(
7985
- (localReviewsRes.docs || []).map((p) => [p.reviewId, p])
7986
- );
7987
7896
  const reviews = await stripe.reviews.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
7988
7897
  const stripeReviewIds = /* @__PURE__ */ new Set();
7989
7898
  for (const review of reviews) {
@@ -8018,22 +7927,10 @@ const SetupIntentsSyncImplementation = defineActionImplementation({
8018
7927
  }),
8019
7928
  name: "setupIntents",
8020
7929
  handler: async (context, args, configuration, options) => {
8021
- if (configuration.sync.stripeSetupIntents !== true) return;
7930
+ if (configuration.sync.tables.stripeSetupIntents !== true) return;
8022
7931
  const stripe = new Stripe(configuration.stripe.secret_key, {
8023
- apiVersion: "2025-08-27.basil"
7932
+ apiVersion: configuration.stripe.version
8024
7933
  });
8025
- const localSetupIntentsRes = await storeDispatchTyped(
8026
- {
8027
- operation: "selectAll",
8028
- table: "stripeSetupIntents"
8029
- },
8030
- context,
8031
- configuration,
8032
- options
8033
- );
8034
- new Map(
8035
- (localSetupIntentsRes.docs || []).map((p) => [p.setupIntentId, p])
8036
- );
8037
7934
  const setupIntents = await stripe.setupIntents.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
8038
7935
  const stripeSetupIntentIds = /* @__PURE__ */ new Set();
8039
7936
  for (const setupIntent of setupIntents) {
@@ -8068,25 +7965,11 @@ const SubscriptionSchedulesSyncImplementation = defineActionImplementation({
8068
7965
  }),
8069
7966
  name: "subscriptionSchedules",
8070
7967
  handler: async (context, args, configuration, options) => {
8071
- if (configuration.sync.stripeSubscriptionSchedules !== true) return;
7968
+ if (configuration.sync.tables.stripeSubscriptionSchedules !== true)
7969
+ return;
8072
7970
  const stripe = new Stripe(configuration.stripe.secret_key, {
8073
- apiVersion: "2025-08-27.basil"
7971
+ apiVersion: configuration.stripe.version
8074
7972
  });
8075
- const localSubscriptionSchedulesRes = await storeDispatchTyped(
8076
- {
8077
- operation: "selectAll",
8078
- table: "stripeSubscriptionSchedules"
8079
- },
8080
- context,
8081
- configuration,
8082
- options
8083
- );
8084
- new Map(
8085
- (localSubscriptionSchedulesRes.docs || []).map((p) => [
8086
- p.subscriptionScheduleId,
8087
- p
8088
- ])
8089
- );
8090
7973
  const subscriptionSchedules = await stripe.subscriptionSchedules.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
8091
7974
  const stripeSubscriptionScheduleIds = /* @__PURE__ */ new Set();
8092
7975
  for (const subscriptionSchedule of subscriptionSchedules) {
@@ -8121,9 +8004,9 @@ const SubscriptionsSyncImplementation = defineActionImplementation({
8121
8004
  }),
8122
8005
  name: "subscriptions",
8123
8006
  handler: async (context, args, configuration, options) => {
8124
- if (configuration.sync.stripeSubscriptions !== true) return;
8007
+ if (configuration.sync.tables.stripeSubscriptions !== true) return;
8125
8008
  const stripe = new Stripe(configuration.stripe.secret_key, {
8126
- apiVersion: "2025-08-27.basil"
8009
+ apiVersion: configuration.stripe.version
8127
8010
  });
8128
8011
  const subscriptions = await stripe.subscriptions.list(
8129
8012
  {
@@ -8160,17 +8043,38 @@ const SubscriptionsSyncImplementation = defineActionImplementation({
8160
8043
  options
8161
8044
  );
8162
8045
  }
8163
- await storeDispatchTyped(
8046
+ const localSubsResponse = await storeDispatchTyped(
8164
8047
  { operation: "selectAll", table: "stripeSubscriptions" },
8165
8048
  context,
8166
8049
  configuration,
8167
8050
  options
8168
8051
  );
8169
- new Set(
8052
+ const hasSub = new Set(
8170
8053
  subscriptions.map(
8171
8054
  (s) => typeof s.customer === "string" ? s.customer : s.customer.id
8172
8055
  )
8173
8056
  );
8057
+ for (const sub of localSubsResponse.docs || []) {
8058
+ if (!hasSub.has(sub.customerId)) {
8059
+ await storeDispatchTyped(
8060
+ {
8061
+ operation: "upsert",
8062
+ table: "stripeSubscriptions",
8063
+ indexName: "byCustomerId",
8064
+ idField: "customerId",
8065
+ data: {
8066
+ customerId: sub.customerId,
8067
+ subscriptionId: null,
8068
+ stripe: null,
8069
+ lastSyncedAt: Date.now()
8070
+ }
8071
+ },
8072
+ context,
8073
+ configuration,
8074
+ options
8075
+ );
8076
+ }
8077
+ }
8174
8078
  }
8175
8079
  });
8176
8080
  const __vite_glob_0_22$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -8183,22 +8087,10 @@ const TaxIdsSyncImplementation = defineActionImplementation({
8183
8087
  }),
8184
8088
  name: "taxIds",
8185
8089
  handler: async (context, args, configuration, options) => {
8186
- if (configuration.sync.stripeTaxIds !== true) return;
8090
+ if (configuration.sync.tables.stripeTaxIds !== true) return;
8187
8091
  const stripe = new Stripe(configuration.stripe.secret_key, {
8188
- apiVersion: "2025-08-27.basil"
8092
+ apiVersion: configuration.stripe.version
8189
8093
  });
8190
- const localTaxIdsRes = await storeDispatchTyped(
8191
- {
8192
- operation: "selectAll",
8193
- table: "stripeTaxIds"
8194
- },
8195
- context,
8196
- configuration,
8197
- options
8198
- );
8199
- new Map(
8200
- (localTaxIdsRes.docs || []).map((p) => [p.taxIdId, p])
8201
- );
8202
8094
  const taxIds = await stripe.taxIds.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
8203
8095
  const stripeTaxIdIds = /* @__PURE__ */ new Set();
8204
8096
  for (const taxId of taxIds) {
@@ -8233,22 +8125,10 @@ const TransfersSyncImplementation = defineActionImplementation({
8233
8125
  }),
8234
8126
  name: "transfers",
8235
8127
  handler: async (context, args, configuration, options) => {
8236
- if (configuration.sync.stripeTransfers !== true) return;
8128
+ if (configuration.sync.tables.stripeTransfers !== true) return;
8237
8129
  const stripe = new Stripe(configuration.stripe.secret_key, {
8238
- apiVersion: "2025-08-27.basil"
8130
+ apiVersion: configuration.stripe.version
8239
8131
  });
8240
- const localTransfersRes = await storeDispatchTyped(
8241
- {
8242
- operation: "selectAll",
8243
- table: "stripeTransfers"
8244
- },
8245
- context,
8246
- configuration,
8247
- options
8248
- );
8249
- new Map(
8250
- (localTransfersRes.docs || []).map((p) => [p.transferId, p])
8251
- );
8252
8132
  const transfers = await stripe.transfers.list({ limit: 100 }, { stripeAccount: args.accountId }).autoPagingToArray({ limit: 1e4 });
8253
8133
  const stripeTransferIds = /* @__PURE__ */ new Set();
8254
8134
  for (const transfer of transfers) {
@@ -8319,11 +8199,11 @@ if (SYNC_HANDLERS.some(
8319
8199
  throw new Error(
8320
8200
  "Each sync handler file should export a valid implementation"
8321
8201
  );
8322
- const SyncDataImplementation = defineActionImplementation({
8202
+ const SyncTablesImplementation = defineActionImplementation({
8323
8203
  args: v.object({
8324
8204
  withConnect: v.optional(v.boolean())
8325
8205
  }),
8326
- name: "sync",
8206
+ name: "syncTables",
8327
8207
  handler: async (context, args, configuration, options) => {
8328
8208
  if (!args.withConnect) {
8329
8209
  await Promise.all(
@@ -8347,13 +8227,11 @@ const SyncDataImplementation = defineActionImplementation({
8347
8227
  );
8348
8228
  } else {
8349
8229
  const stripe = new Stripe(configuration.stripe.secret_key, {
8350
- apiVersion: "2025-08-27.basil"
8230
+ apiVersion: configuration.stripe.version
8351
8231
  });
8352
8232
  const accounts = await stripe.accounts.list({ limit: 100 }).autoPagingToArray({ limit: 1e4 });
8353
8233
  const accountIds = [void 0, ...accounts.map((account) => account.id)];
8354
8234
  await Promise.all(
8355
- // TODO: syncing an accounts is deleting all other resources
8356
- // thus only last account is being really considered, remove the deletion of the resources
8357
8235
  accountIds.map(async (accountId) => {
8358
8236
  await Promise.all(
8359
8237
  SYNC_HANDLERS.map(async (handler) => {
@@ -8388,7 +8266,7 @@ const SyncPortalImplementation = defineActionImplementation({
8388
8266
  name: "syncPortal",
8389
8267
  handler: async (context, args, configuration) => {
8390
8268
  const stripe = new Stripe(configuration.stripe.secret_key, {
8391
- apiVersion: "2025-08-27.basil"
8269
+ apiVersion: configuration.stripe.version
8392
8270
  });
8393
8271
  const configurations = await stripe.billingPortal.configurations.list({ limit: 100 }).autoPagingToArray({ limit: 1e4 });
8394
8272
  const defaultConfiguration = configurations.find(
@@ -8401,7 +8279,7 @@ const SyncPortalImplementation = defineActionImplementation({
8401
8279
  return;
8402
8280
  }
8403
8281
  await stripe.billingPortal.configurations.create(
8404
- configuration.portal
8282
+ configuration.sync.portal
8405
8283
  );
8406
8284
  console.info(
8407
8285
  "[STRIPE SYNC PORTAL](Created) Default billing portal configuration created."
@@ -8426,7 +8304,7 @@ const accounts_handler = defineWebhookHandler({
8426
8304
  // "financial_connections.account.created",
8427
8305
  ],
8428
8306
  handle: async (event, context, configuration, options) => {
8429
- if (configuration.sync.stripeAccounts !== true) return;
8307
+ if (configuration.sync.tables.stripeAccounts !== true) return;
8430
8308
  const account = event.data.object;
8431
8309
  const entityId = account.metadata?.entityId;
8432
8310
  switch (event.type) {
@@ -8468,7 +8346,7 @@ const billingPortalConfiguration_handler = defineWebhookHandler({
8468
8346
  "billing_portal.configuration.updated"
8469
8347
  ],
8470
8348
  handle: async (event, context, configuration, options) => {
8471
- if (configuration.sync.stripeProducts !== true) return;
8349
+ if (configuration.sync.tables.stripeProducts !== true) return;
8472
8350
  const billingPortalConfiguration = event.data.object;
8473
8351
  switch (event.type) {
8474
8352
  case "billing_portal.configuration.created":
@@ -8503,7 +8381,7 @@ const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
8503
8381
  const capabilities_handler = defineWebhookHandler({
8504
8382
  events: ["capability.updated"],
8505
8383
  handle: async (event, context, configuration, options) => {
8506
- if (configuration.sync.stripeAccounts !== true) return;
8384
+ if (configuration.sync.tables.stripeAccounts !== true) return;
8507
8385
  const capability = event.data.object;
8508
8386
  switch (event.type) {
8509
8387
  case "capability.updated":
@@ -8543,7 +8421,7 @@ const charges_handler = defineWebhookHandler({
8543
8421
  "charge.updated"
8544
8422
  ],
8545
8423
  handle: async (event, context, configuration, options) => {
8546
- if (configuration.sync.stripeCharges !== true) return;
8424
+ if (configuration.sync.tables.stripeCharges !== true) return;
8547
8425
  const charge = event.data.object;
8548
8426
  switch (event.type) {
8549
8427
  case "charge.captured":
@@ -8586,7 +8464,7 @@ const checkoutSessions_handler = defineWebhookHandler({
8586
8464
  "checkout.session.expired"
8587
8465
  ],
8588
8466
  handle: async (event, context, configuration, options) => {
8589
- if (configuration.sync.stripeCheckoutSessions !== true) return;
8467
+ if (configuration.sync.tables.stripeCheckoutSessions !== true) return;
8590
8468
  const checkoutSession = event.data.object;
8591
8469
  switch (event.type) {
8592
8470
  case "checkout.session.async_payment_failed":
@@ -8621,7 +8499,7 @@ const __vite_glob_0_4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
8621
8499
  const coupons_handler = defineWebhookHandler({
8622
8500
  events: ["coupon.created", "coupon.updated", "coupon.deleted"],
8623
8501
  handle: async (event, context, configuration, options) => {
8624
- if (configuration.sync.stripeCoupons !== true) return;
8502
+ if (configuration.sync.tables.stripeCoupons !== true) return;
8625
8503
  const coupon = event.data.object;
8626
8504
  switch (event.type) {
8627
8505
  case "coupon.created":
@@ -8668,7 +8546,7 @@ const __vite_glob_0_5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
8668
8546
  const creditNotes_handler = defineWebhookHandler({
8669
8547
  events: ["credit_note.created", "credit_note.updated", "credit_note.voided"],
8670
8548
  handle: async (event, context, configuration, options) => {
8671
- if (configuration.sync.stripeCreditNotes !== true) return;
8549
+ if (configuration.sync.tables.stripeCreditNotes !== true) return;
8672
8550
  const creditNote = event.data.object;
8673
8551
  switch (event.type) {
8674
8552
  case "credit_note.created":
@@ -8702,7 +8580,7 @@ const __vite_glob_0_6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
8702
8580
  const customers_handler = defineWebhookHandler({
8703
8581
  events: ["customer.created", "customer.updated", "customer.deleted"],
8704
8582
  handle: async (event, context, configuration, options) => {
8705
- if (configuration.sync.stripeCustomers !== true) return;
8583
+ if (configuration.sync.tables.stripeCustomers !== true) return;
8706
8584
  const customer = event.data.object;
8707
8585
  const entityId = customer.metadata?.entityId;
8708
8586
  switch (event.type) {
@@ -8763,7 +8641,7 @@ const disputes_handler = defineWebhookHandler({
8763
8641
  "charge.dispute.funds_withdrawn"
8764
8642
  ],
8765
8643
  handle: async (event, context, configuration, options) => {
8766
- if (configuration.sync.stripeDisputes !== true) return;
8644
+ if (configuration.sync.tables.stripeDisputes !== true) return;
8767
8645
  const dispute = event.data.object;
8768
8646
  switch (event.type) {
8769
8647
  case "charge.dispute.funds_withdrawn":
@@ -8802,7 +8680,7 @@ const earlyFraudWarnings_handler = defineWebhookHandler({
8802
8680
  "radar.early_fraud_warning.updated"
8803
8681
  ],
8804
8682
  handle: async (event, context, configuration, options) => {
8805
- if (configuration.sync.stripeDisputes !== true) return;
8683
+ if (configuration.sync.tables.stripeDisputes !== true) return;
8806
8684
  const earlyFraudWarning = event.data.object;
8807
8685
  switch (event.type) {
8808
8686
  case "radar.early_fraud_warning.created":
@@ -8852,7 +8730,7 @@ const invoices_handler = defineWebhookHandler({
8852
8730
  "invoice.will_be_due"
8853
8731
  ],
8854
8732
  handle: async (event, context, configuration, options) => {
8855
- if (configuration.sync.stripeInvoices !== true) return;
8733
+ if (configuration.sync.tables.stripeInvoices !== true) return;
8856
8734
  const invoice = event.data.object;
8857
8735
  switch (event.type) {
8858
8736
  case "invoice.created":
@@ -8906,7 +8784,7 @@ const __vite_glob_0_10 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
8906
8784
  const mandates_handler = defineWebhookHandler({
8907
8785
  events: ["mandate.updated"],
8908
8786
  handle: async (event, context, configuration, options) => {
8909
- if (configuration.sync.stripeMandates !== true) return;
8787
+ if (configuration.sync.tables.stripeMandates !== true) return;
8910
8788
  const mandate = event.data.object;
8911
8789
  switch (event.type) {
8912
8790
  case "mandate.updated":
@@ -8947,7 +8825,7 @@ const paymentIntents_handler = defineWebhookHandler({
8947
8825
  "payment_intent.succeeded"
8948
8826
  ],
8949
8827
  handle: async (event, context, configuration, options) => {
8950
- if (configuration.sync.stripePaymentIntents !== true) return;
8828
+ if (configuration.sync.tables.stripePaymentIntents !== true) return;
8951
8829
  const paymentIntent = event.data.object;
8952
8830
  switch (event.type) {
8953
8831
  case "payment_intent.created":
@@ -8991,7 +8869,7 @@ const paymentMethods_handler = defineWebhookHandler({
8991
8869
  "payment_method.updated"
8992
8870
  ],
8993
8871
  handle: async (event, context, configuration, options) => {
8994
- if (configuration.sync.stripePaymentMethods !== true) return;
8872
+ if (configuration.sync.tables.stripePaymentMethods !== true) return;
8995
8873
  const paymentMethod = event.data.object;
8996
8874
  switch (event.type) {
8997
8875
  case "payment_method.attached":
@@ -9033,7 +8911,7 @@ const payouts_handler = defineWebhookHandler({
9033
8911
  "payout.updated"
9034
8912
  ],
9035
8913
  handle: async (event, context, configuration, option) => {
9036
- if (configuration.sync.stripePayouts !== true) return;
8914
+ if (configuration.sync.tables.stripePayouts !== true) return;
9037
8915
  const payout = event.data.object;
9038
8916
  switch (event.type) {
9039
8917
  case "payout.updated":
@@ -9070,7 +8948,7 @@ const __vite_glob_0_14 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
9070
8948
  const plans_handler = defineWebhookHandler({
9071
8949
  events: ["plan.created", "plan.deleted", "plan.updated"],
9072
8950
  handle: async (event, context, configuration, options) => {
9073
- if (configuration.sync.stripePlans !== true) return;
8951
+ if (configuration.sync.tables.stripePlans !== true) return;
9074
8952
  const plan = event.data.object;
9075
8953
  switch (event.type) {
9076
8954
  case "plan.created":
@@ -9104,7 +8982,7 @@ const __vite_glob_0_15 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
9104
8982
  const prices_handler = defineWebhookHandler({
9105
8983
  events: ["price.created", "price.updated", "price.deleted"],
9106
8984
  handle: async (event, context, configuration, options) => {
9107
- if (configuration.sync.stripePrices !== true) return;
8985
+ if (configuration.sync.tables.stripePrices !== true) return;
9108
8986
  const price = event.data.object;
9109
8987
  switch (event.type) {
9110
8988
  case "price.created":
@@ -9153,7 +9031,7 @@ const __vite_glob_0_16 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
9153
9031
  const products_handler = defineWebhookHandler({
9154
9032
  events: ["product.created", "product.updated", "product.deleted"],
9155
9033
  handle: async (event, context, configuration, options) => {
9156
- if (configuration.sync.stripeProducts !== true) return;
9034
+ if (configuration.sync.tables.stripeProducts !== true) return;
9157
9035
  const product = event.data.object;
9158
9036
  switch (event.type) {
9159
9037
  case "product.created":
@@ -9202,7 +9080,7 @@ const __vite_glob_0_17 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
9202
9080
  const promotionCodes_handler = defineWebhookHandler({
9203
9081
  events: ["promotion_code.created", "promotion_code.updated"],
9204
9082
  handle: async (event, context, configuration, options) => {
9205
- if (configuration.sync.stripePromotionCodes !== true) return;
9083
+ if (configuration.sync.tables.stripePromotionCodes !== true) return;
9206
9084
  const promotionCode = event.data.object;
9207
9085
  switch (event.type) {
9208
9086
  case "promotion_code.created":
@@ -9240,7 +9118,7 @@ const refunds_handler = defineWebhookHandler({
9240
9118
  "charge.refund.updated"
9241
9119
  ],
9242
9120
  handle: async (event, context, configuration, options) => {
9243
- if (configuration.sync.stripeRefunds !== true) return;
9121
+ if (configuration.sync.tables.stripeRefunds !== true) return;
9244
9122
  const refund = event.data.object;
9245
9123
  switch (event.type) {
9246
9124
  case "refund.created":
@@ -9274,7 +9152,7 @@ const __vite_glob_0_19 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
9274
9152
  const reviews_handler = defineWebhookHandler({
9275
9153
  events: ["review.closed", "review.opened"],
9276
9154
  handle: async (event, context, configuration, options) => {
9277
- if (configuration.sync.stripeReviews !== true) return;
9155
+ if (configuration.sync.tables.stripeReviews !== true) return;
9278
9156
  const review = event.data.object;
9279
9157
  switch (event.type) {
9280
9158
  case "review.closed":
@@ -9313,7 +9191,7 @@ const setupIntent_handler = defineWebhookHandler({
9313
9191
  "setup_intent.succeeded"
9314
9192
  ],
9315
9193
  handle: async (event, context, configuration, options) => {
9316
- if (configuration.sync.stripeSetupIntents !== true) return;
9194
+ if (configuration.sync.tables.stripeSetupIntents !== true) return;
9317
9195
  const setupIntent = event.data.object;
9318
9196
  switch (event.type) {
9319
9197
  case "setup_intent.canceled":
@@ -9361,7 +9239,7 @@ const subscriptionSchedules_handler = defineWebhookHandler({
9361
9239
  "subscription_schedule.updated"
9362
9240
  ],
9363
9241
  handle: async (event, context, configuration, options) => {
9364
- if (configuration.sync.stripeSubscriptionSchedules !== true) return;
9242
+ if (configuration.sync.tables.stripeSubscriptionSchedules !== true) return;
9365
9243
  const subscriptionSchedule = event.data.object;
9366
9244
  switch (event.type) {
9367
9245
  case "subscription_schedule.aborted":
@@ -9408,7 +9286,7 @@ const subscriptions_handler = defineWebhookHandler({
9408
9286
  "customer.subscription.trial_will_end"
9409
9287
  ],
9410
9288
  handle: async (event, context, configuration, options) => {
9411
- if (configuration.sync.stripeSubscriptions !== true) return;
9289
+ if (configuration.sync.tables.stripeSubscriptions !== true) return;
9412
9290
  const subscription = event.data.object;
9413
9291
  switch (event.type) {
9414
9292
  case "customer.subscription.created":
@@ -9452,7 +9330,7 @@ const taxId_handler = defineWebhookHandler({
9452
9330
  "customer.tax_id.updated"
9453
9331
  ],
9454
9332
  handle: async (event, context, configuration, options) => {
9455
- if (configuration.sync.stripeTaxIds !== true) return;
9333
+ if (configuration.sync.tables.stripeTaxIds !== true) return;
9456
9334
  const taxId = event.data.object;
9457
9335
  switch (event.type) {
9458
9336
  case "customer.tax_id.created":
@@ -9492,7 +9370,7 @@ const transfers_handler = defineWebhookHandler({
9492
9370
  // "treasury.credit_reversal.created"
9493
9371
  ],
9494
9372
  handle: async (event, context, configuration, options) => {
9495
- if (configuration.sync.stripeAccounts !== true) return;
9373
+ if (configuration.sync.tables.stripeAccounts !== true) return;
9496
9374
  const transfer = event.data.object;
9497
9375
  switch (event.type) {
9498
9376
  case "transfer.created":
@@ -9571,7 +9449,7 @@ const webhookImplementation = async (configuration, options, context, request, c
9571
9449
  const signature = request.headers.get("Stripe-Signature");
9572
9450
  if (!signature) return new Response("No signature", { status: 400 });
9573
9451
  const stripe = stripe_ ? stripe_ : new Stripe(configuration.stripe.secret_key, {
9574
- apiVersion: "2025-08-27.basil"
9452
+ apiVersion: configuration.stripe.version
9575
9453
  });
9576
9454
  if (typeof signature !== "string")
9577
9455
  return new Response("Invalid signature", { status: 400 });
@@ -9606,12 +9484,12 @@ const SyncAccountWebhookImplementation = defineActionImplementation({
9606
9484
  args: v.object({}),
9607
9485
  name: "syncAccountWebhook",
9608
9486
  handler: async (context, args, configuration) => {
9609
- const url = `${process.env.CONVEX_SITE_URL}${configuration.webhook.path}`;
9487
+ const url = `${process.env.CONVEX_SITE_URL}${configuration.sync.webhooks.account.path}`;
9610
9488
  const events = new Set(
9611
9489
  WEBHOOK_HANDLERS.map((handler) => handler.events).flat()
9612
9490
  );
9613
9491
  const stripe = new Stripe(configuration.stripe.secret_key, {
9614
- apiVersion: "2025-08-27.basil"
9492
+ apiVersion: configuration.stripe.version
9615
9493
  });
9616
9494
  const endpoints = await stripe.webhookEndpoints.list({ limit: 100 }).autoPagingToArray({ limit: 1e4 });
9617
9495
  const endpoint = endpoints.find(
@@ -9637,10 +9515,9 @@ const SyncAccountWebhookImplementation = defineActionImplementation({
9637
9515
  const endpoint2 = await stripe.webhookEndpoints.create({
9638
9516
  url,
9639
9517
  enabled_events: Array.from(events),
9640
- description: configuration.webhook.description,
9641
- // TODO: move version to a global constant or configuration
9642
- api_version: "2025-08-27.basil",
9643
- metadata: configuration.webhook.metadata,
9518
+ description: configuration.sync.webhooks.account.description,
9519
+ api_version: configuration.stripe.version,
9520
+ metadata: configuration.sync.webhooks.account.metadata,
9644
9521
  connect: false
9645
9522
  });
9646
9523
  console.info(
@@ -9654,12 +9531,12 @@ const SyncConnectWebhookImplementation = defineActionImplementation({
9654
9531
  args: v.object({}),
9655
9532
  name: "syncConnectWebhook",
9656
9533
  handler: async (context, args, configuration) => {
9657
- const url = `${process.env.CONVEX_SITE_URL}${configuration.webhook.path}?connect=true`;
9534
+ const url = `${process.env.CONVEX_SITE_URL}${configuration.sync.webhooks.connect.path}`;
9658
9535
  const events = new Set(
9659
9536
  WEBHOOK_HANDLERS.map((handler) => handler.events).flat()
9660
9537
  );
9661
9538
  const stripe = new Stripe(configuration.stripe.secret_key, {
9662
- apiVersion: "2025-08-27.basil"
9539
+ apiVersion: configuration.stripe.version
9663
9540
  });
9664
9541
  const endpoints = await stripe.webhookEndpoints.list({ limit: 100 }).autoPagingToArray({ limit: 1e4 });
9665
9542
  const endpoint = endpoints.find(
@@ -9685,10 +9562,9 @@ const SyncConnectWebhookImplementation = defineActionImplementation({
9685
9562
  const endpoint2 = await stripe.webhookEndpoints.create({
9686
9563
  url,
9687
9564
  enabled_events: Array.from(events),
9688
- description: configuration.webhook.description,
9689
- // TODO: move version to a global constant or configuration
9690
- api_version: "2025-08-27.basil",
9691
- metadata: configuration.webhook.metadata,
9565
+ description: configuration.sync.webhooks.connect.description,
9566
+ api_version: configuration.stripe.version,
9567
+ metadata: configuration.sync.webhooks.connect.metadata,
9692
9568
  connect: true
9693
9569
  });
9694
9570
  console.info(
@@ -9700,7 +9576,7 @@ const SyncConnectWebhookImplementation = defineActionImplementation({
9700
9576
  });
9701
9577
  const SyncImplementation = defineActionImplementation({
9702
9578
  args: v.object({
9703
- data: v.union(
9579
+ tables: v.union(
9704
9580
  v.boolean(),
9705
9581
  v.object({ withConnect: v.optional(v.boolean()) })
9706
9582
  ),
@@ -9715,7 +9591,7 @@ const SyncImplementation = defineActionImplementation({
9715
9591
  }),
9716
9592
  name: "sync",
9717
9593
  handler: async (context, {
9718
- data,
9594
+ tables,
9719
9595
  webhooks,
9720
9596
  // TODO: enable catalog and portal setup for accounts as well, except if enabling it on root enables it on sub accounts too
9721
9597
  portal,
@@ -9733,16 +9609,16 @@ const SyncImplementation = defineActionImplementation({
9733
9609
  "catalog"
9734
9610
  ],
9735
9611
  [
9736
- Boolean(data),
9737
- () => SyncDataImplementation.handler(
9612
+ Boolean(tables),
9613
+ () => SyncTablesImplementation.handler(
9738
9614
  context,
9739
9615
  {
9740
- withConnect: typeof data === "object" && data.withConnect
9616
+ withConnect: typeof tables === "object" && tables.withConnect
9741
9617
  },
9742
9618
  configuration,
9743
9619
  options
9744
9620
  ),
9745
- "data"
9621
+ "tables"
9746
9622
  ],
9747
9623
  [
9748
9624
  Boolean(webhooks?.account),
@@ -9782,6 +9658,7 @@ const SyncImplementation = defineActionImplementation({
9782
9658
  });
9783
9659
  const buildHttp = (configuration, options) => ({
9784
9660
  webhook: {
9661
+ // TODO: should be using the url from the stripe webhook
9785
9662
  path: "/stripe/webhook",
9786
9663
  method: "POST",
9787
9664
  handler: (context, request, stripe) => {
@@ -9819,10 +9696,31 @@ const internalConvexStripe = (configuration_, options_) => {
9819
9696
  );
9820
9697
  return {
9821
9698
  stripe: {
9699
+ /** Raw HTTP handler descriptors. Prefer `addHttpRoutes` unless you need manual control. */
9822
9700
  http: http_,
9701
+ /** A pre-configured Stripe SDK client using your `secret_key` and `version`. */
9823
9702
  client: new Stripe(ConvexStripeInternalConfiguration.stripe.secret_key, {
9824
- apiVersion: "2025-08-27.basil"
9703
+ apiVersion: ConvexStripeInternalConfiguration.stripe.version
9825
9704
  }),
9705
+ /**
9706
+ * Registers the Stripe webhook and redirect routes on your Convex `HttpRouter`.
9707
+ * Call this inside your `convex/http.ts` file.
9708
+ *
9709
+ * - `POST /stripe/webhook` receives and verifies Stripe webhook events.
9710
+ * - `GET /stripe/return/*` handles post-payment/portal redirect flows.
9711
+ *
9712
+ * @param http - Your Convex `HttpRouter` instance.
9713
+ * @param config - Optional config override (defaults to the root configuration).
9714
+ *
9715
+ * @example
9716
+ * // convex/http.ts
9717
+ * import { httpRouter } from "convex/server";
9718
+ * import { stripe } from "./stripe";
9719
+ *
9720
+ * const http = httpRouter();
9721
+ * stripe.addHttpRoutes(http);
9722
+ * export default http;
9723
+ */
9826
9724
  addHttpRoutes: (http, config) => {
9827
9725
  config = normalizeConfiguration(config || configuration_);
9828
9726
  http.route({
@@ -9840,6 +9738,14 @@ const internalConvexStripe = (configuration_, options_) => {
9840
9738
  })
9841
9739
  });
9842
9740
  },
9741
+ /**
9742
+ * Opens a Stripe Billing Portal session for an existing customer.
9743
+ * Use this to let users manage their subscription, invoices, and payment methods.
9744
+ *
9745
+ * @param context - The Convex action context.
9746
+ * @param args - Customer identifier and return URL.
9747
+ * @param options - Optional overrides (e.g. portal configuration ID).
9748
+ */
9843
9749
  portal: (context, args, options = {}) => PortalImplementation.handler(
9844
9750
  context,
9845
9751
  args,
@@ -9847,6 +9753,14 @@ const internalConvexStripe = (configuration_, options_) => {
9847
9753
  ConvexStripeInternalConfiguration,
9848
9754
  ConvexStripeInternalOptions
9849
9755
  ),
9756
+ /**
9757
+ * Creates a Stripe Checkout session in `subscription` mode.
9758
+ * Redirects the user to Stripe Checkout to set up a recurring subscription.
9759
+ *
9760
+ * @param context - The Convex action context.
9761
+ * @param args - Price ID, customer info, and success/cancel URLs.
9762
+ * @param options - Optional overrides for the Checkout session.
9763
+ */
9850
9764
  subscribe: (context, args, options = {}) => SubscribeImplementation.handler(
9851
9765
  context,
9852
9766
  args,
@@ -9854,6 +9768,13 @@ const internalConvexStripe = (configuration_, options_) => {
9854
9768
  ConvexStripeInternalConfiguration,
9855
9769
  ConvexStripeInternalOptions
9856
9770
  ),
9771
+ /**
9772
+ * Creates a Stripe Checkout session in `payment` mode (one-time payment).
9773
+ *
9774
+ * @param context - The Convex action context.
9775
+ * @param args - Price ID, quantity, and success/cancel URLs.
9776
+ * @param options - Optional overrides for the Checkout session.
9777
+ */
9857
9778
  pay: (context, args, options = {}) => PayImplementation.handler(
9858
9779
  context,
9859
9780
  args,
@@ -9862,6 +9783,13 @@ const internalConvexStripe = (configuration_, options_) => {
9862
9783
  ConvexStripeInternalOptions
9863
9784
  ),
9864
9785
  customers: {
9786
+ /**
9787
+ * Creates a new Stripe Customer and stores it in your Convex database.
9788
+ *
9789
+ * @param context - The Convex action context.
9790
+ * @param args - Customer details (email, name, metadata, etc.).
9791
+ * @param options - Optional overrides for the customer creation.
9792
+ */
9865
9793
  create: (context, args, options = {}) => CreateCustomerImplementation.handler(
9866
9794
  context,
9867
9795
  args,
@@ -9871,6 +9799,14 @@ const internalConvexStripe = (configuration_, options_) => {
9871
9799
  )
9872
9800
  },
9873
9801
  accounts: {
9802
+ /**
9803
+ * Creates a new Stripe Connect account (Express or Custom).
9804
+ * Use this to onboard sellers, platforms, or service providers.
9805
+ *
9806
+ * @param context - The Convex action context.
9807
+ * @param args - Account type, email, and capabilities.
9808
+ * @param options - Optional overrides for the account creation.
9809
+ */
9874
9810
  create: (context, args, options = {}) => CreateAccountImplementation.handler(
9875
9811
  context,
9876
9812
  args,
@@ -9878,6 +9814,14 @@ const internalConvexStripe = (configuration_, options_) => {
9878
9814
  ConvexStripeInternalConfiguration,
9879
9815
  ConvexStripeInternalOptions
9880
9816
  ),
9817
+ /**
9818
+ * Creates a Stripe Connect Account Link for onboarding.
9819
+ * Redirects the connected account holder to Stripe's hosted onboarding flow.
9820
+ *
9821
+ * @param context - The Convex action context.
9822
+ * @param args - Account ID, refresh URL, and return URL.
9823
+ * @param options - Optional overrides for the account link.
9824
+ */
9881
9825
  link: (context, args, options = {}) => {
9882
9826
  return CreateAccountLinkImplementation.handler(
9883
9827
  context,
@@ -9889,6 +9833,10 @@ const internalConvexStripe = (configuration_, options_) => {
9889
9833
  }
9890
9834
  }
9891
9835
  },
9836
+ /**
9837
+ * Internal Convex mutation that persists a Stripe object into your database.
9838
+ * Typically called from within the webhook handler not meant for direct use.
9839
+ */
9892
9840
  store: internalMutationGeneric({
9893
9841
  args: StoreImplementation.args,
9894
9842
  handler: async (context, args) => StoreImplementation.handler(
@@ -9898,6 +9846,11 @@ const internalConvexStripe = (configuration_, options_) => {
9898
9846
  ConvexStripeInternalOptions
9899
9847
  )
9900
9848
  }),
9849
+ /**
9850
+ * Internal Convex action that syncs Stripe catalog data (products, prices,
9851
+ * webhooks, portal config) into Stripe based on your `sync` configuration.
9852
+ * Run this manually or on deploy to keep Stripe in sync with your config.
9853
+ */
9901
9854
  sync: internalActionGeneric({
9902
9855
  args: SyncImplementation.args,
9903
9856
  handler: (context, args) => SyncImplementation.handler(
@@ -9912,5 +9865,8 @@ const internalConvexStripe = (configuration_, options_) => {
9912
9865
  export {
9913
9866
  Logger,
9914
9867
  internalConvexStripe,
9915
- stripeTables
9868
+ stripeTables,
9869
+ syncAllTables,
9870
+ syncAllTablesExcept,
9871
+ syncOnlyTables
9916
9872
  };