Add confirmationMode to merchantResources - #181
nicolasalmeida-stark wants to merge 1 commit into
Conversation
edu-stark
left a comment
There was a problem hiding this comment.
Review against the Python reference and the backend services (read-only pass over every open PR, 2026-09-17). Findings below; happy to help with the rebase once the content points are addressed.
#181 - Add confirmationMode to merchantResources
- Repo: /Users/eduardo.santos/git/starkbank/sdk-node (default
master, headorigin/pr-181) - Author: Nicolas | 1 commit
d3a6918| 13 files, +221/-12 | forked atcd8b4eb(2026-07-21) - Branch shape: single non-merge commit -> mergeable shape once rebased.
- Verdict: request-changes
Rebase status
- Behind by 4 commits on master (
git rev-list --left-right --count origin/master...origin/pr-181->4 1); 2 of them are merge commits (#185 docstrings, #189 dependency bumps), which is where the "2 behind" count comes from. git merge-tree --write-tree origin/master origin/pr-181conflicts in:CHANGELOG.md- both sides insert under## [Unreleased]. Trivial: keep master's### Fixedblock and append the PR's### Addedblock.sdk/merchantSession/merchantSession.js- master's #185 inserted a JSDoc block between theexports.purchasesignature and thepayload = {literal; the PR's hunk uses those two lines as adjacent context. Trivial once theconfirmationModepayload change is dropped (see blocking #1), because then only the constructor hunk remains and it auto-merges.README.mdandsdk/merchantPurchase/merchantPurchase.jsauto-merge cleanly.
- Rebase is trivial (docs-only + one hunk that has to be deleted anyway).
Blocking findings
1. confirmationMode on merchantSession.purchase is rejected by the API - wire bug
sdk/merchantSession/merchantSession.js:77 (signature) and :96 (payload, at PR head)
billingZipCode, metadata, cardId, confirmationMode, user} = {}) {
payload = {
...
"confirmationMode": confirmationMode,- The endpoint is
POST /merchant-session/<uuid>/purchase(api-v2-ms-card-merchant/routes/public.py:39). - Its body whitelist is
mandatoryParameters = ["cardNumber","cardExpiration","amount","fundingType","cardSecurityCode","holderName"]andoptionalParameters = ["installmentCount","tags"](+ the billing/holder/metadata challenge params) -confirmationModeis not in either set:api-v2-ms-card-merchant/middlewares/merchantSessionPurchase.py:35-47. checkJsonParametershard-rejects unknown keys:lib-server/server/utils/parameters.py:26-34returnsCoreApiCode.invalidJson/unknownParameters.- Consequence:
merchantSession.purchase(uuid, {..., confirmationMode: 'manual'})returns a 400invalidJson: unknownParameters: confirmationMode.api.removeNullKeys(payload)hides it when the caller omits the field, so the failure fires exactly when someone uses the new parameter. - It is also redundant: a session purchase inherits confirmationMode from the session -
api-v2-ms-card-merchant/handlers/public/merchantSessionPurchase.py:96(confirmationMode=session["confirmationMode"]), and the backend's own test asserts it (tests/handlers/public/merchantSessionPurchaseTest.py:273-288: session"manual"->purchase.confirmationMode == "manual"). - Fix: drop
confirmationModefrom theexports.purchasesignature and payload. Keep it on thePurchasesub-resource as a return-only attribute (sdk/merchantSession/purchase.js:37is fine) and keep it as an input onmerchantSession.createonly, which the backend does accept (middlewares/merchantSession.py:196,218). - No test exercises this path, which is why it survived: the PR's new tests only cover
merchantSession.createandmerchantPurchase.create.
2. merchantPurchase.delete docstring/README state a rule the backend does not have
sdk/merchantPurchase/merchantPurchase.js:102 (PR head) - "Only applies to purchases created with confirmationMode "manual"." and the README section "Cancel or reverse a MerchantPurchase" (README.md, new block after line 2696).
DELETE /merchant-purchase/<purchaseId>maps on status alone:approved -> canceled,confirmed -> reversed,paid -> reversed(api-v2-ms-card-merchant/middlewares/merchantPurchase.py:152-168)._validateReversedPurchase(:199-222) and_validateCanceledPurchase(:171-196) contain no confirmationMode check. Only the capture path requires manual mode:_validateConfirmedPurchaseat:224-230(purchase.confirmationMode != MerchantSessionConfirmationMode.manual->purchaseNotInManualConfirmationMode).- So a plain automatic purchase in status
confirmed/paidcan be reversed bydelete; the docstring tells users it cannot. The docstring also omitspaid(the README does mention it). - Fix: drop the "only manual" sentence, add
paidto the statuses, and keep the manual-only wording where it belongs (updatewithstatus: 'confirmed').
Non-blocking notes
types/merchantSession/merchantSession.d.ts:80putsconfirmationMode : stringin the writable block ofMerchantSession.Purchase; once finding #1 is fixed it belongs with thereadonlyattributes, same aschallengeMode.- README "Confirm (capture)" claims the amount must be "between 100 (in cents) and the authorized amount". The middleware only enforces
minValue=100, maxValue=10**15(middlewares/merchantPurchase.py:588-596); the upper bound is not enforced there. - Python parity:
grep -rn "confirmation_mode" /Users/eduardo.santos/git/starkbank/sdk-pythonis empty - the normative surface has neither the attribute normerchantpurchase.delete(Python cancels/reverses viaupdate(status=..., amount=...)). Node would ship ahead of sdk-python; a companion Python PR should land with or before this. - Scope: the title mentions only
confirmationMode, but the PR also addsmerchantPurchase.delete(+index.js/.d.tswiring). The backend does expose it (handlers/public/merchantPurchaseInfo.py:72), and the_delete as deleted.ts pattern andexports.deleteindex wiring match the repo (boleto, webhook, taxPayment...). Worth splitting or retitling. - New tests swallow any error and only assert on the message "Only approved and unconfirmed purchases can be canceled" (which does exist:
utils/apiMessage.py:152). Loose, but it would pass even ifdeletewere broken. - Tree position, docstring shape (JSDoc inside the function body), CHANGELOG shape and README section placement all match the repo's existing form.
Two-line summary for the owner
confirmationMode is real and backend-supported on MerchantSession.create and MerchantPurchase.create, but the PR also bolts it onto merchantSession.purchase, where the API's strict body whitelist rejects unknown keys - so the new parameter 400s, and it is redundant since a session purchase inherits the mode from its session; the delete docstring/README also invent a "manual only" restriction the backend does not enforce.
Ask Nicolas to delete the merchantSession.purchase parameter and fix the two doc claims, then rebase on the current master tip (4 behind; CHANGELOG + one merchantSession.js hunk, both trivial) and force-push - it merges after that.
No description provided.