@amos.com/amos-js 0.9.9 → 0.9.11

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/dist/types.d.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  import { components } from '@amos.com/node';
2
+ /**
3
+ * PCI-safe snapshot of card/bank form validity, posted when HTML
4
+ * constraint validation changes. Use this to enable or disable a host
5
+ * checkout button.
6
+ */
7
+ export type PaymentMethodFormValidityChangeEvent = {
8
+ isValid: boolean;
9
+ };
2
10
  /**
3
11
  * Why an interactive confirmation attempt ended with `status: "incomplete"`.
4
12
  *
@@ -69,6 +77,99 @@ export type Appearance = {
69
77
  */
70
78
  labels?: AppearanceLabels;
71
79
  };
80
+ /**
81
+ * Inline style bag sent through `postMessage` to the wallet-button iframe.
82
+ *
83
+ * Matches the serializable subset of a CSSStyleDeclaration / React
84
+ * `CSSProperties` object (string or number values). Custom properties such
85
+ * as `--apple-pay-button-height` are allowed.
86
+ */
87
+ export type WalletButtonStyle = {
88
+ [property: string]: string | number | undefined;
89
+ };
90
+ /**
91
+ * `buttonstyle` attribute on Apple's `<apple-pay-button>`.
92
+ *
93
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
94
+ */
95
+ export type ApplePayButtonStyle = "black" | "white" | "white-outline";
96
+ /**
97
+ * `type` attribute on Apple's `<apple-pay-button>`.
98
+ *
99
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
100
+ */
101
+ export type ApplePayButtonType = "plain" | "buy" | "set-up" | "donate" | "check-out" | "book" | "subscribe" | "reload" | "add-money" | "top-up" | "order" | "rent" | "support" | "contribute" | "tip";
102
+ /**
103
+ * Visual props for Apple's `<apple-pay-button>`, using Apple's attribute
104
+ * names. Applied inside the Amos embed iframe.
105
+ *
106
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
107
+ */
108
+ export type ApplePayButtonElementProps = {
109
+ /**
110
+ * Apple Pay button color.
111
+ *
112
+ * @default "black"
113
+ */
114
+ buttonstyle?: ApplePayButtonStyle;
115
+ /**
116
+ * Apple Pay button label / verb.
117
+ *
118
+ * @default "plain"
119
+ */
120
+ type?: ApplePayButtonType;
121
+ /**
122
+ * BCP 47 locale for the button label (e.g. `"en-US"`).
123
+ *
124
+ * @default "en-US"
125
+ */
126
+ locale?: string;
127
+ /**
128
+ * Inline style for the `<apple-pay-button>`. Height is controlled with
129
+ * `--apple-pay-button-height` (Apple ignores CSS `height`). Width uses
130
+ * `--apple-pay-button-width` or CSS `width`.
131
+ */
132
+ style?: WalletButtonStyle;
133
+ };
134
+ /**
135
+ * Visual props for Google's Pay button, using `@google-pay/button-react`
136
+ * / Google Pay API names. Applied inside the Amos embed iframe.
137
+ *
138
+ * @see https://developers.google.com/pay/api/web/guides/resources/customize
139
+ */
140
+ export type GooglePayButtonElementProps = {
141
+ /**
142
+ * Button label / verb.
143
+ *
144
+ * @default "short"
145
+ */
146
+ buttonType?: google.payments.api.ButtonType;
147
+ /** Button color. */
148
+ buttonColor?: google.payments.api.ButtonColor;
149
+ /** Corner radius in pixels (0–20). */
150
+ buttonRadius?: number;
151
+ /**
152
+ * `"fill"` stretches the button to the container width; `"static"`
153
+ * uses Google's default size.
154
+ */
155
+ buttonSizeMode?: google.payments.api.ButtonSizeMode;
156
+ /** BCP 47 locale for the button label (e.g. `"en"`). */
157
+ buttonLocale?: string;
158
+ /** Whether the button draws a border. */
159
+ buttonBorderType?: google.payments.api.ButtonBorderType;
160
+ /**
161
+ * Inline style for the Google Pay button wrapper. Use `height` /
162
+ * `width` here (unlike Apple Pay, Google honors CSS `height`).
163
+ */
164
+ style?: WalletButtonStyle;
165
+ };
166
+ /**
167
+ * Keep only JSON-cloneable string/number declarations from a style object
168
+ * before sending it through `postMessage`.
169
+ */
170
+ export declare function serializeWalletButtonStyle(style: WalletButtonStyle | undefined): Record<string, string | number> | undefined;
171
+ export declare function pickApplePayButtonElementProps(options: ApplePayButtonElementProps): ApplePayButtonElementProps;
172
+ export declare function pickGooglePayButtonElementProps(options: GooglePayButtonElementProps): GooglePayButtonElementProps;
72
173
  /**
73
174
  * Typed `postMessage` payloads exchanged between the host page and the
74
175
  * embedded Amos iframe.
@@ -95,6 +196,18 @@ export type Message = {
95
196
  /** Parent → embed: push appearance overrides into the iframe. */
96
197
  type: "UPDATE_APPEARANCE";
97
198
  appearance: Appearance;
199
+ } | {
200
+ /**
201
+ * Parent → embed: visual options for the Apple Pay button. Nested
202
+ * under `props` so Apple's `type` attribute does not collide with
203
+ * this message discriminant.
204
+ */
205
+ type: "UPDATE_APPLE_PAY_BUTTON";
206
+ props: ApplePayButtonElementProps;
207
+ } | {
208
+ /** Parent → embed: visual options for the Google Pay button. */
209
+ type: "UPDATE_GOOGLE_PAY_BUTTON";
210
+ props: GooglePayButtonElementProps;
98
211
  } | {
99
212
  /**
100
213
  * Parent → embed: validate form inputs (`requestId` only).
@@ -138,6 +251,14 @@ export type Message = {
138
251
  } | {
139
252
  /** Parent → embed: clear all form field values and API errors. */
140
253
  type: "RESET_FORM";
254
+ } | {
255
+ /**
256
+ * Embed → parent: card/bank form validity changed.
257
+ * `isValid` is true when all required fields are present and
258
+ * valid. Does not include PCI data.
259
+ */
260
+ type: "FORM_VALIDITY_CHANGE";
261
+ isValid: boolean;
141
262
  };
142
263
  /**
143
264
  * Identity helper that brands an object as a typed `Message`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amos.com/amos-js",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
4
4
  "main": "dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
package/src/apple-pay.ts CHANGED
@@ -10,10 +10,12 @@ import {
10
10
  sendParentReadyMessage,
11
11
  updateAmount as sendUpdateAmount,
12
12
  updateAppearance as sendUpdateAppearance,
13
+ updateApplePayButton as sendUpdateApplePayButton,
13
14
  updateMerchantName as sendUpdateMerchantName,
14
15
  } from "./messaging";
15
16
  import {
16
17
  type Appearance,
18
+ type ApplePayButtonElementProps,
17
19
  type ConfirmationResult,
18
20
  createMessage,
19
21
  type Message,
@@ -36,7 +38,7 @@ export function getApplePayButtonInitialHeight(): string {
36
38
  /**
37
39
  * Options accepted by {@link attachApplePayButtonListeners}.
38
40
  */
39
- export type ApplePayButtonListenerOptions = {
41
+ export type ApplePayButtonListenerOptions = ApplePayButtonElementProps & {
40
42
  /** The amount of the payment, in the same format passed in props. */
41
43
  amount: string;
42
44
  /** A user-visible merchant name. */
@@ -83,7 +85,9 @@ export type ApplePayButtonController = {
83
85
  /**
84
86
  * Update one or more listener options without re-attaching the
85
87
  * message listener. Pass `amount` or `merchantName` to push the new
86
- * value into the iframe; pass `appearance` to update theme variables.
88
+ * value into the iframe; pass `appearance` to update theme variables;
89
+ * pass `buttonstyle`, `type`, `locale`, or `style` to restyle the
90
+ * Apple Pay button.
87
91
  */
88
92
  update: (patch: Partial<ApplePayButtonListenerOptions>) => void;
89
93
  /**
@@ -126,6 +130,10 @@ export function attachApplePayButtonListeners(
126
130
  sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
127
131
  }
128
132
 
133
+ function pushButtonProps() {
134
+ sendUpdateApplePayButton({ iframe, props: current });
135
+ }
136
+
129
137
  function handleMessage(event: MessageEvent<Message>) {
130
138
  // Ignore messages from other frames / windows.
131
139
  if (event.source !== iframe.contentWindow) {
@@ -138,6 +146,7 @@ export function attachApplePayButtonListeners(
138
146
  sendUpdateAppearance({ iframe, appearance: current.appearance });
139
147
  pushAmount();
140
148
  pushMerchantName();
149
+ pushButtonProps();
141
150
  break;
142
151
 
143
152
  case "UPDATE_HEIGHT":
@@ -199,6 +208,11 @@ export function attachApplePayButtonListeners(
199
208
  const hadAppearance = "appearance" in patch;
200
209
  const hadAmount = "amount" in patch;
201
210
  const hadMerchantName = "merchantName" in patch;
211
+ const hadButtonProps =
212
+ "buttonstyle" in patch ||
213
+ "type" in patch ||
214
+ "locale" in patch ||
215
+ "style" in patch;
202
216
  current = { ...current, ...patch };
203
217
  if (hadAppearance) {
204
218
  sendUpdateAppearance({ iframe, appearance: current.appearance });
@@ -209,6 +223,9 @@ export function attachApplePayButtonListeners(
209
223
  if (hadMerchantName) {
210
224
  pushMerchantName();
211
225
  }
226
+ if (hadButtonProps) {
227
+ pushButtonProps();
228
+ }
212
229
  },
213
230
  destroy() {
214
231
  window.removeEventListener("message", handleMessage);
package/src/google-pay.ts CHANGED
@@ -7,9 +7,15 @@ import {
7
7
  sendParentReadyMessage,
8
8
  updateAmount as sendUpdateAmount,
9
9
  updateAppearance as sendUpdateAppearance,
10
+ updateGooglePayButton as sendUpdateGooglePayButton,
10
11
  updateMerchantName as sendUpdateMerchantName,
11
12
  } from "./messaging";
12
- import type { Appearance, ConfirmationResult, Message } from "./types";
13
+ import type {
14
+ Appearance,
15
+ ConfirmationResult,
16
+ GooglePayButtonElementProps,
17
+ Message,
18
+ } from "./types";
13
19
 
14
20
  /**
15
21
  * Build the iframe `src` URL for the embedded Google Pay button.
@@ -28,7 +34,7 @@ export function getGooglePayButtonInitialHeight(): string {
28
34
  /**
29
35
  * Options accepted by {@link attachGooglePayButtonListeners}.
30
36
  */
31
- export type GooglePayButtonListenerOptions = {
37
+ export type GooglePayButtonListenerOptions = GooglePayButtonElementProps & {
32
38
  /** The amount of the payment, in the same format passed in props. */
33
39
  amount: string;
34
40
  /** A user-visible merchant name. */
@@ -75,7 +81,10 @@ export type GooglePayButtonController = {
75
81
  /**
76
82
  * Update one or more listener options without re-attaching the
77
83
  * message listener. Pass `amount` or `merchantName` to push the new
78
- * value into the iframe; pass `appearance` to update theme variables.
84
+ * value into the iframe; pass `appearance` to update theme variables;
85
+ * pass `buttonType`, `buttonColor`, `buttonRadius`, `buttonSizeMode`,
86
+ * `buttonLocale`, `buttonBorderType`, or `style` to restyle the
87
+ * Google Pay button.
79
88
  */
80
89
  update: (patch: Partial<GooglePayButtonListenerOptions>) => void;
81
90
  /**
@@ -106,6 +115,10 @@ export function attachGooglePayButtonListeners(
106
115
  sendUpdateMerchantName({ iframe, merchantName: current.merchantName });
107
116
  }
108
117
 
118
+ function pushButtonProps() {
119
+ sendUpdateGooglePayButton({ iframe, props: current });
120
+ }
121
+
109
122
  function handleMessage(event: MessageEvent<Message>) {
110
123
  if (event.source !== iframe.contentWindow) {
111
124
  return;
@@ -117,6 +130,7 @@ export function attachGooglePayButtonListeners(
117
130
  sendUpdateAppearance({ iframe, appearance: current.appearance });
118
131
  pushAmount();
119
132
  pushMerchantName();
133
+ pushButtonProps();
120
134
  break;
121
135
 
122
136
  case "UPDATE_HEIGHT":
@@ -163,6 +177,14 @@ export function attachGooglePayButtonListeners(
163
177
  const hadAppearance = "appearance" in patch;
164
178
  const hadAmount = "amount" in patch;
165
179
  const hadMerchantName = "merchantName" in patch;
180
+ const hadButtonProps =
181
+ "buttonType" in patch ||
182
+ "buttonColor" in patch ||
183
+ "buttonRadius" in patch ||
184
+ "buttonSizeMode" in patch ||
185
+ "buttonLocale" in patch ||
186
+ "buttonBorderType" in patch ||
187
+ "style" in patch;
166
188
  current = { ...current, ...patch };
167
189
  if (hadAppearance) {
168
190
  sendUpdateAppearance({ iframe, appearance: current.appearance });
@@ -173,6 +195,9 @@ export function attachGooglePayButtonListeners(
173
195
  if (hadMerchantName) {
174
196
  pushMerchantName();
175
197
  }
198
+ if (hadButtonProps) {
199
+ pushButtonProps();
200
+ }
176
201
  },
177
202
  destroy() {
178
203
  window.removeEventListener("message", handleMessage);
package/src/index.ts CHANGED
@@ -32,6 +32,8 @@ export {
32
32
  sendParentReadyMessage,
33
33
  updateAmount,
34
34
  updateAppearance,
35
+ updateApplePayButton,
36
+ updateGooglePayButton,
35
37
  updateMerchantName,
36
38
  validateForm,
37
39
  } from "./messaging";
@@ -66,9 +68,20 @@ export {
66
68
  export type {
67
69
  Appearance,
68
70
  AppearanceLabels,
71
+ ApplePayButtonElementProps,
72
+ ApplePayButtonStyle,
73
+ ApplePayButtonType,
69
74
  ConfirmationIncompleteReason,
70
75
  ConfirmationResult,
76
+ GooglePayButtonElementProps,
71
77
  Message,
78
+ PaymentMethodFormValidityChangeEvent,
72
79
  ThemeVariable,
80
+ WalletButtonStyle,
81
+ } from "./types";
82
+ export {
83
+ createMessage,
84
+ pickApplePayButtonElementProps,
85
+ pickGooglePayButtonElementProps,
86
+ serializeWalletButtonStyle,
73
87
  } from "./types";
74
- export { createMessage } from "./types";
package/src/messaging.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  import type { components } from "@amos.com/node";
2
2
  import { decodeJwt } from "./jwt";
3
- import { type Appearance, createMessage, type Message } from "./types";
3
+ import {
4
+ type Appearance,
5
+ type ApplePayButtonElementProps,
6
+ createMessage,
7
+ type GooglePayButtonElementProps,
8
+ type Message,
9
+ pickApplePayButtonElementProps,
10
+ pickGooglePayButtonElementProps,
11
+ } from "./types";
4
12
 
5
13
  type Iframe = HTMLIFrameElement | null | undefined;
6
14
 
@@ -55,6 +63,52 @@ export function updateAppearance({
55
63
  );
56
64
  }
57
65
 
66
+ /**
67
+ * Push Apple Pay button visual options into the embedded iframe.
68
+ */
69
+ export function updateApplePayButton({
70
+ iframe,
71
+ props,
72
+ }: {
73
+ iframe: Iframe;
74
+ props: ApplePayButtonElementProps;
75
+ }): void {
76
+ if (!iframe?.contentWindow) {
77
+ return;
78
+ }
79
+
80
+ iframe.contentWindow.postMessage(
81
+ createMessage({
82
+ type: "UPDATE_APPLE_PAY_BUTTON",
83
+ props: pickApplePayButtonElementProps(props),
84
+ }),
85
+ getIframeTargetOrigin(iframe),
86
+ );
87
+ }
88
+
89
+ /**
90
+ * Push Google Pay button visual options into the embedded iframe.
91
+ */
92
+ export function updateGooglePayButton({
93
+ iframe,
94
+ props,
95
+ }: {
96
+ iframe: Iframe;
97
+ props: GooglePayButtonElementProps;
98
+ }): void {
99
+ if (!iframe?.contentWindow) {
100
+ return;
101
+ }
102
+
103
+ iframe.contentWindow.postMessage(
104
+ createMessage({
105
+ type: "UPDATE_GOOGLE_PAY_BUTTON",
106
+ props: pickGooglePayButtonElementProps(props),
107
+ }),
108
+ getIframeTargetOrigin(iframe),
109
+ );
110
+ }
111
+
58
112
  /**
59
113
  * Push the express-checkout amount into the embedded Google Pay iframe.
60
114
  */
@@ -3,7 +3,12 @@ import {
3
3
  sendParentReadyMessage,
4
4
  updateAppearance as sendUpdateAppearance,
5
5
  } from "./messaging";
6
- import type { Appearance, ConfirmationResult, Message } from "./types";
6
+ import type {
7
+ Appearance,
8
+ ConfirmationResult,
9
+ Message,
10
+ PaymentMethodFormValidityChangeEvent,
11
+ } from "./types";
7
12
 
8
13
  /**
9
14
  * The additional fields beyond the standard card number, expiration
@@ -126,6 +131,12 @@ export type PaymentMethodFormListenerOptions = {
126
131
  * iframe's opacity from `0` to `1` to fade it in.
127
132
  */
128
133
  onAppearanceReady?: () => void;
134
+ /**
135
+ * Called when card/bank form validity changes. `isValid` is true
136
+ * when all required fields are present and valid. Does not include
137
+ * PCI data. Use this to enable or disable a host checkout button.
138
+ */
139
+ onValidityChange?: (event: PaymentMethodFormValidityChangeEvent) => void;
129
140
  /**
130
141
  * Called when the interactive confirmation flow finishes (success or
131
142
  * terminal failure). Not settlement proof — verify via webhooks.
@@ -191,6 +202,10 @@ export function attachPaymentMethodFormListeners(
191
202
  current.onAppearanceReady?.();
192
203
  break;
193
204
 
205
+ case "FORM_VALIDITY_CHANGE":
206
+ current.onValidityChange?.({ isValid: event.data.isValid });
207
+ break;
208
+
194
209
  case "CONFIRMATION_RESULT":
195
210
  current.onResult(event.data.result);
196
211
  break;
package/src/types.ts CHANGED
@@ -1,5 +1,16 @@
1
+ /// <reference types="googlepay" />
2
+
1
3
  import type { components } from "@amos.com/node";
2
4
 
5
+ /**
6
+ * PCI-safe snapshot of card/bank form validity, posted when HTML
7
+ * constraint validation changes. Use this to enable or disable a host
8
+ * checkout button.
9
+ */
10
+ export type PaymentMethodFormValidityChangeEvent = {
11
+ isValid: boolean;
12
+ };
13
+
3
14
  /**
4
15
  * Why an interactive confirmation attempt ended with `status: "incomplete"`.
5
16
  *
@@ -303,6 +314,193 @@ export type Appearance = {
303
314
  labels?: AppearanceLabels;
304
315
  };
305
316
 
317
+ /**
318
+ * Inline style bag sent through `postMessage` to the wallet-button iframe.
319
+ *
320
+ * Matches the serializable subset of a CSSStyleDeclaration / React
321
+ * `CSSProperties` object (string or number values). Custom properties such
322
+ * as `--apple-pay-button-height` are allowed.
323
+ */
324
+ export type WalletButtonStyle = {
325
+ [property: string]: string | number | undefined;
326
+ };
327
+
328
+ /**
329
+ * `buttonstyle` attribute on Apple's `<apple-pay-button>`.
330
+ *
331
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
332
+ */
333
+ export type ApplePayButtonStyle = "black" | "white" | "white-outline";
334
+
335
+ /**
336
+ * `type` attribute on Apple's `<apple-pay-button>`.
337
+ *
338
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
339
+ */
340
+ export type ApplePayButtonType =
341
+ | "plain"
342
+ | "buy"
343
+ | "set-up"
344
+ | "donate"
345
+ | "check-out"
346
+ | "book"
347
+ | "subscribe"
348
+ | "reload"
349
+ | "add-money"
350
+ | "top-up"
351
+ | "order"
352
+ | "rent"
353
+ | "support"
354
+ | "contribute"
355
+ | "tip";
356
+
357
+ /**
358
+ * Visual props for Apple's `<apple-pay-button>`, using Apple's attribute
359
+ * names. Applied inside the Amos embed iframe.
360
+ *
361
+ * @see https://developer.apple.com/documentation/apple_pay_on_the_web/apple-pay-button
362
+ */
363
+ export type ApplePayButtonElementProps = {
364
+ /**
365
+ * Apple Pay button color.
366
+ *
367
+ * @default "black"
368
+ */
369
+ buttonstyle?: ApplePayButtonStyle;
370
+ /**
371
+ * Apple Pay button label / verb.
372
+ *
373
+ * @default "plain"
374
+ */
375
+ type?: ApplePayButtonType;
376
+ /**
377
+ * BCP 47 locale for the button label (e.g. `"en-US"`).
378
+ *
379
+ * @default "en-US"
380
+ */
381
+ locale?: string;
382
+ /**
383
+ * Inline style for the `<apple-pay-button>`. Height is controlled with
384
+ * `--apple-pay-button-height` (Apple ignores CSS `height`). Width uses
385
+ * `--apple-pay-button-width` or CSS `width`.
386
+ */
387
+ style?: WalletButtonStyle;
388
+ };
389
+
390
+ /**
391
+ * Visual props for Google's Pay button, using `@google-pay/button-react`
392
+ * / Google Pay API names. Applied inside the Amos embed iframe.
393
+ *
394
+ * @see https://developers.google.com/pay/api/web/guides/resources/customize
395
+ */
396
+ export type GooglePayButtonElementProps = {
397
+ /**
398
+ * Button label / verb.
399
+ *
400
+ * @default "short"
401
+ */
402
+ buttonType?: google.payments.api.ButtonType;
403
+ /** Button color. */
404
+ buttonColor?: google.payments.api.ButtonColor;
405
+ /** Corner radius in pixels (0–20). */
406
+ buttonRadius?: number;
407
+ /**
408
+ * `"fill"` stretches the button to the container width; `"static"`
409
+ * uses Google's default size.
410
+ */
411
+ buttonSizeMode?: google.payments.api.ButtonSizeMode;
412
+ /** BCP 47 locale for the button label (e.g. `"en"`). */
413
+ buttonLocale?: string;
414
+ /** Whether the button draws a border. */
415
+ buttonBorderType?: google.payments.api.ButtonBorderType;
416
+ /**
417
+ * Inline style for the Google Pay button wrapper. Use `height` /
418
+ * `width` here (unlike Apple Pay, Google honors CSS `height`).
419
+ */
420
+ style?: WalletButtonStyle;
421
+ };
422
+
423
+ /**
424
+ * Keep only JSON-cloneable string/number declarations from a style object
425
+ * before sending it through `postMessage`.
426
+ */
427
+ export function serializeWalletButtonStyle(
428
+ style: WalletButtonStyle | undefined,
429
+ ): Record<string, string | number> | undefined {
430
+ if (!style || typeof style !== "object") {
431
+ return undefined;
432
+ }
433
+
434
+ const result: Record<string, string | number> = {};
435
+ for (const [key, value] of Object.entries(style)) {
436
+ if (typeof value === "string") {
437
+ if (value.length === 0) {
438
+ continue;
439
+ }
440
+ result[key] = value;
441
+ continue;
442
+ }
443
+ if (typeof value === "number" && Number.isFinite(value)) {
444
+ result[key] = value;
445
+ }
446
+ }
447
+
448
+ return Object.keys(result).length > 0 ? result : undefined;
449
+ }
450
+
451
+ export function pickApplePayButtonElementProps(
452
+ options: ApplePayButtonElementProps,
453
+ ): ApplePayButtonElementProps {
454
+ const props: ApplePayButtonElementProps = {};
455
+ if (options.buttonstyle !== undefined) {
456
+ props.buttonstyle = options.buttonstyle;
457
+ }
458
+ if (options.type !== undefined) {
459
+ props.type = options.type;
460
+ }
461
+ if (options.locale !== undefined) {
462
+ props.locale = options.locale;
463
+ }
464
+ if (options.style !== undefined) {
465
+ const style = serializeWalletButtonStyle(options.style);
466
+ if (style) {
467
+ props.style = style;
468
+ }
469
+ }
470
+ return props;
471
+ }
472
+
473
+ export function pickGooglePayButtonElementProps(
474
+ options: GooglePayButtonElementProps,
475
+ ): GooglePayButtonElementProps {
476
+ const props: GooglePayButtonElementProps = {};
477
+ if (options.buttonType !== undefined) {
478
+ props.buttonType = options.buttonType;
479
+ }
480
+ if (options.buttonColor !== undefined) {
481
+ props.buttonColor = options.buttonColor;
482
+ }
483
+ if (options.buttonRadius !== undefined) {
484
+ props.buttonRadius = options.buttonRadius;
485
+ }
486
+ if (options.buttonSizeMode !== undefined) {
487
+ props.buttonSizeMode = options.buttonSizeMode;
488
+ }
489
+ if (options.buttonLocale !== undefined) {
490
+ props.buttonLocale = options.buttonLocale;
491
+ }
492
+ if (options.buttonBorderType !== undefined) {
493
+ props.buttonBorderType = options.buttonBorderType;
494
+ }
495
+ if (options.style !== undefined) {
496
+ const style = serializeWalletButtonStyle(options.style);
497
+ if (style) {
498
+ props.style = style;
499
+ }
500
+ }
501
+ return props;
502
+ }
503
+
306
504
  /**
307
505
  * Typed `postMessage` payloads exchanged between the host page and the
308
506
  * embedded Amos iframe.
@@ -336,6 +534,20 @@ export type Message =
336
534
  type: "UPDATE_APPEARANCE";
337
535
  appearance: Appearance;
338
536
  }
537
+ | {
538
+ /**
539
+ * Parent → embed: visual options for the Apple Pay button. Nested
540
+ * under `props` so Apple's `type` attribute does not collide with
541
+ * this message discriminant.
542
+ */
543
+ type: "UPDATE_APPLE_PAY_BUTTON";
544
+ props: ApplePayButtonElementProps;
545
+ }
546
+ | {
547
+ /** Parent → embed: visual options for the Google Pay button. */
548
+ type: "UPDATE_GOOGLE_PAY_BUTTON";
549
+ props: GooglePayButtonElementProps;
550
+ }
339
551
  | {
340
552
  /**
341
553
  * Parent → embed: validate form inputs (`requestId` only).
@@ -390,6 +602,15 @@ export type Message =
390
602
  | {
391
603
  /** Parent → embed: clear all form field values and API errors. */
392
604
  type: "RESET_FORM";
605
+ }
606
+ | {
607
+ /**
608
+ * Embed → parent: card/bank form validity changed.
609
+ * `isValid` is true when all required fields are present and
610
+ * valid. Does not include PCI data.
611
+ */
612
+ type: "FORM_VALIDITY_CHANGE";
613
+ isValid: boolean;
393
614
  };
394
615
 
395
616
  /**