Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); fix(demos): pass the plugin explicitly when discovering gateways by farhan-t-ottu · Pull Request #175 · ottuco/docs · GitHub
Skip to content

fix(demos): pass the plugin explicitly when discovering gateways - #175

Merged
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main
Aug 24, 2026
Merged

fix(demos): pass the plugin explicitly when discovering gateways#175
farhan-t-ottu merged 2 commits into
mainfrom
fix/159191-checkout-demo-plugin-mismatch-main

Conversation

@farhan-t-ottu

Copy link
Copy Markdown
Contributor

Production (main) counterpart of #174, which targets dev. Same two commits, cherry-picked.

Fixes the interactive Checkout SDK demo failing at the Creating session step.

Refs #159191

Root cause

CheckoutDemoInner.tsx called callPaymentMethods without a plugin, which callPaymentMethods silently defaulted to payment_request, and then created the session with type: "e_commerce". Gateways are enabled per plugin, so discovery returned a gateway the session type does not accept.

This branch matters more than #174: main runs ACTIVE_CONNECT = SANDBOX, which is the merchant the bug actually reproduces on.

Payment Methods callgateways returned
plugin: "payment_request" (what the demo sent)14 — includes cbk-private
plugin: "e_commerce"13cbk-private dropped
POST /b/checkout/v1/pymt-txn/ (type: e_commerce, 14 codes) → 400
["pg code `cbk-private` is not enabled for `e_commerce` plugin."]

Changes

  • src/utils/sandbox.ts — added PaymentPlugin ("e_commerce" | "payment_request", matching the Checkout API type enum). plugin on callPaymentMethods and type on CreateSessionOptions are both now required, removing the two ?? "payment_request" defaults that hid this.
  • All four demos — each declares one plugin source of truth and uses it for both the Payment Methods call and the session type, including the ApiPanel request previews, so the displayed request cannot drift from what is sent.
  • WalletDemo — dropped a || ({} as any) that widened the filter to any and would have silently defeated the new required-plugin check.

Cherry-pick notes

main and dev differ in this area, so reviewers should confirm nothing dev-only leaked. Verified — the diff against main is only the plugin fix, and these stay untouched:

  • ACTIVE_CONNECT = SANDBOX and its docs.ottu.com comment block (dev has KSA)
  • walletDemoConfig.ts keeps currency: "USD" / 10.00 / 8.00 for ottu-sandbox-usd (dev uses KWD)
  • WalletDemo's "Try Wallet at Checkout" / tagged "demo" wording

Verification

Run on this branch against sandbox.ottu.net (main's own merchant), driving each demo in the browser with a fetch recorder capturing real request bodies:

DemoPayment MethodsSession
CheckoutDemoplugin: "e_commerce" → 200201, 13 codes, cbk-private absent
RecurringDemoplugin: "e_commerce" → 200201, type: "e_commerce"
PaymentJourneyplugin: "payment_request" → 200201, Step 3 panel renders type from the constant
WalletDemoplugin: "e_commerce" → 200, returns ottu-sandbox-usdnot reached locally — see below

npm run typecheck and npm run build both pass. Omitting plugin, omitting type, or misspelling either is now a compile error.

WalletDemo's seed step returns 502 {"error":"keycloak_error","message":"Missing Keycloak client secret for backend@sandbox.ottu.net"} locally — SANDBOX_KEYCLOAK_CLIENT_SECRET is not in my .env.local, so the flow stops before session creation. Unrelated to this change: step 1 (the call this PR touches) succeeds, and the step 3 change is type: "e_commerce"type: filter.plugin where filter.plugin === "e_commerce", an identical value. Worth a re-run by someone holding that secret.

🤖 Generated with Claude Code

CheckoutDemo called callPaymentMethods without a plugin, which silently
defaulted to payment_request, then created the session with
type: "e_commerce". On sandbox.ottu.net that discovery returns cbk-private,
which is not enabled for the e-commerce plugin, so the Checkout API rejected
the session:
400 ["pg code `cbk-private` is not enabled for `e_commerce` plugin."]
Each demo now declares its plugin once and uses it for both the Payment
Methods call and the session type, so the two can no longer drift apart.
callPaymentMethods takes plugin as a required PaymentPlugin, removing the
default that hid this; RecurringDemo and PaymentJourney also send the type
they already display in their request panels.
Refs #159191
Addresses PR review on #174.
PaymentJourney's Step 3 request panel still hardcoded
type: "payment_request" while the real call used PLUGIN. Harmless today
because they happen to match, but it is the exact drift this branch
removes, so the panel now reads PLUGIN as well.
CreateSessionOptions.type is now required, dropping its
?? "payment_request" fallback. That silent default is the same footgun
that caused #159191 on the discovery side; every call site already passes
type explicitly, so this is a type-level change only.
Refs #159191
@farhan-t-ottu

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 24, 2026

Copy link
Copy Markdown

Claude finished @farhan-t-ottu's task in 1m 20s —— View job


Review complete

  • Gather context (PR description, changed files list)
  • Read diff for all 6 changed files
  • Review for correctness, consistency with cherry-pick claims, and code quality
  • Post review feedback

Verdict: LGTM. This is a clean, well-scoped fix — the root cause analysis holds up and the diff matches exactly what the description claims.

What I checked

  • src/utils/sandbox.ts: PaymentPlugin type added, both type on CreateSessionOptions and plugin on callPaymentMethods are now required (no more ?? "payment_request" defaults). This correctly turns the silent-mismatch bug class into a compile error.
  • All 4 demos (CheckoutDemoInner.tsx, PaymentJourneyInner.tsx, RecurringDemoInner.tsx, WalletDemoInner.tsx): each declares one PLUGIN/filter.plugin source of truth and threads it through both the Payment Methods discovery call and the session type. I grepped for stray "e_commerce"/"payment_request" string literals across src/ — the only ones left are the five legitimate single-source declarations (one per demo + the walletDemoConfig.ts default + the type definition itself). No drift risk.
  • WalletDemoInner.tsx: confirmed filter (from WALLET_DEMO.pgFilter) stays in scope across step 1 and step 3 inside the same try block in launch, so type: filter.plugin at the session-creation call is valid and correctly mirrors what was discovered. Since pgFilter is a required, non-optional field on WALLET_DEMO, dropping || ({} as any) is safe — it was a needless escape hatch that would've silently defeated the new required-plugin check.
  • ApiPanel previews: in RecurringDemoInner.tsx these render from state.pmRequest/state.citRequest/state.mitRequest, which are built from PLUGIN earlier — so the displayed request can't drift from what's sent. PaymentJourneyInner.tsx's inline ApiPaneldata={{...}} objects were updated in the same diff to use PLUGIN.
  • Cherry-pick hygiene (the PR's main ask for reviewers): verified ACTIVE_CONNECT = SANDBOX in sandbox.ts, walletDemoConfig.ts still has currency: "USD" / 10.00 / 8.00, and the WalletDemo tagged "demo" copy is untouched — nothing dev-only leaked into this branch.

Minor notes (non-blocking)

  • I wasn't able to run npm run typecheck / npm run build myself in this sandbox (no shell approval for npm here), so I relied on static review — the PR body states both pass locally, and the type changes (required fields replacing optional-with-default) are exactly the kind of change tsc would catch immediately if a call site were missed. A CI run would be good confirmation before merge if not already green.
  • Nothing else stood out — no leftover any widening, no unrelated changes, diff size matches the stated scope (58/-15 across 6 files).

@farhan-t-ottu
farhan-t-ottu merged commit 82f73e5 into mainAug 24, 2026
1 check passed
Sign up for freeto 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

@farhan-t-ottu@jab3z