Skip to content

feat: Add PaywallListener for purchase lifecycle callbacks#804

Draft
tonidero wants to merge 9 commits intomainfrom
feat/add-paywall-listener
Draft

feat: Add PaywallListener for purchase lifecycle callbacks#804
tonidero wants to merge 9 commits intomainfrom
feat/add-paywall-listener

Conversation

@tonidero
Copy link
Copy Markdown
Contributor

@tonidero tonidero commented Mar 17, 2026

Summary

  • Adds a PaywallListener interface with onPurchaseStarted, onPurchaseError, and onPurchaseCancelled optional callbacks for observing purchase lifecycle events within presentPaywall
  • Wires listener into both the regular purchase flow and the express purchase button flow, with try/catch safety around all listener invocations
  • Deprecates PresentPaywallParams.onPurchaseError in favor of listener.onPurchaseError (both still called when both are provided)
  • Adds toast notifications to the example app paywall launcher page to demonstrate listener callbacks

Test plan

  • New unit tests in paywall-listener.test.ts (6 tests) pass
  • Full test suite passes (520 tests)
  • API report updated via api-extractor
  • Manual verification: launch paywall in demo app, confirm toasts appear for purchase started, error, and cancellation events

🤖 Generated with Claude Code

tonidero and others added 3 commits March 17, 2026 14:24
…Paywall

Adds a PaywallListener interface with onPurchaseStarted, onPurchaseError,
and onPurchaseCancelled callbacks, wired into both the regular and express
purchase flows. Deprecates PresentPaywallParams.onPurchaseError in favor
of listener.onPurchaseError. Adds toast notifications to the example app
paywall launcher page to demonstrate the listener in action.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tonidero tonidero force-pushed the feat/add-paywall-listener branch from 45c02cc to 6a01732 Compare March 17, 2026 13:31
tonidero and others added 3 commits March 17, 2026 14:37
…f PurchasesError

Matches the signature of the deprecated PresentPaywallParams.onPurchaseError
for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deduplicates the try/catch-wrapped listener calls from both the regular
and express purchase flows into notifyPurchaseStarted and
notifyPurchaseError helper functions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
display: "flex",
flexDirection: "column",
gap: 8,
zIndex: 1000003,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This puts it on top of both the paywall and the purchase screens.

@tonidero tonidero marked this pull request as ready for review March 17, 2026 13:43
@tonidero tonidero requested review from a team March 17, 2026 13:43
Copy link
Copy Markdown
Contributor

@nicfix nicfix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the approach makes sense, I just think the callbacks for the express purchase button should be passed to the presentExpressPurchaseButton method to make sure they are then passed to the right callbacks inside the component that renders it.

As they are now:

  1. The start purchase will be called every time a Express purchase button is rendered, not clicked
  2. The purchase cancelled works, but if we move it inside the presentExpressPurchaseButton we make it available to that method as well

src/main.ts Outdated
return {};
}
let buttonUpdater: ExpressPurchaseButtonUpdater | null = null;
notifyPurchaseStarted(pkg);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not really the right spot for the ExpressPurchaseButton.
Basically it will be triggered by any rendering of the button in this place.

We should probably expose an explicit parameter to the presentExpressPurchaseButton and pass it down to the component that handles it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohhh my bad... I should have tested that flow 🥴. I will address this next week. Thanks for the feedback!!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, Express Purchase Button it's a bit tricky!

src/main.ts Outdated
if (paywallParams.onPurchaseError) {
paywallParams.onPurchaseError(err);
}
notifyPurchaseError(err);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could pass this to the presentExpressPurchaseButton method as parameter so that it's handled by it instead of here.

@tonidero tonidero marked this pull request as draft March 30, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants