Skip to content

Add confirmationMode to merchantResources - #181

Open
nicolasalmeida-stark wants to merge 1 commit into
masterfrom
feature/pre-authorization
Open

nicolasalmeida-stark wants to merge 1 commit into
masterfrom
feature/pre-authorization

Conversation

@nicolasalmeida-stark

Copy link
Copy Markdown
Contributor

No description provided.

@nicolasalmeida-stark

Copy link
Copy Markdown
Contributor Author

@claude

@edu-stark edu-stark left a comment

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.

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, head origin/pr-181)
  • Author: Nicolas | 1 commit d3a6918 | 13 files, +221/-12 | forked at cd8b4eb (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-181 conflicts in:
    • CHANGELOG.md - both sides insert under ## [Unreleased]. Trivial: keep master's ### Fixed block and append the PR's ### Added block.
    • sdk/merchantSession/merchantSession.js - master's #185 inserted a JSDoc block between the exports.purchase signature and the payload = { literal; the PR's hunk uses those two lines as adjacent context. Trivial once the confirmationMode payload change is dropped (see blocking #1), because then only the constructor hunk remains and it auto-merges.
    • README.md and sdk/merchantPurchase/merchantPurchase.js auto-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"] and optionalParameters = ["installmentCount","tags"] (+ the billing/holder/metadata challenge params) - confirmationMode is not in either set: api-v2-ms-card-merchant/middlewares/merchantSessionPurchase.py:35-47.
  • checkJsonParameters hard-rejects unknown keys: lib-server/server/utils/parameters.py:26-34 returns CoreApiCode.invalidJson / unknownParameters.
  • Consequence: merchantSession.purchase(uuid, {..., confirmationMode: 'manual'}) returns a 400 invalidJson: 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 confirmationMode from the exports.purchase signature and payload. Keep it on the Purchase sub-resource as a return-only attribute (sdk/merchantSession/purchase.js:37 is fine) and keep it as an input on merchantSession.create only, 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.create and merchantPurchase.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: _validateConfirmedPurchase at :224-230 (purchase.confirmationMode != MerchantSessionConfirmationMode.manual -> purchaseNotInManualConfirmationMode).
  • So a plain automatic purchase in status confirmed/paid can be reversed by delete; the docstring tells users it cannot. The docstring also omits paid (the README does mention it).
  • Fix: drop the "only manual" sentence, add paid to the statuses, and keep the manual-only wording where it belongs (update with status: 'confirmed').

Non-blocking notes

  • types/merchantSession/merchantSession.d.ts:80 puts confirmationMode : string in the writable block of MerchantSession.Purchase; once finding #1 is fixed it belongs with the readonly attributes, same as challengeMode.
  • 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-python is empty - the normative surface has neither the attribute nor merchantpurchase.delete (Python cancels/reverses via update(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 adds merchantPurchase.delete (+ index.js/.d.ts wiring). The backend does expose it (handlers/public/merchantPurchaseInfo.py:72), and the _delete as delete d.ts pattern and exports.delete index 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 if delete were 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.

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