Skip to content

Conversation

@tobihagemann
Copy link
Member

@tobihagemann tobihagemann commented Feb 7, 2026

⚠️ DO NOT MERGE YET. We need to make sure that API/Store are ready and associated PRs are merged first.

The billing page now refreshes the Hub license token through the /licenses/hub/refresh API endpoint instead of exposing it directly from the store response. A captcha challenge is required before the token is issued, and on checkout/modification flows the user is redirected back to Hub automatically. If the refresh fails, a Retry button lets the user re-trigger the captcha and try again (using x-if to fully recreate the widget). Also extracts the captcha widget into the reusable captcha.html partial and fixes Paddle passthrough JSON serialization.

Instead of using the store's token directly, the billing page now
refreshes the license token through the /licenses/hub/refresh API
endpoint with captcha verification. On normal visits the token is
displayed inline; on checkout/modification flows the user is
redirected back to Hub. Also extracts captcha widget into a reusable
partial and fixes Paddle passthrough JSON serialization.
Show a Retry button when the license token refresh fails, allowing
the user to re-trigger the captcha and refresh flow. Switch the
captcha container from x-show to x-if so the ALTCHA widget is fully
destroyed and recreated on retry, guaranteeing a fresh challenge.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 7, 2026

Walkthrough

Adds a license token refresh workflow: new REFRESH_LICENSE_URL constant and HubSubscription.refreshToken() POST flow that handles captcha-verified token refresh, errors, and conditional post-refresh transfer. Replaces direct token usage with verificationToken across load/post/put flows and adds subscription flags needsTokenRefresh and shouldTransferToHub to control refresh and transfer behavior. Updates UI templates to surface captcha-driven refresh states and replaces inline captcha widgets with a reusable captcha partial that supports onVerified callbacks. Adds i18n keys for a retry action. Minor changes to generate-pay-link payload formatting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~23 minutes

Suggested reviewers

  • overheadhunter
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately summarizes the main change: refreshing the Hub license token via API with captcha protection.
Description check ✅ Passed The pull request description clearly explains the changes, including token refresh via API, captcha requirement, auto-redirect flow, retry logic, and the JSON serialization fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/migrate-hub-subscriptions-to-api

No actionable comments were generated in the recent review. 🎉


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@layouts/hub-billing/single.html`:
- Around line 179-194: The "Retry" button is shown even when the captcha is
auto-started because x-show only checks subscriptionData.token; update the Retry
button's visibility to also require that the captcha is not active (e.g. change
its x-show to !subscriptionData.token && !subscriptionData.needsTokenRefresh) so
it is hidden while subscriptionData.needsTokenRefresh is true, or alternatively
keep it visible but change its label logic to a generic action when
subscriptionData.needsTokenRefresh is true; adjust the button that currently
references subscriptionData.token and subscriptionData.needsTokenRefresh
accordingly (the button with `@click.prevent` setting
subscriptionData.errorMessage = ''; subscriptionData.needsTokenRefresh = true).

hidefooter
floating="auto"
@statechange="{{ .captchaState }} = $event.detail.state; if ($event.detail.state === 'verified') { {{ .captchaPayload }} = $event.detail.payload }"
{{ with .auto }}auto="{{ . }}"{{ else }}floating="auto"{{ end }}
Copy link
Member

Choose a reason for hiding this comment

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

What is floating="auto"? I am pretty sure this is not to be confused with auto=...

Copy link
Member Author

Choose a reason for hiding this comment

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

floating="auto" displays the widget as a popup near the submit button and internally sets auto="onsubmit" (see Floating UI docs). This is the default behavior we've used for all captchas until now.

With the new hub-register and hub-billing flows, we need auto="onload" instead so the captcha starts solving immediately. In that case we shouldn't also set floating="auto" since it would override auto back to onsubmit. That's why they're mutually exclusive in the template.

Does that make sense?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants