better_auth-stripe 0.2.0 → 0.5.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd6fea79b678b06d713919a087366ca4d6e0e160e5623e0e2b4c788e5041e7ae
4
- data.tar.gz: 96fdab018ed1cdce8beb551052b36ebdea06d832daf178ea54727472ebd604a6
3
+ metadata.gz: 50cbd34a0653ee11f468c468680cab8488c7c9237222988a5081d3f4a9360854
4
+ data.tar.gz: 96a160c8321fd680d82836be2757dbbc3db3836d454151e5a48f864221d1e7c5
5
5
  SHA512:
6
- metadata.gz: f8b8e916a57096cca616e465cdf4d5ab2688b4ed4592c794a8309f4c71523c8550750a8360b2e76e357743cb52258e214ddf04a28bb232e371302926a3af328d
7
- data.tar.gz: 3b2f8193888d31bb65992147081a022c8952a152b3d5642b80364ad0c18e6c9a5e6cdce8c36c09287ba5823f3ffd95e65a82b92ced1f290024b0c69635bee93d
6
+ metadata.gz: 6bf99b4001607d42cf0622868dac3f53e02b8116a65f6dd6cb8018b092c20ac6dda31359cc6ed3ae267461576a78c56ffc43ff9b494ca33d05e95dcd1313fc35
7
+ data.tar.gz: 1eac1624ebfedeedfd0cc57b7a1f29d5011580bf7ee0ad6c4d87e6555fe24572838946066afb9bf9c60df4b954191de0b8e1b498f86154c22271ffeb449f299b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.2.1] - 2026-04-30
6
+
7
+ - Fixed Stripe checkout and subscription parity edge cases for reused customer IDs, plugin-owned schedule releases, missing checkout sessions, plan limits, and organization reference validation.
8
+ - Expanded Stripe organization and subscription parity coverage.
9
+
5
10
  ## [0.2.0] - 2026-04-29
6
11
 
7
12
  - Aligned Stripe subscription, checkout, portal, webhook, customer, and organization flows with upstream Better Auth behavior.
@@ -257,13 +257,14 @@ module BetterAuth
257
257
  raise APIError.new("BAD_REQUEST", message: STRIPE_ERROR_CODES.fetch("SUBSCRIPTION_NOT_FOUND")) unless subscription_to_update && subscription_to_update["referenceId"] == reference_id
258
258
  end
259
259
 
260
+ subscriptions = subscription_to_update ? [subscription_to_update] : ctx.context.adapter.find_many(model: "subscription", where: [{field: "referenceId", value: reference_id}])
261
+ reference_customer_id = subscriptions.find { |entry| entry["stripeCustomerId"] }&.fetch("stripeCustomerId", nil)
260
262
  customer_id = if customer_type == "organization"
261
- subscription_to_update&.fetch("stripeCustomerId", nil) || stripe_organization_customer(config, ctx, reference_id, body[:metadata])
263
+ subscription_to_update&.fetch("stripeCustomerId", nil) || reference_customer_id || stripe_organization_customer(config, ctx, reference_id, body[:metadata])
262
264
  else
263
- subscription_to_update&.fetch("stripeCustomerId", nil) || user["stripeCustomerId"] || stripe_create_customer(config, ctx, user, body[:metadata])
265
+ subscription_to_update&.fetch("stripeCustomerId", nil) || reference_customer_id || user["stripeCustomerId"] || stripe_create_customer(config, ctx, user, body[:metadata])
264
266
  end
265
267
 
266
- subscriptions = subscription_to_update ? [subscription_to_update] : ctx.context.adapter.find_many(model: "subscription", where: [{field: "referenceId", value: reference_id}])
267
268
  active_or_trialing = subscriptions.find { |entry| stripe_active_or_trialing?(entry) }
268
269
  active_stripe_subscriptions = stripe_active_subscriptions(config, customer_id)
269
270
  active_stripe = active_stripe_subscriptions.find do |entry|
@@ -295,6 +296,8 @@ module BetterAuth
295
296
  end
296
297
 
297
298
  if active_stripe
299
+ stripe_release_plugin_schedule(ctx, config, customer_id, active_stripe, active_or_trialing || subscription_to_update)
300
+
298
301
  if body[:schedule_at_period_end]
299
302
  url = stripe_schedule_plan_change(ctx, config, active_stripe, active_or_trialing, plan, price_id, requested_seats, seat_only_plan, body)
300
303
  next ctx.json({url: url, redirect: stripe_redirect?(body)})
@@ -517,7 +520,13 @@ module BetterAuth
517
520
  subscription_id = query[:subscription_id]
518
521
  if checkout_session_id
519
522
  callback = callback.to_s.gsub("{CHECKOUT_SESSION_ID}", checkout_session_id.to_s)
520
- checkout_session = stripe_client(config || {}).checkout.sessions.retrieve(checkout_session_id)
523
+ checkout_session = begin
524
+ stripe_client(config || {}).checkout.sessions.retrieve(checkout_session_id)
525
+ rescue
526
+ nil
527
+ end
528
+ raise ctx.redirect(stripe_url(ctx, callback)) unless checkout_session
529
+
521
530
  metadata = normalize_hash(stripe_fetch(checkout_session || {}, "metadata") || {})
522
531
  subscription_id = metadata[:subscription_id]
523
532
  end
@@ -814,7 +823,12 @@ module BetterAuth
814
823
  def stripe_plans(config)
815
824
  plans = stripe_subscription_options(config)[:plans] || []
816
825
  plans = plans.call if plans.respond_to?(:call)
817
- Array(plans).map { |plan| normalize_hash(plan) }
826
+ Array(plans).map do |plan|
827
+ normalized = normalize_hash(plan)
828
+ limits = stripe_fetch(plan, "limits")
829
+ normalized[:limits] = limits if limits
830
+ normalized
831
+ end
818
832
  end
819
833
 
820
834
  def stripe_plan_by_name(config, name)
@@ -844,7 +858,7 @@ module BetterAuth
844
858
  raise APIError.new("BAD_REQUEST", message: STRIPE_ERROR_CODES.fetch("ORGANIZATION_SUBSCRIPTION_NOT_ENABLED")) unless config.dig(:organization, :enabled)
845
859
 
846
860
  reference_id = explicit_reference_id || session.fetch(:session)["activeOrganizationId"]
847
- raise APIError.new("BAD_REQUEST", message: STRIPE_ERROR_CODES.fetch("ORGANIZATION_NOT_FOUND")) if reference_id.to_s.empty?
861
+ raise APIError.new("BAD_REQUEST", message: STRIPE_ERROR_CODES.fetch("ORGANIZATION_REFERENCE_ID_REQUIRED")) if reference_id.to_s.empty?
848
862
  reference_id
849
863
  end
850
864
 
@@ -1023,6 +1037,28 @@ module BetterAuth
1023
1037
  stripe_url(ctx, body[:return_url] || "/")
1024
1038
  end
1025
1039
 
1040
+ def stripe_release_plugin_schedule(ctx, config, customer_id, active_stripe, db_subscription)
1041
+ return unless stripe_schedule_id(active_stripe)
1042
+ return unless stripe_client(config).respond_to?(:subscription_schedules)
1043
+
1044
+ schedules = stripe_client(config).subscription_schedules.list(customer: customer_id)
1045
+ active_subscription_id = stripe_fetch(active_stripe, "id")
1046
+ existing = Array(stripe_fetch(schedules, "data")).find do |schedule|
1047
+ subscription = stripe_fetch(schedule, "subscription")
1048
+ schedule_subscription_id = subscription.is_a?(Hash) ? stripe_id(subscription) : subscription
1049
+ metadata = stripe_fetch(schedule, "metadata") || {}
1050
+ schedule_subscription_id == active_subscription_id &&
1051
+ stripe_fetch(schedule, "status") == "active" &&
1052
+ stripe_metadata_fetch(metadata, "source") == "@better-auth/stripe"
1053
+ end
1054
+ return unless existing
1055
+
1056
+ stripe_client(config).subscription_schedules.release(stripe_id(existing))
1057
+ if db_subscription
1058
+ ctx.context.adapter.update(model: "subscription", where: [{field: "id", value: db_subscription.fetch("id")}], update: {stripeScheduleId: nil})
1059
+ end
1060
+ end
1061
+
1026
1062
  def stripe_direct_subscription_update?(old_plan, plan, auto_managed_seats)
1027
1063
  return true if auto_managed_seats && old_plan && old_plan[:seat_price_id] != plan[:seat_price_id]
1028
1064
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module BetterAuth
4
4
  module Stripe
5
- VERSION = "0.2.0"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_auth-stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Sala