fix: prefill APM fields by canonical key and parse E.164 phone numbers - #277
Draft
roshan-gorasia-cko wants to merge 3 commits into
Draft
fix: prefill APM fields by canonical key and parse E.164 phone numbers#277roshan-gorasia-cko wants to merge 3 commits into
roshan-gorasia-cko wants to merge 3 commits into
Conversation
roshan-gorasia-cko
force-pushed
the
fix/apm-initial-data-prefill
branch
2 times, most recently
from
August 6, 2026 10:47
282832c to
3cc9902
Compare
Prefilling an APM form via `initialData` had two problems. Values were matched only against the payment method's own parameter key, so the documented `initialData.phone_number` silently did nothing whenever a payment method named the field something else (for example `customerPhone`), leaving merchants to discover each one's internal parameter names. `email` and `phone_number` now also match on the parameter's type, so the canonical keys prefill on every payment method. An exact parameter-key match still wins, so a specific field can be targeted or a canonical value overridden. A phone number passed as an E.164 string was dropped into the national number input whole, with the dialing code set to the first entry in the available list. That selected the wrong country, left `+CC` inside the number box and submitted a malformed value. The string is now split on a longest-prefix match against the available dialing codes, falling back to the browser-locale default when the country isn't offered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
roshan-gorasia-cko
force-pushed
the
fix/apm-initial-data-prefill
branch
from
August 6, 2026 10:48
3cc9902 to
89b6b96
Compare
The prefill computed in NextSteps never reached the phone field. The field reads a `value` prop; the form's only call site passed it as `number`, and `Props<T>`'s `[key: string]: any` index signature let the misnamed prop typecheck and vanish into the input's attributes. A prefilled phone rendered as an empty box on the locale default country. `normalizePhoneValue` also returned the pre-#225 `value` key, so a prefilled phone submitted without the user touching the field posted `value` where the API expects `number`. It now emits `number`, matching the declared `PhoneState` and the field's own `oninput`; both keys are still accepted as input, so the documented `initialData` object form keeps working. `validateField` read `value` too, which made `required` pass vacuously for any phone once the field had emitted its own shape. It now reads the national number under either key, so an empty phone is caught. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Three issues stopped
initialDatafrom prefilling an APM form.1. Prefill only matched the payment method's own parameter key.
NextStepslooked upinitialData[param.key], so the documentedinitialData.phone_numbersilently no-op'd whenever a payment method named the field something else (for examplecustomerPhone). In practice a merchant had to discover each payment method's internal parameter names to prefill anything.2. An E.164 phone string wasn't parsed. A
phone_numberpassed as"+48123123123"went into the national-number input whole, with the dialing code set to the first entry in the available list. The+-prefix splitting logic only existed in the phone field's paste/typing handler, so it never ran for seeded state.3. The prefilled phone value never reached the field, and submitted the wrong key. Two separate breaks, both of which made the first two fixes invisible in the browser:
Phonereads avalueprop, but its only call site passed the stored form value asnumber.Props<T>carries an[key: string]: anyindex signature, so the misnamed prop typechecked and was swallowed into the input's attributes. A prefilled phone rendered as an empty box on the default country — the same result as no prefill at all. This dates from the prop rename in fix(apm): rename phone "value" to "number" to conform with the BE API contracts #225.validateFieldread the national number fromvalue, but the field emitsnumber. Once a phone held the field's own shape,actualValuewas the whole object, sorequiredpassed for any phone including an empty one.Changes
resolvePrefilledValue(src/apm/utils.ts) resolves a parameter's prefill value: an exact parameter-key match wins, otherwise the canonical key for that parameter's type (email→ typeemail,phone_number→ typephone). Canonical keys now work on every payment method, and a specific parameter can still be targeted directly or used to override a canonical value.normalizePhoneValue(src/apm/utils.ts) coerces a prefilled phone into the shape the field renders. An E.164 string is split on a longest-prefix match against the available dialing codes (so+1242beats+1), separators are ignored, and the browser-locale default is used when the country isn't offered.value:, andPhoneProps.value/ the field's initial state are keyed onnumber(src/apm/views/utils/form.ts,src/apm/elements/phone.ts).validateFieldreads the national number under either key, sorequiredcatches an empty phone.{ dialing_code, number }rather than its whole internal state, which also carries the flag picker'siso. That emit only started firing once the prop name was fixed, soisowould otherwise have been submitted as a gateway parameter.InitialData(src/apm/types.ts) typesphone_numberasstring | { dialing_code?, value? }and allows payment-method-specific keys.Notes on the key name
The codebase disagreed with itself about whether a phone's national number lives under
valueornumber. This settles onnumber: it matches the API contract per #225, the field's ownoninput, and thePhoneStatethatFormStatealready declared. Both keys are still accepted as input, so the documentedinitialDataobject form keeps working unchanged.Worth a reviewer's eye: the
validateFieldchange is shared by every field type. The pre-existingvaluelookup is kept as a fallback, but it's worth confirming no other field type stores an object with a meaningfulvaluekey.The prefilling docs present
email/phone_numberas universal keys and document the phone value as a bare E.164 string. Both are now true of the SDK; the docs should be extended to cover the object form and to note that a specific parameter key can also be passed and takes precedence.Tests
test/apm/prefill.test.ts— key/type resolution precedence and E.164 splitting.test/apm/phone-prefill-wiring.test.ts— asserts which props the form hands the phone field, what the field renders from a prefill, what it seeds back to the form, andrequiredvalidation. Two loaders intest/support/loadNamespace.tsevaluateform.tsandphone.tsagainst stubbed components to make prop-level assertions possible; the absence of that coverage is why the index-signature mismatch went unnoticed.Reverting the three source fixes fails 4 of the 6 new wiring cases.
yarn test,yarn buildandyarn lintall pass.