@wirexapp/card-sdk-core 1.1.0-beta.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,241 @@
1
1
  # @wirexapp/card-sdk-core
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8097859: CVV entry masking — show / hide what was typed into the top-up CVV field. The
8
+ CVV has always been masked as it is typed (a password input); this adds the
9
+ reveal element's masking model to that input, for both collect variants
10
+ (`createCardTopUpFields`, `createCardTopUpForm`). The card number is not
11
+ affected, and with no option passed nothing changes.
12
+
13
+ - `masked` (boolean, default `true`) — the state at mount; `false` starts the
14
+ field shown.
15
+ - `maskToggle: 'button' | 'text' | 'none'` (default `'none'`) — an in-frame
16
+ control at the field's right edge: the reveal's eye / eye-off icon, or a
17
+ text button from the new collect strings `show` / `hide`. It is the same
18
+ control the reveal rows draw (one module in the frames), themed by the same
19
+ `copyIconSize` / `colorCopyIcon` / `colorCopyIconHover` tokens. No `'row'`
20
+ mode: a tap on an input has to focus it. The toggle never takes the focus
21
+ from the field; the value and the caret stay.
22
+ - `maskAfter` (ms, default never) — shown digits re-mask from the frame,
23
+ counted from the moment they are visible.
24
+ - `setMasked(boolean)` on `PciCollectElement` and `PciCollectGroup` (the group
25
+ forwards to its `cvv` field) — host control in place, safe before `mount()`
26
+ resolves and after `destroy()`. Host→frame event `collect-set-masked`, sent
27
+ with the reply-less `PciFrameChannel.post()`.
28
+ - `onMaskedChange({ masked, reason })` — the state the frame applied, once at
29
+ mount (`'init'`) and after every change (`'user'`, `'host'`, `'timeout'`).
30
+ Frame→host event `collect-masked-changed`: a boolean and a reason, never
31
+ the value.
32
+ - `PciCollectGroup.field(name, options?)` takes the same masking options for
33
+ the `cvv` field (they win over the group config's).
34
+ - React: `CardCvvField` takes `masked` (live — forwarded in place, never a
35
+ remount), `maskToggle`, `maskAfter` and `onMaskedChange`. Mirroring
36
+ `onMaskedChange` into the state `masked` is rendered from is safe — the rule
37
+ is "when in doubt, mask": a hide is always sent, a show is not sent when it
38
+ is the echo of the frame's own "shown" report.
39
+
40
+ No reveal gate (`onRevealRequested`) on the input — the digits are the user's
41
+ own typing — and no `maskedPlaceholder`: the masked rendering is the browser's
42
+ password bullet. Microsoft Edge's built-in reveal button is now hidden in the
43
+ CVV field (it showed the digits behind the frame's state); the SDK's toggle
44
+ and `setMasked()` are the only ways to show them, in every browser alike.
45
+ The OCT package's surface is unchanged (its profile has no CVV). Additive
46
+ within protocol v1: frames that predate this ignore the three options and
47
+ `collect-set-masked`, keep the CVV masked and never send
48
+ `collect-masked-changed`; ship the frames first.
49
+
50
+ - 901cddf: Collect failures. `PciFrameRequestError` gains `code`,
51
+ `retryable` and `reason`: the mobile SDK's failure payload
52
+ (`WirexCollectErrorPayload`), with the same values classified by the same rules.
53
+
54
+ - `code` is one of a frozen set: `unauthorized`, `actionRequired`,
55
+ `updateRequired`, `invalidInput`, `temporary`, `failed`. It is typed as the
56
+ `PciFrameErrorCode` union, so a `switch` over it checks exhaustively.
57
+ - `retryable` says whether sending the request again is safe.
58
+ - `reason` is present where one `code` has two remedies: `invalidInput` with
59
+ `cardAlreadyLinked` (enter another card) or `cardLimitReached` (remove one
60
+ first). The set grows; handle an unknown value.
61
+
62
+ The frame classifies a tokenize failure by the backend's business code on a 400
63
+ (`0243`, `0366`), otherwise by the HTTP status. A request without an answer is
64
+ `temporary`; a `Validation failed — …` reply is `invalidInput`. Messages are
65
+ unchanged. Older frames send none of the fields (`code` and `reason` undefined,
66
+ `retryable` false): ship the frames first.
67
+
68
+ - cc46627: Protocol (additive within v1): every frame init config accepts an optional `diagnostics.userId` — an opaque, host-chosen correlation id the frames attach as `user.id` to the error events they report to Wirex (`PciDiagnosticsInit`, docs/ERROR-TRACKING.md §5, §7). Validated in-frame; never an email or wallet address. The wallet documents honour it from this release; the host-side packages do not send it yet (Phase 3).
69
+ - 390c416: New `fontSmoothing` appearance token — `'auto'` (default, as today) or
70
+ `'antialiased'`: the frame document gets `-webkit-font-smoothing:
71
+ antialiased` and `-moz-osx-font-smoothing: grayscale`. Host pages whose
72
+ global CSS antialiases the body (Mantine, Tailwind preflight, most design
73
+ systems) otherwise sit next to frame text that macOS renders visibly heavier
74
+ at the same family, size and weight. Applies to the collect, reveal and
75
+ wallet frames; enumerated and re-validated in the frame, and an older frame
76
+ drops the token and keeps `auto`.
77
+ - b43affc: Wallet availability tells WHY Google Pay is unavailable: `PciWalletAvailability`
78
+ gains `googlePayState` — `ready` / `handoff` / `needs_card` / `unavailable`.
79
+ `needs_card` is an Android device where Google Pay works but no card in Google
80
+ Wallet on the phone qualifies for the cryptogram-only top-up (the probe's
81
+ cryptogram check fails, a `PAN_ONLY` capability check passes, and the WebView
82
+ is at or above the config's `min_webview_version`). A host may keep the wallet
83
+ row and send the user to Google Wallet instead of checkout.
84
+
85
+ Additive: `googlePay` keeps meaning "can pay here", so hosts that ignore the
86
+ new field behave as before. `checkWalletAvailability` persists the field and
87
+ derives it from the booleans when an older frames deployment omits it.
88
+
89
+ - d4654e9: Reveal `copy` option — `'button'` (default: the icon button, as today),
90
+ `'row'` (the whole row is one copy control: a real `<button>`, no icon, no
91
+ reserved width; the copied state shows on the value and is announced to
92
+ assistive tech) or `'none'` (no copy affordance; the value stays selectable
93
+ text). Copy still runs inside the frame and `onCopied` still carries the
94
+ field name only. Enumerated and re-validated in the frame; an older frame
95
+ ignores the option and renders the icon button.
96
+
97
+ Reveal `showLabels` option (default `true`). `false` renders no label
98
+ element at all — not an empty one — so a row is exactly as tall as its
99
+ value; the label string becomes the value's `aria-label`, and the icon copy
100
+ button's name carries the field ("Card Number: Copy"). With `copy:
101
+ 'button'` such a row is floored at the icon's hit target (`copyIconSize` +
102
+ 12px) so adjacent buttons never overlap. Replaces the `fontSizeLabel: '0px'`
103
+ / `lineHeightLabel: '0px'` workaround.
104
+
105
+ Reveal `rowStyle` option — `'plain'` (default, as today) or `'boxed'`: each
106
+ row becomes a pill drawn from the box tokens the collect inputs already use
107
+ (`colorBackground`, `colorBorder`, `borderRadius`, `borderWidth`,
108
+ `controlMinHeight`; 16px horizontal padding, `spacingUnit` vertical,
109
+ `fieldGap` between pills), so a border hugs the value instead of the
110
+ iframe. Deliberately opt-in: those tokens already reach reveal frames from
111
+ hosts that share one appearance object with collect, so honouring them on
112
+ presence would have restyled existing reveal rows.
113
+
114
+ Reveal `layout` option — `'column'` (default) or `'row'`: the frame's
115
+ fields sit side by side with equal widths, separated by the new `fieldGap`
116
+ appearance token (length; default `12px`; also the gap between `'boxed'`
117
+ pills). `fields: ['expiry', 'cvv']` with `layout: 'row'` is one frame and
118
+ one `/details` call where two single-field frames called it twice with the
119
+ same action token. Frame-wide on purpose: a mixed arrangement is two
120
+ frames, because a nested `fields` shape would not be ignorable by older
121
+ frames.
122
+
123
+ New `wordSpacing` appearance token (length grammar): extra space between
124
+ the card number's four-digit groups in the reveal frame — the value is
125
+ still chunked with single spaces, and no other row is affected. Reveal
126
+ `fields` entries are now validated against the known row names (unknown
127
+ entries are dropped instead of rendering an `undefined` label).
128
+
129
+ - 417ab29: Reveal masking — show/hide each sensitive value in place (WPAY-5064). The
130
+ masked state is per row (number, expiry, CVV, PIN; never the cardholder) and
131
+ lives in the frame; while masked the value TEXT is replaced (card number:
132
+ one glyph per digit except the last four; expiry `••/••`; CVV / PIN fully),
133
+ with the same character count so the row keeps its height. The values are
134
+ still fetched once at mount under the step-up and the copy control still
135
+ copies the real value — masking is a display aid, not a second
136
+ authorisation. Two things change the state:
137
+
138
+ - the USER, through an opt-in in-frame control: `maskToggle` (`'button'` =
139
+ eye / eye-off icon, themed by the `copyIcon*` tokens; `'text'` = a text
140
+ button from the new `show` / `hide` strings, sized to the wider word;
141
+ `'row'` = the value itself; default `'none'`), with `maskToggleByField`
142
+ overrides;
143
+ - the HOST, through `masked` at mount (`true`, or a per-row map such as
144
+ `{ cvv: true, pin: true }`) and `PciRevealElement.setMasked(boolean | map)`
145
+ later — no refetch, no new `actionToken` (host→frame event
146
+ `reveal-set-masked`, sent with the new reply-less `PciFrameChannel.post()`).
147
+
148
+ `onMaskedChange` / `reveal-masked-changed` reports the state of every
149
+ rendered maskable row (never the cardholder) after every change with
150
+ `{ masked, field?, reason }` (`'init'`,
151
+ `'user'`, `'host'`, `'timeout'`). `maskAfter` (ms, a number or a per-row map;
152
+ default never) re-masks a shown row from the frame; `onRevealRequested`
153
+ gates revealing: the toggle then only asks (`reveal-requested { field }`)
154
+ and the host reveals with `setMasked({ [field]: false })`. React: the
155
+ `masked` prop of `CardReveal` is live (forwarded in place, a map compared by
156
+ value); `onMaskedChange` and `onRevealRequested` are props. New string
157
+ `maskedPlaceholder` (the glyph; default `•`). Older frames ignore every
158
+ masking option and show the values: ship the frames first.
159
+
160
+ Reveal copy control — `copy: 'text'` renders the `copy` / `copied` strings
161
+ as a text button (the same shape set as `maskToggle`), and `copyByField`
162
+ overrides `copy` per row (`{ pin: 'none' }` keeps the icon button everywhere
163
+ but the PIN). Each entry is validated in the frame; an invalid entry leaves
164
+ that row on `copy`; older frames ignore the map. `copy: 'none'` keeps its
165
+ meaning (no control, the value stays selectable text).
166
+
167
+ Frames: the reveal presentation options are now resolved in one pure module
168
+ (`revealOptions.ts`) with unit tests; `fields` that is not an array is
169
+ ignored instead of thrown on; a row's side controls (toggle, copy) are
170
+ siblings of the cell, so `copy: 'row'` and a toggle button combine.
171
+
172
+ - 1d89a12: Wallet polish: `checkWalletAvailability` gains a persistent
173
+ stale-while-revalidate `cache` option (Storage-shaped adapter,
174
+ localStorage by default, `null` to disable); the checkout popup centers
175
+ over the opener window; the payment-sheet's billing contact, cardholder
176
+ name and Apple transaction id ride the token payload as optional fields
177
+ (collected only when the provider config requests billing).
178
+ - 5f67be4: Wallet checkout polish: loading skeleton + popup page padding; the popup
179
+ carries `appearance` in the URL fragment so the pre-quote skeleton renders
180
+ themed; privacy-only legal line with a partner-configurable
181
+ `branding.privacyUrl` (https-only, validated in-frame, Wirex policy
182
+ fallback); Google Pay button draws the design pill radius natively; fee row
183
+ rounds up to the minor unit (host-app parity).
184
+ - 33b4595: New wallet frame mode `wallet-preview` (`PciWalletPreviewInitConfig`): Google's
185
+ own Google Pay sheet with no price (`NOT_CURRENTLY_KNOWN`), for the probe's
186
+ `needs_card` — a phone where Google Pay works but Google Wallet holds no card
187
+ the top-up accepts. No quote and no backend call; the sheet's result is dropped
188
+ in the frame and the host hears only how it closed (`wallet-preview-closed`,
189
+ `PciWalletPreviewOutcome`) and, with `autoOpen`, whether it opened without a tap
190
+ (`wallet-preview-auto`). `PciFrameDocument` gains `wallet-preview`. Additive.
191
+ - 731da3e: Wallet checkout TOKEN MODE (WPAY-4431): pass the backend's short-lived top-up
192
+ token as `auth.checkoutToken` and the hosted checkout executes the top-up
193
+ itself, reporting `onExecuted` / `onExecuteFailed` (`wallet-executed` /
194
+ `wallet-execute-failed` on the wire) — the wallet payment token never leaves
195
+ the frame. Legacy tokenize-and-return (`onToken`) is unchanged without `auth`.
196
+
197
+ Token mode also brings Google Pay to desktop (`googlePayHandoff: 'qr' | 'none'`,
198
+ probe flag `googlePayHandoff`): the frame draws a QR that carries the checkout
199
+ itself — the token, the quote and the estimate's `provider` name (new init /
200
+ `arm()` / `update()` field) — and an Android phone opens the same checkout
201
+ top-level, pays and executes. Nothing is stored on the frames service and the
202
+ desktop never learns the outcome: hosts reconcile by their own status reads
203
+ after `wallet-state: handoff-pending`. `arm(quote, config, auth?, provider?)` /
204
+ `update(quote, config?, auth?, provider?)`; `wallet-update` carries `auth` and
205
+ `provider`; new `wallet-state` values `executing`, `handoff-pending`.
206
+
207
+ `buildWalletLaunchFragment` / `buildWalletLaunchUrl` (core) build the same
208
+ compact fragment for a Chrome Custom Tab launch (`#t=&e=&s=&p=[&r=]`); the page
209
+ resolves the provider block from the public BaaS config by name.
210
+
211
+ ### Patch Changes
212
+
213
+ - 274c69f: Fixed: the frames rendered as solid white rectangles in host pages that declare
214
+ `<meta name="color-scheme" content="dark">` (or `light dark` with dark
215
+ preferred) — typical of hybrid-app shells and dark-themed sites. The SDK set
216
+ `color-scheme: normal` on the iframe element; Chromium resolves `normal` from
217
+ the host's meta, so under a dark host the element became dark while the frame
218
+ document is light, and on that mismatch the browser paints the frame's canvas
219
+ opaque (CSS Color Adjust). The iframe element is now explicitly
220
+ `color-scheme: light`, matching the frame documents, which now declare
221
+ `:root { color-scheme: light }` as well — the frames stay transparent under any
222
+ host scheme. Hosts that set their dark theme through CSS alone were never
223
+ affected. The SDK change alone removes the mismatch for an updated host; the
224
+ frame-document change makes the pair explicit and independent of any meta.
225
+ - a629a98: Wallet checkout return link: `returnUrl` (`buildWalletLaunchUrl` → `r`) may
226
+ now be your app's own scheme (`com.partner.app:/wallet/return`) as well as an
227
+ `https` App Link / Universal Link. Only the schemes a browser would execute in
228
+ the checkout's own origin (`javascript:`, `data:`, `blob:`, …),
229
+ browser-internal ones and cleartext `http:` are refused —
230
+ `buildWalletLaunchFragment` throws a `TypeError` on those, and the frame
231
+ ignores them. New exports `resolveWalletReturnUrl` and
232
+ `PCI_WALLET_RETURN_URL_BLOCKED_SCHEMES`.
233
+
234
+ The frames (service) must be deployed for an app scheme to be offered; an SDK
235
+ built before this release already passes any `returnUrl` through, so the
236
+ frames deployment alone enables the change — this release only adds the
237
+ early validation and the documentation.
238
+
3
239
  ## 1.1.0-beta.4
4
240
 
5
241
  ### Minor Changes
@@ -1,11 +1,48 @@
1
- import type { PciAppearance, PciCollectChangeState, PciCollectProfile, PciFrameStrings, PciTokenizeOctResult, PciTokenizeTopUpResult } from './protocol.js';
1
+ import type { PciAppearance, PciCollectChangeState, PciCollectMaskedReason, PciCollectMaskToggleMode, PciCollectProfile, PciFrameStrings, PciTokenizeOctResult, PciTokenizeTopUpResult } from './protocol.js';
2
2
  export interface PciCollectAuth {
3
3
  /** Called right before every backend hop so the frame always gets a fresh
4
4
  * access token. By design the frame authenticates with the caller's bearer —
5
5
  * the host passes its own user's bearer. There is no publishable-key layer. */
6
6
  getBearerToken: () => Promise<string>;
7
7
  }
8
- export interface PciCollectElementConfig {
8
+ /** `onMaskedChange` payload: whether the CVV input is masked after a change
9
+ * and who made it — the mount report (`'init'`), the user's in-frame toggle
10
+ * (`'user'`), your `setMasked()` (`'host'`) or the `maskAfter` timer
11
+ * (`'timeout'`). A boolean and a reason — never the value. */
12
+ export interface PciCollectMaskedChange {
13
+ masked: boolean;
14
+ reason: PciCollectMaskedReason;
15
+ }
16
+ /**
17
+ * Masking of the CVV input while the user types — the same options on the
18
+ * single-form element and the per-field group. The card number is never
19
+ * masked; a profile without a CVV (`oct-destination`) ignores all of this.
20
+ */
21
+ export interface PciCollectMaskConfig {
22
+ /** Start with the CVV masked (default `true` — the digits are bullets as
23
+ * they are typed, as before this option existed). `false` starts it
24
+ * shown. The state lives in the frame; the user's `maskToggle` and your
25
+ * `setMasked()` change it in place — the value, the caret and the focus
26
+ * stay. Read at mount. */
27
+ masked?: boolean;
28
+ /** The in-frame show/hide control at the field's right edge (default
29
+ * `'none'`: no control — today's field). `'button'` — an eye / eye-off
30
+ * icon, the same control and `copyIcon*` tokens as the reveal element's;
31
+ * `'text'` — a text button from the `show` / `hide` strings. Read at
32
+ * mount. */
33
+ maskToggle?: PciCollectMaskToggleMode;
34
+ /** Re-mask a shown CVV after this many milliseconds, counted from the
35
+ * moment typed digits are visible; masking it earlier cancels the timer.
36
+ * Default: never. Reported through `onMaskedChange` with reason
37
+ * `'timeout'`. Read at mount. */
38
+ maskAfter?: number;
39
+ /** The CVV input's masked state as the frame applied it: once at mount,
40
+ * then after every change. A frame deployment that predates CVV masking
41
+ * never calls it (and keeps the field masked) — that is how you can
42
+ * tell. */
43
+ onMaskedChange?: (event: PciCollectMaskedChange) => void;
44
+ }
45
+ export interface PciCollectElementConfig extends PciCollectMaskConfig {
9
46
  profile: PciCollectProfile;
10
47
  auth: PciCollectAuth;
11
48
  appearance?: PciAppearance;
@@ -46,8 +83,17 @@ export interface PciCollectTokenizer {
46
83
  export declare class PciCollectElement implements PciCollectTokenizer {
47
84
  private readonly config;
48
85
  private readonly channel;
86
+ private readonly mask;
49
87
  constructor(frameUrl: string, config: PciCollectElementConfig);
50
88
  mount(container: HTMLElement): Promise<void>;
89
+ /** Mask (`true`) or show (`false`) the CVV input in place — the value,
90
+ * the caret and the focus stay where they are. Safe to call before
91
+ * `mount()` resolves (the last value is applied once the frame is
92
+ * initialized) and after `destroy()` (ignored). The frame confirms
93
+ * through `onMaskedChange` when the state actually changed; a profile
94
+ * without a CVV, and a frame deployment that predates CVV masking,
95
+ * ignore it. */
96
+ setMasked(masked: boolean): void;
51
97
  /** Profile `topup`: link a new external top-up card. */
52
98
  tokenizeTopUp(params: TokenizeTopUpParams): Promise<PciTokenizeTopUpResult>;
53
99
  /** Profile `oct-destination`: tokenize a payout destination card (no CVV). */
@@ -1 +1 @@
1
- {"version":3,"file":"collectElement.d.ts","sourceRoot":"","sources":["../src/collectElement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EAEjB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B;;oFAEgF;IAChF,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;4DAC4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC5E,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC7F;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;gBAE9B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,uBAAuB;IAQvD,KAAK,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD,wDAAwD;IAClD,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAsBjF,8EAA8E;IACxE,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAkBjG,OAAO,IAAI,IAAI;CAGhB"}
1
+ {"version":3,"file":"collectElement.d.ts","sourceRoot":"","sources":["../src/collectElement.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,iBAAiB,EAEjB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B;;oFAEgF;IAChF,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACvC;AAED;;;+DAG+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;+BAI2B;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;iBAIa;IACb,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC;;;sCAGkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;gBAGY;IACZ,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;4DAC4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC5E,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC7F;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;gBAE7B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,uBAAuB;IAYvD,KAAK,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBlD;;;;;;qBAMiB;IACjB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAIhC,wDAAwD;IAClD,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAsBjF,8EAA8E;IACxE,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAkBjG,OAAO,IAAI,IAAI;CAIhB"}
@@ -1,3 +1,4 @@
1
+ import { CollectMaskSender } from './collectMask.js';
1
2
  import { PciFrameChannel } from './frameChannel.js';
2
3
  /**
3
4
  * Card-entry element. Renders PAN/expiry/CVV/name (profile `topup`) or PAN
@@ -9,9 +10,13 @@ export class PciCollectElement {
9
10
  constructor(frameUrl, config) {
10
11
  this.config = config;
11
12
  this.channel = new PciFrameChannel(frameUrl);
13
+ this.mask = new CollectMaskSender(this.channel);
12
14
  this.channel.onMessage(message => {
13
15
  if (message.type === 'change')
14
16
  config.onChange?.(message.state);
17
+ if (message.type === 'collect-masked-changed') {
18
+ config.onMaskedChange?.({ masked: message.masked, reason: message.reason });
19
+ }
15
20
  });
16
21
  }
17
22
  async mount(container) {
@@ -27,8 +32,22 @@ export class PciCollectElement {
27
32
  auth,
28
33
  appearance: this.config.appearance,
29
34
  strings: this.config.strings,
35
+ masked: this.config.masked,
36
+ maskToggle: this.config.maskToggle,
37
+ maskAfter: this.config.maskAfter,
30
38
  },
31
39
  });
40
+ this.mask.open();
41
+ }
42
+ /** Mask (`true`) or show (`false`) the CVV input in place — the value,
43
+ * the caret and the focus stay where they are. Safe to call before
44
+ * `mount()` resolves (the last value is applied once the frame is
45
+ * initialized) and after `destroy()` (ignored). The frame confirms
46
+ * through `onMaskedChange` when the state actually changed; a profile
47
+ * without a CVV, and a frame deployment that predates CVV masking,
48
+ * ignore it. */
49
+ setMasked(masked) {
50
+ this.mask.send(masked);
32
51
  }
33
52
  /** Profile `topup`: link a new external top-up card. */
34
53
  async tokenizeTopUp(params) {
@@ -71,6 +90,7 @@ export class PciCollectElement {
71
90
  });
72
91
  }
73
92
  destroy() {
93
+ this.mask.close();
74
94
  this.channel.destroy();
75
95
  }
76
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"collectElement.js","sourceRoot":"","sources":["../src/collectElement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collectElement.js","sourceRoot":"","sources":["../src/collectElement.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import type { PciCollectAuth, PciCollectTokenizer, TokenizeOctDestinationParams, TokenizeTopUpParams } from './collectElement.js';
1
+ import type { PciCollectAuth, PciCollectMaskConfig, PciCollectTokenizer, TokenizeOctDestinationParams, TokenizeTopUpParams } from './collectElement.js';
2
2
  import type { PciAppearance, PciCollectChangeState, PciCollectFieldName, PciCollectProfile, PciFrameStrings, PciTokenizeOctResult, PciTokenizeTopUpResult } from './protocol.js';
3
- export interface PciCollectGroupConfig {
3
+ export interface PciCollectGroupConfig extends PciCollectMaskConfig {
4
4
  profile: PciCollectProfile;
5
5
  auth: PciCollectAuth;
6
6
  appearance?: PciAppearance;
@@ -8,6 +8,15 @@ export interface PciCollectGroupConfig {
8
8
  /** Aggregated validity/brand across all mounted fields (never card values). */
9
9
  onChange?: (state: PciCollectChangeState) => void;
10
10
  }
11
+ /**
12
+ * Options of ONE field, passed to `field(name, options)`. Today only the
13
+ * `cvv` field has any — its masking options — and each entry given here wins
14
+ * over the group config's for that field; other fields ignore them. The
15
+ * group config is the usual place (it reads the same for the single-form
16
+ * element); this is for a wrapper that owns one field, not the group — the
17
+ * React `CardCvvField` passes its props here.
18
+ */
19
+ export type PciCollectFieldOptions = PciCollectMaskConfig;
11
20
  /** Handle for one field's iframe. The host mounts it into its own container. */
12
21
  export interface PciCollectField {
13
22
  mount(container: HTMLElement): Promise<void>;
@@ -26,9 +35,20 @@ export declare class PciCollectGroup implements PciCollectTokenizer {
26
35
  private readonly channels;
27
36
  private readonly states;
28
37
  private brand;
38
+ /** The `setMasked()` path of the CVV field's frame, while that field exists. */
39
+ private cvvMask;
29
40
  constructor(frameUrl: string, config: PciCollectGroupConfig);
30
- /** Create a field element. Mount it into your own container for layout. */
31
- field(name: PciCollectFieldName): PciCollectField;
41
+ /** Create a field element. Mount it into your own container for layout.
42
+ * `options` — see `PciCollectFieldOptions` (the `cvv` field only). */
43
+ field(name: PciCollectFieldName, options?: PciCollectFieldOptions): PciCollectField;
44
+ /** Mask (`true`) or show (`false`) the CVV input in place — forwarded to
45
+ * the CVV field's frame; the value, the caret and the focus stay. A no-op
46
+ * while no CVV field exists (not created yet, destroyed, or a profile
47
+ * without one); called between `field('cvv')` and the end of its
48
+ * `mount()`, the last value is applied once the frame is initialized. The
49
+ * frame confirms through `onMaskedChange` when the state actually
50
+ * changed. */
51
+ setMasked(masked: boolean): void;
32
52
  private emitChange;
33
53
  private aggregator;
34
54
  private otherFields;
@@ -1 +1 @@
1
- {"version":3,"file":"collectGroup.d.ts","sourceRoot":"","sources":["../src/collectGroup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,4BAA4B,EAC5B,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EACV,aAAa,EAEb,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAUpB,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACnD;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;CACjB;AAOD;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,mBAAmB;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkF;IACzG,OAAO,CAAC,KAAK,CAA2B;gBAE5B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB;IAK3D,2EAA2E;IAC3E,KAAK,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe;IAsCjD,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,WAAW;IAIb,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAuB3E,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmBjG,OAAO,IAAI,IAAI;CAIhB"}
1
+ {"version":3,"file":"collectGroup.d.ts","sourceRoot":"","sources":["../src/collectGroup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,4BAA4B,EAC5B,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EACV,aAAa,EAEb,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAapB,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE1D,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;CACjB;AAOD;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,mBAAmB;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkF;IACzG,OAAO,CAAC,KAAK,CAA2B;IACxC,gFAAgF;IAChF,OAAO,CAAC,OAAO,CAAkC;gBAErC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB;IAK3D;2EACuE;IACvE,KAAK,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,GAAE,sBAA2B,GAAG,eAAe;IA2DvF;;;;;;mBAMe;IACf,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAIhC,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,WAAW;IAIb,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAuB3E,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmBjG,OAAO,IAAI,IAAI;CAMhB"}
@@ -1,3 +1,4 @@
1
+ import { CollectMaskSender } from './collectMask.js';
1
2
  import { PciFrameChannel } from './frameChannel.js';
2
3
  const FIELDS_BY_PROFILE = {
3
4
  topup: ['number', 'expiry', 'cvv', 'name'],
@@ -5,6 +6,8 @@ const FIELDS_BY_PROFILE = {
5
6
  };
6
7
  /** The aggregator field — the one that gathers siblings and POSTs. */
7
8
  const AGGREGATOR = 'number';
9
+ /** The one field with a masked state — see `PciCollectMaskConfig`. */
10
+ const MASKABLE = 'cvv';
8
11
  const randomId = () => typeof crypto !== 'undefined' && 'randomUUID' in crypto
9
12
  ? crypto.randomUUID()
10
13
  : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
@@ -20,11 +23,14 @@ export class PciCollectGroup {
20
23
  this.channels = new Map();
21
24
  this.states = {};
22
25
  this.brand = 'unknown';
26
+ /** The `setMasked()` path of the CVV field's frame, while that field exists. */
27
+ this.cvvMask = null;
23
28
  this.frameUrl = frameUrl;
24
29
  this.config = config;
25
30
  }
26
- /** Create a field element. Mount it into your own container for layout. */
27
- field(name) {
31
+ /** Create a field element. Mount it into your own container for layout.
32
+ * `options` — see `PciCollectFieldOptions` (the `cvv` field only). */
33
+ field(name, options = {}) {
28
34
  if (!FIELDS_BY_PROFILE[this.config.profile].includes(name)) {
29
35
  throw new Error(`Field "${name}" is not part of the "${this.config.profile}" profile`);
30
36
  }
@@ -33,7 +39,17 @@ export class PciCollectGroup {
33
39
  }
34
40
  const channel = new PciFrameChannel(this.frameUrl, { group: this.groupId });
35
41
  this.channels.set(name, channel);
42
+ const mask = name === MASKABLE ? new CollectMaskSender(channel) : null;
43
+ if (mask)
44
+ this.cvvMask = mask;
36
45
  channel.onMessage(message => {
46
+ if (message.type === 'collect-masked-changed') {
47
+ // Only the CVV frame has a masked state to report.
48
+ if (mask) {
49
+ (options.onMaskedChange ?? this.config.onMaskedChange)?.({ masked: message.masked, reason: message.reason });
50
+ }
51
+ return;
52
+ }
37
53
  if (message.type !== 'change')
38
54
  return;
39
55
  Object.assign(this.states, message.state.fields);
@@ -52,15 +68,38 @@ export class PciCollectGroup {
52
68
  groupId: this.groupId,
53
69
  appearance: this.config.appearance,
54
70
  strings: this.config.strings,
71
+ // The masking options go to the CVV frame only; the field's own
72
+ // options win over the group's, entry by entry.
73
+ ...(mask
74
+ ? {
75
+ masked: options.masked ?? this.config.masked,
76
+ maskToggle: options.maskToggle ?? this.config.maskToggle,
77
+ maskAfter: options.maskAfter ?? this.config.maskAfter,
78
+ }
79
+ : {}),
55
80
  },
56
81
  });
82
+ mask?.open();
57
83
  },
58
84
  destroy: () => {
85
+ mask?.close();
86
+ if (mask && this.cvvMask === mask)
87
+ this.cvvMask = null;
59
88
  channel.destroy();
60
89
  this.channels.delete(name);
61
90
  },
62
91
  };
63
92
  }
93
+ /** Mask (`true`) or show (`false`) the CVV input in place — forwarded to
94
+ * the CVV field's frame; the value, the caret and the focus stay. A no-op
95
+ * while no CVV field exists (not created yet, destroyed, or a profile
96
+ * without one); called between `field('cvv')` and the end of its
97
+ * `mount()`, the last value is applied once the frame is initialized. The
98
+ * frame confirms through `onMaskedChange` when the state actually
99
+ * changed. */
100
+ setMasked(masked) {
101
+ this.cvvMask?.send(masked);
102
+ }
64
103
  emitChange() {
65
104
  const active = FIELDS_BY_PROFILE[this.config.profile];
66
105
  const fields = {};
@@ -123,6 +162,8 @@ export class PciCollectGroup {
123
162
  });
124
163
  }
125
164
  destroy() {
165
+ this.cvvMask?.close();
166
+ this.cvvMask = null;
126
167
  for (const channel of this.channels.values())
127
168
  channel.destroy();
128
169
  this.channels.clear();
@@ -1 +1 @@
1
- {"version":3,"file":"collectGroup.js","sourceRoot":"","sources":["../src/collectGroup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collectGroup.js","sourceRoot":"","sources":["../src/collectGroup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { PciFrameChannel } from './frameChannel.js';
2
+ /**
3
+ * The host→frame `collect-set-masked` path of ONE collect frame, shared by
4
+ * the single-form element and the per-field group (internal — not part of
5
+ * the package surface).
6
+ *
7
+ * A frame drops every event that arrives before its `init`, so a command
8
+ * given earlier is held and sent once `open()` says the init was
9
+ * acknowledged. Only the LAST one is kept: the state is a single boolean, an
10
+ * earlier command has nothing left to say. After `close()` everything is
11
+ * ignored, so `setMasked()` on a destroyed element is safe.
12
+ */
13
+ export declare class CollectMaskSender {
14
+ private readonly channel;
15
+ private pending;
16
+ private opened;
17
+ private closed;
18
+ constructor(channel: PciFrameChannel);
19
+ send(masked: boolean): void;
20
+ /** The frame acknowledged its init: events reach it from now on. */
21
+ open(): void;
22
+ close(): void;
23
+ }
24
+ //# sourceMappingURL=collectMask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectMask.d.ts","sourceRoot":"","sources":["../src/collectMask.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,eAAe;IAIpC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAS3B,oEAAoE;IACpE,IAAI,IAAI,IAAI;IAOZ,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The host→frame `collect-set-masked` path of ONE collect frame, shared by
3
+ * the single-form element and the per-field group (internal — not part of
4
+ * the package surface).
5
+ *
6
+ * A frame drops every event that arrives before its `init`, so a command
7
+ * given earlier is held and sent once `open()` says the init was
8
+ * acknowledged. Only the LAST one is kept: the state is a single boolean, an
9
+ * earlier command has nothing left to say. After `close()` everything is
10
+ * ignored, so `setMasked()` on a destroyed element is safe.
11
+ */
12
+ export class CollectMaskSender {
13
+ constructor(channel) {
14
+ this.pending = null;
15
+ this.opened = false;
16
+ this.closed = false;
17
+ this.channel = channel;
18
+ }
19
+ send(masked) {
20
+ if (this.closed)
21
+ return;
22
+ if (!this.opened) {
23
+ this.pending = masked;
24
+ return;
25
+ }
26
+ this.channel.post({ type: 'collect-set-masked', masked });
27
+ }
28
+ /** The frame acknowledged its init: events reach it from now on. */
29
+ open() {
30
+ if (this.closed || this.opened)
31
+ return;
32
+ this.opened = true;
33
+ if (this.pending !== null)
34
+ this.channel.post({ type: 'collect-set-masked', masked: this.pending });
35
+ this.pending = null;
36
+ }
37
+ close() {
38
+ this.closed = true;
39
+ this.pending = null;
40
+ }
41
+ }
42
+ //# sourceMappingURL=collectMask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectMask.js","sourceRoot":"","sources":["../src/collectMask.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,iBAAiB;IAM5B,YAAY,OAAwB;QAJ5B,YAAO,GAAmB,IAAI,CAAC;QAC/B,WAAM,GAAG,KAAK,CAAC;QACf,WAAM,GAAG,KAAK,CAAC;QAGrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,MAAe;QAClB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;YACtB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,oEAAoE;IACpE,IAAI;QACF,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI;YAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACnG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;CACF"}