Main - #115
Conversation
release: promote development → main (2026-06-19T05:13:28Z)
Promote development → main (bom1 region)
release: promote development → main (2026-06-20T14:07:32Z)
release: promote development → main (2026-06-23T14:29:25Z)
release: promote development → main (2026-06-23T15:03:03Z)
release: promote development → main (2026-06-23T15:41:26Z)
release: promote development → main (2026-06-23T16:36:19Z)
…bservability, Next.js security - stripe-webhook: grant entitlement on mode=payment + async_payment_succeeded (one-time/lifetime purchases were silently dropped); reuses subscription-handler upsert path (email/current_period_end), ~100yr period for lifetime. - PayCraftBillingManager: replace 3 silent catches with PayCraftLogger.onError (transferToDevice, revokeCurrentDevice, applyPremiumResult); add 11 unit tests covering premium/cache application, logout reset, OAuth error, OTP decisioning, transfer abort guard. - dashboard: bump Next.js 14.2.15 -> 14.2.35 (resolves the 2025-12-11 critical CVE). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e-existing UI files) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(paycraft): production hardening — lifetime entitlement + billing observability + Next.js security
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
paycraft-docs | 68af408 | Jul 14 2026, 11:43 AM |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughPayCraftBillingManager now logs selected failures and gains deterministic state and RPC tests. Stripe webhooks now grant lifetime entitlements for settled payment-mode checkouts, including asynchronous payments. UI imports and the dashboard Next.js version are updated. ChangesBilling manager behavior
Stripe payment entitlements
Maintenance updates
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Stripe
participant stripe_webhook
participant handleSubscriptionEvent
Stripe->>stripe_webhook: checkout.session.completed or checkout.session.async_payment_succeeded
stripe_webhook->>stripe_webhook: Check payment mode and settlement
stripe_webhook->>handleSubscriptionEvent: Create lifetime entitlement
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
supabase/functions/stripe-webhook/index.ts (1)
205-261: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate lifetime-entitlement construction between the two handlers.
Lines 236-260 (completed handler) and 284-305 (async handler) build the exact same
lifetimePeriodEnd,oneTimeId, andhandleSubscriptionEventpayload. Extracting a shared helper (e.g.grantLifetimeEntitlement(session, tenantId, eventType, email)) removes the duplication and prevents the two paths from silently drifting apart on future edits.Also applies to: 265-308
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/stripe-webhook/index.ts` around lines 205 - 261, Extract the duplicated lifetime-entitlement construction from the completed and async payment handlers into a shared helper, such as grantLifetimeEntitlement, accepting the session, tenantId, eventType, and email. Move the lifetimePeriodEnd calculation, oneTimeId selection, and handleSubscriptionEvent payload into that helper, then call it from both branches while preserving the existing payment-settlement guard and behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/functions/stripe-webhook/index.ts`:
- Around line 229-234: The payment-status guard in the checkout session handling
must treat "no_payment_required" as settled. Update the condition around
session.payment_status to block only "unpaid" (while preserving the existing
wait-and-break behavior), allowing "paid" and "no_payment_required" sessions to
continue to entitlement processing.
---
Nitpick comments:
In `@supabase/functions/stripe-webhook/index.ts`:
- Around line 205-261: Extract the duplicated lifetime-entitlement construction
from the completed and async payment handlers into a shared helper, such as
grantLifetimeEntitlement, accepting the session, tenantId, eventType, and email.
Move the lifetimePeriodEnd calculation, oneTimeId selection, and
handleSubscriptionEvent payload into that helper, then call it from both
branches while preserving the existing payment-settlement guard and behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 924e6f37-65b1-429d-a711-b9bd02c62981
⛔ Files ignored due to path filters (1)
dashboard/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/core/PayCraftBillingManager.ktcmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/ui/PayCraftBanner.ktcmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/ui/PayCraftPaywall.ktcmp-paycraft/src/commonTest/kotlin/com/mobilebytelabs/paycraft/core/PayCraftBillingManagerTest.ktdashboard/package.jsonsupabase/functions/stripe-webhook/index.ts
…checkout) CodeRabbit (PR #115): a fully-discounted payment-mode checkout completes with payment_status='no_payment_required'. The prior guard skipped entitlement for anything != 'paid' and waited for async_payment_succeeded, which never fires for such sessions → the user never got lifetime access. Now grant on both 'paid' and 'no_payment_required'; only genuinely 'unpaid' async sessions await settlement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ayment-required fix(stripe-webhook): grant lifetime entitlement on no_payment_required (100%-off checkout)
…l deploy) #114 bumped next 14.2.15→14.2.35 in package.json via npm, so pnpm-lock.yaml stayed at 14.2.15. Vercel builds with 'pnpm install --frozen-lockfile' → ERR_PNPM_OUTDATED_LOCKFILE (lockfile 14.2.15 ≠ manifest 14.2.35) → production build failed. Regenerated the lock with pnpm 10 so frozen-install matches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(dashboard): sync pnpm-lock.yaml with next@14.2.35 — unblocks Vercel deploy
Description
Type of Change
Related Issues
Fixes #
Checklist
./gradlew spotlessApplyto format my code./gradlew detektand fixed any issuesTesting
Screenshots (if applicable)
Additional Notes
Summary by CodeRabbit