@starfish-codes/hellgate 3.9.0 → 3.10.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.
Files changed (31) hide show
  1. package/dist/3ds/typings.d.ts +1 -0
  2. package/dist/__tests__/card-handler.spec.d.ts +1 -0
  3. package/dist/__tests__/test-utils.d.ts +11 -0
  4. package/dist/card/card-handler.d.ts +24 -8
  5. package/dist/card/coordinator/__tests__/card-handler-coordinator.spec.d.ts +1 -0
  6. package/dist/card/coordinator/card-handler-coordinator.d.ts +34 -0
  7. package/dist/card/coordinator/index.d.ts +2 -0
  8. package/dist/card/coordinator/typings.d.ts +45 -0
  9. package/dist/card/typings.d.ts +30 -0
  10. package/dist/card/ui/elements/base-element.d.ts +3 -3
  11. package/dist/card/ui/elements/utils.d.ts +1 -2
  12. package/dist/card/ui/iframe/elements/base-element.d.ts +4 -2
  13. package/dist/card/ui/iframe/elements/card-expiration-month.d.ts +1 -0
  14. package/dist/card/ui/iframe/elements/text-element.d.ts +1 -0
  15. package/dist/card/ui/iframe/index.d.ts +1 -0
  16. package/dist/card/ui/iframe/utils.d.ts +1 -0
  17. package/dist/card/ui/typings.d.ts +8 -5
  18. package/dist/card/ui/utils.d.ts +3 -1
  19. package/dist/coordinator/coordinator.d.ts +38 -0
  20. package/dist/coordinator/iframe/constants.d.ts +1 -0
  21. package/dist/coordinator/iframe/iframe-coordinator.d.ts +33 -0
  22. package/dist/coordinator/iframe/iframe.d.ts +1 -0
  23. package/dist/coordinator/iframe/index.d.ts +2 -0
  24. package/dist/coordinator/index.d.ts +3 -0
  25. package/dist/coordinator/typings.d.ts +39 -0
  26. package/dist/hellgate-sdk.mjs +464 -1145
  27. package/dist/hellgate-sdk.umd.js +1 -1
  28. package/dist/hellgate.d.ts +5 -2
  29. package/dist/session/session.d.ts +1 -1
  30. package/dist/utils.d.ts +1 -0
  31. package/package.json +7 -6
@@ -26,6 +26,7 @@ export type Do3DSChallengeActionDTO = {
26
26
  action: '3ds_challenge';
27
27
  result: {
28
28
  requestor_trans_id: string;
29
+ requestorTransId?: string;
29
30
  event: string;
30
31
  param?: string;
31
32
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,2 +1,13 @@
1
1
  export declare function wait(milliseconds: number): Promise<void>;
2
2
  export declare function fill(input: HTMLInputElement, value: string): void;
3
+ export declare const HELLGATE_BASE_URL: string;
4
+ type CreateHellgateSessionParams = {
5
+ bypass_identification?: boolean;
6
+ };
7
+ export declare function createHellgateSession(params: CreateHellgateSessionParams): Promise<{
8
+ session_id: string;
9
+ }>;
10
+ export declare function refreshHellgateSession(): Promise<{
11
+ session_id: string;
12
+ }>;
13
+ export {};
@@ -1,20 +1,35 @@
1
1
  import { CompleteActionResult, HellgateSession } from '../session';
2
+ import { Coordinator } from '../coordinator';
2
3
  import { CreateCardFieldsOptions, CreateCardFormOptions, PaymentAdditionalData, RefreshSecurityCodeSessionStateDTO, TokenizeCardSessionStateDTO, TokenizedData } from './typings';
3
4
  import { CardElement, CardExpirationDateElement, CardNumberElement, CardVerificationCodeElement, TextElement } from './ui/elements';
5
+ import { CardElementBase } from './ui/elements/base-element';
4
6
  import { CardExpirationMonthElement } from './ui/elements/card-expiration-month';
5
7
  import { CardExpirationYearElement } from './ui/elements/card-expiration-year';
6
- import { ChangeEvent, ElementBaseOptions } from './ui/typings';
7
- export type FormFieldState = Omit<ChangeEvent<never>['data'], 'type'>;
8
+ import { CardSchema, ChangeEvent, ElementBaseOptions } from './ui/typings';
9
+ export type FormFieldState = Omit<ChangeEvent['data'], 'type'>;
8
10
  export type CardHandlerSessionInitState = TokenizeCardSessionStateDTO | RefreshSecurityCodeSessionStateDTO;
11
+ type FormField<T extends CardElementBase<any, any>> = {
12
+ element: T;
13
+ state: FormFieldState;
14
+ };
15
+ type ElementsMap = {
16
+ card: FormField<CardElement>;
17
+ cardNumber: FormField<CardNumberElement>;
18
+ cardExpirationDate: FormField<CardExpirationDateElement>;
19
+ cardExpirationMonth: FormField<CardExpirationMonthElement>;
20
+ cardExpirationYear: FormField<CardExpirationYearElement>;
21
+ cardVerificationCode: FormField<CardVerificationCodeElement>;
22
+ };
9
23
  export declare class HellgateCardHandler {
10
24
  session: HellgateSession<CardHandlerSessionInitState>;
25
+ private coordinator;
11
26
  state: FormFieldState;
12
- private cardElements;
27
+ cardElements: Partial<ElementsMap>;
13
28
  private textElements;
14
29
  private stateChangeHandlers;
15
30
  readonly cvcOnlyEnabled: boolean;
16
- static init(session: HellgateSession<CardHandlerSessionInitState>): Promise<HellgateCardHandler>;
17
- constructor(session: HellgateSession<CardHandlerSessionInitState>);
31
+ static init(session: HellgateSession<CardHandlerSessionInitState>, coordinator: Coordinator): Promise<HellgateCardHandler>;
32
+ constructor(session: HellgateSession<CardHandlerSessionInitState>, coordinator: Coordinator);
18
33
  createForm: (options?: CreateCardFormOptions) => CardElement;
19
34
  createFormFields(options: CreateCardFieldsOptions<'separate'>): {
20
35
  cardNumber: CardNumberElement;
@@ -35,13 +50,14 @@ export declare class HellgateCardHandler {
35
50
  dispose: () => void;
36
51
  process: (additionalData?: PaymentAdditionalData) => Promise<CompleteActionResult>;
37
52
  private refreshSecurityCode;
38
- private getFormValue;
39
53
  private hasFormElements;
40
54
  private disableFormElements;
41
- private extractAdditionalData;
42
- private encryptCardData;
43
55
  private addElementStateListener;
44
56
  updateFormState(): void;
45
57
  private createFieldDefaultState;
58
+ private serializeAdditionalData;
59
+ private getSessionSchemes;
46
60
  private getCardDataValidationError;
47
61
  }
62
+ export declare function resolveSchemes(sessionSchemes: CardSchema[] | undefined, userSchemes: CardSchema[] | undefined): CardSchema[] | undefined;
63
+ export {};
@@ -0,0 +1,34 @@
1
+ import { CompleteActionResult, HellgateSession } from '../../session';
2
+ import { FormFieldState } from '../card-handler';
3
+ import { PaymentAdditionalDataDTO, TokenizedData } from '../typings';
4
+ type FormField<Value = string> = {
5
+ value?: Value;
6
+ state: FormFieldState;
7
+ };
8
+ type ElementsMap = {
9
+ card: FormField<{
10
+ number: string;
11
+ expiry_date: string;
12
+ cvc: string;
13
+ }>;
14
+ cardNumber: FormField;
15
+ cardExpirationDate: FormField;
16
+ cardExpirationMonth: FormField;
17
+ cardExpirationYear: FormField;
18
+ cardVerificationCode: FormField;
19
+ } & Record<string, FormField>;
20
+ export declare class CardHandlerCoordinator {
21
+ private session;
22
+ private cardElements;
23
+ constructor(session: HellgateSession);
24
+ tokenize: (additionalData: PaymentAdditionalDataDTO) => Promise<TokenizedData>;
25
+ process: (additionalData?: PaymentAdditionalDataDTO) => Promise<CompleteActionResult>;
26
+ refreshSecurityCode(): Promise<CompleteActionResult>;
27
+ onElementChange: (key: keyof ElementsMap | string, data: FormFieldState) => void;
28
+ dispose(): void;
29
+ private getFormValue;
30
+ private extractAdditionalData;
31
+ private encryptCardData;
32
+ private extractAdditionalDataStringValue;
33
+ }
34
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './card-handler-coordinator';
2
+ export * from './typings';
@@ -0,0 +1,45 @@
1
+ import { CompleteActionResult } from '../../session';
2
+ import { FormFieldState } from '../card-handler';
3
+ import { PaymentAdditionalDataDTO, TokenizedData } from '../typings';
4
+ import { ElementBaseOptions } from '../ui/typings';
5
+ export type CardHandlerToCoordinatorMessage = {
6
+ type: 'card:tokenize';
7
+ additionalData?: PaymentAdditionalDataDTO;
8
+ } | {
9
+ type: 'card:process';
10
+ additionalData?: PaymentAdditionalDataDTO;
11
+ } | {
12
+ type: 'card:refresh_security_code';
13
+ };
14
+ export type CoordinatorToCardHandlerMessage = {
15
+ type: 'card:tokenize:response';
16
+ success: boolean;
17
+ result: TokenizedData | null;
18
+ error?: string;
19
+ } | {
20
+ type: 'card:process:response';
21
+ success: boolean;
22
+ result: CompleteActionResult | null;
23
+ error?: string;
24
+ } | {
25
+ type: 'card:refresh_security_code:response';
26
+ success: boolean;
27
+ result: CompleteActionResult | null;
28
+ error?: string;
29
+ };
30
+ export type ElementToCoordinatorMessage = {
31
+ type: 'element:change';
32
+ data: {
33
+ element: string;
34
+ key: string;
35
+ state: FormFieldState;
36
+ };
37
+ };
38
+ export type CoordinatorToElementMessage = {
39
+ type: 'coordinator:element:update';
40
+ data: {
41
+ element: string;
42
+ key: string;
43
+ options: ElementBaseOptions;
44
+ };
45
+ };
@@ -20,6 +20,9 @@ export type CreateCardFieldsOptions<T extends ExpiryDateElementType = 'combined'
20
20
  expiryDate?: ElementBaseOptions;
21
21
  });
22
22
  export type AdditionalDataValue = string | TextElement;
23
+ export type AdditionalDataValueDTO = string | {
24
+ key: string;
25
+ };
23
26
  export type PaymentAdditionalData<FieldValue = AdditionalDataValue> = {
24
27
  cardholder_name?: FieldValue;
25
28
  email?: FieldValue;
@@ -31,7 +34,21 @@ export type PaymentAdditionalData<FieldValue = AdditionalDataValue> = {
31
34
  city?: FieldValue;
32
35
  country?: FieldValue;
33
36
  };
37
+ /**
38
+ * Token lifecycle intent. When `true` (the SDK default), the resulting PCI
39
+ * token is ephemeral and cleaned up after a short TTL. When `false`, the
40
+ * token is persistent. Use `false` only on cardholder consent.
41
+ */
42
+ ephemeral?: boolean;
43
+ /**
44
+ * Optional ISO-8601 timestamp setting an explicit expiration for the
45
+ * resulting PCI token. When present it takes precedence over `ephemeral`
46
+ * (subject to a server-side cap). Use this for a "Save my card" UX where
47
+ * the merchant chooses the exact retention window after cardholder consent.
48
+ */
49
+ expiration_date?: string;
34
50
  };
51
+ export type PaymentAdditionalDataDTO = PaymentAdditionalData<AdditionalDataValueDTO>;
35
52
  export type ElementsCardData = {
36
53
  number: string | null;
37
54
  expiration_month: number | null;
@@ -48,11 +65,13 @@ export type TokenizeCardActionDTO = {
48
65
  action: 'tokenize_card';
49
66
  result: TokenizedData;
50
67
  };
68
+ export type HellgateCardScheme = 'visa' | 'mastercard' | 'americanexpress' | 'discover' | 'dinersclub' | 'jcb' | 'unionpay';
51
69
  export type TokenizeCardConfig = {
52
70
  provider: 'guardian';
53
71
  api_key: string;
54
72
  base_url: string;
55
73
  jwk: JWK;
74
+ allowed_schemes?: HellgateCardScheme[];
56
75
  };
57
76
  export type TokenizeCardSessionStateDTO = {
58
77
  next_action: 'tokenize_card';
@@ -65,6 +84,17 @@ export type CardTokenizeData = {
65
84
  security_code: string;
66
85
  cardholder_name?: string;
67
86
  additional_data: PaymentAdditionalData<string>;
87
+ /**
88
+ * Optional token lifecycle intent decrypted by Guardian inside the JWE.
89
+ * `true` requests an ephemeral PCI token, `false` a persistent one. Absent
90
+ * preserves Guardian's pre-existing default behavior.
91
+ */
92
+ ephemeral?: boolean;
93
+ /**
94
+ * Optional ISO-8601 expiration timestamp decrypted by Guardian inside the
95
+ * JWE. Wins over `ephemeral` server side.
96
+ */
97
+ expiration_date?: string;
68
98
  };
69
99
  export type TokenizedCardMaskedData = {
70
100
  account_number_last_four: string;
@@ -8,15 +8,15 @@ export declare abstract class CardElementBase<Value, IframeValue = string> {
8
8
  protected abstract type: ElementType;
9
9
  protected abstract extractValue: (rawValue: IframeValue | null) => Value | null;
10
10
  protected abstract putValue: (rawValue: Value | null) => IframeValue | null;
11
- constructor(options: ElementBaseOptions<Value>, key?: string);
11
+ key: string;
12
+ constructor(options: ElementBaseOptions<Value>);
12
13
  mount(selector: string | Element): Promise<void>;
13
14
  update: ({ ...data }: ElementBaseOptions<Value>) => Promise<void>;
14
15
  clear: () => void;
15
16
  focus: () => void;
16
17
  blur: () => void;
17
18
  unmount: () => void;
18
- on<T extends EventType>(eventType: T, listener: (event: FindByType<Explicit<CardElementEvents<never>>, T>['data']) => void): Subscription;
19
- secureValue(key: string): Value | null;
19
+ on<T extends EventType>(eventType: T, listener: (event: FindByType<Explicit<CardElementEvents>, T>['data']) => void): Subscription;
20
20
  private emitEvent;
21
21
  private iframePostMessage;
22
22
  }
@@ -15,6 +15,5 @@ type Elements = {
15
15
  cardVerificationCode: CardVerificationCodeElement;
16
16
  text: TextElement;
17
17
  };
18
- export declare function createElement<T extends keyof Elements>(type: T, options: ElementBaseOptions, key?: string): Elements[T];
19
- export declare function uid(): string;
18
+ export declare function createElement<T extends keyof Elements>(type: T, options: ElementBaseOptions): Elements[T];
20
19
  export {};
@@ -3,7 +3,6 @@ import { FactoryArg, InputMask, Masked } from 'imask';
3
3
  import { BaseElement, CardElementEvents, ElementBaseOptions, ElementEventListener, ElementMetadata, ElementType, EventType, Subscription } from '../../typings';
4
4
  export type PostMessageOptions = {
5
5
  postMessageOrigin: string;
6
- postMessageRoot: Window;
7
6
  };
8
7
  export declare abstract class IframeCardElementBase implements BaseElement<ElementBaseOptions, CardElementEvents<string>, string> {
9
8
  protected rootNode: Element;
@@ -16,11 +15,13 @@ export declare abstract class IframeCardElementBase implements BaseElement<Eleme
16
15
  protected abstract options: ElementBaseOptions;
17
16
  protected abstract inputMaskOptions: FactoryArg;
18
17
  protected inputMask?: InputMask<FactoryArg>;
19
- private id;
18
+ protected id: string;
20
19
  cardType?: CreditCardType;
21
20
  value: null;
21
+ private channel;
22
22
  constructor(rootNode: Element, postMessageOptions: PostMessageOptions);
23
23
  mount(): Promise<void>;
24
+ protected onMount(): void;
24
25
  unmount(): void;
25
26
  focus(): void;
26
27
  blur(): void;
@@ -29,6 +30,7 @@ export declare abstract class IframeCardElementBase implements BaseElement<Eleme
29
30
  updateState(): void;
30
31
  update(options: ElementBaseOptions): Promise<void>;
31
32
  on<T extends EventType>(eventType: T, listener: ElementEventListener<CardElementEvents<string>, T>): Subscription;
33
+ protected get key(): string;
32
34
  private emitEvent;
33
35
  protected validate(masked: Masked): ElementMetadata;
34
36
  protected renderHTML(): string;
@@ -7,4 +7,5 @@ export declare class IframeCardExpirationMonth extends IframeCardElementBase imp
7
7
  compiledMask?: Masked;
8
8
  protected inputMaskOptions: FactoryArg;
9
9
  protected validate(masked: Masked): ElementMetadata;
10
+ protected onMount(): void;
10
11
  }
@@ -5,4 +5,5 @@ export declare class IframeTextElement extends IframeCardElementBase implements
5
5
  readonly type: ElementType;
6
6
  protected options: ElementBaseOptions;
7
7
  protected inputMaskOptions: FactoryArg;
8
+ protected get key(): string;
8
9
  }
@@ -1 +1,2 @@
1
1
  export * from './iframe';
2
+ export { parseURLSearchParams } from './utils';
@@ -21,4 +21,5 @@ export declare function generateElementId(type: ElementType): string;
21
21
  export declare function mergeOptions(options1: ElementBaseOptions, options2: ElementBaseOptions): ElementBaseOptions;
22
22
  export declare function mergeStyles(style1: ElementStyle, style2: ElementStyle): ElementStyle;
23
23
  export declare function applyStyle(id: string, { fonts, ...styles }: ElementStyle): void;
24
+ export declare function uid(): string;
24
25
  export {};
@@ -7,18 +7,21 @@ type EventType = 'ready' | 'change' | 'focus' | 'blur' | 'keydown';
7
7
  export declare const EVENT_TYPES: EventType[];
8
8
  type BaseEvent<T extends EventType, TData = unknown> = {
9
9
  type: T;
10
+ id: string;
10
11
  element: ElementType;
11
12
  } & (TData extends object ? {
12
13
  data: TData;
13
14
  } : unknown);
14
- type ReadyEvent = BaseEvent<'ready'>;
15
- type ChangeEvent<Value> = BaseEvent<'change', {
15
+ type ReadyEvent = BaseEvent<'ready', {
16
+ key: string;
17
+ }>;
18
+ type ChangeEvent<Value = never> = BaseEvent<'change', {
16
19
  empty: boolean;
17
20
  complete: boolean;
18
21
  valid?: boolean;
19
22
  error?: string;
20
23
  errorCode?: CardValidationError;
21
- value: Value extends never ? never : Value | null;
24
+ value?: Value extends never ? never : Value | null;
22
25
  }>;
23
26
  type InputFocusEvent = BaseEvent<'focus'>;
24
27
  type InputBlurEvent = BaseEvent<'blur'>;
@@ -26,11 +29,11 @@ type InputKeydownEvent = BaseEvent<'keydown', {
26
29
  key: ListenableKey;
27
30
  } & Pick<KeyboardEvent, 'altKey' | 'ctrlKey' | 'shiftKey' | 'metaKey'>>;
28
31
  type BaseElementEvents = ReadyEvent | InputFocusEvent | InputBlurEvent | InputKeydownEvent;
29
- type CardElementEvents<Value> = BaseElementEvents | ChangeEvent<Value>;
32
+ type CardElementEvents<Value = never> = BaseElementEvents | ChangeEvent<Value>;
30
33
  /**
31
34
  * Utility type that helps find a Union type based on a `type` property
32
35
  */
33
- type FindByType<Union, Type extends EventType> = Union extends {
36
+ type FindByType<Union, Type extends string> = Union extends {
34
37
  type: Type;
35
38
  } ? Union : never;
36
39
  type ElementEventListener<Events, Type extends EventType> = (event: FindByType<Events, Type>) => void;
@@ -1,2 +1,4 @@
1
- import { TokenizedCardMaskedData } from '../typings';
1
+ import { HellgateCardScheme, TokenizedCardMaskedData } from '../typings';
2
+ import { CardSchema } from './typings';
3
+ export declare function mapHellgateSchemesToCardSchema(schemes: HellgateCardScheme[]): CardSchema[];
2
4
  export declare function getMaskedCardNumber(data: TokenizedCardMaskedData): string;
@@ -0,0 +1,38 @@
1
+ import { FindByType } from '../card/ui/typings';
2
+ import { CoordinatorToParentMessage, ParentToCoordinatorMessage } from './typings';
3
+ /**
4
+ * Coordinator lives on the parent (merchant) page.
5
+ *
6
+ * It creates a hidden iframe with `?type=coordinator` that hosts the
7
+ * IframeCoordinator. All sensitive card operations (data collection,
8
+ * encryption, API calls) happen inside that iframe — card data never
9
+ * crosses the iframe boundary back to the merchant page.
10
+ *
11
+ * Communication with the iframe uses window.postMessage, carrying only
12
+ * commands and validation state — never card data.
13
+ */
14
+ export declare class Coordinator {
15
+ private iframe;
16
+ private iframeBaseUrl;
17
+ private messageHandler;
18
+ constructor();
19
+ /**
20
+ * Mount the coordinator iframe into the DOM and wait until it is
21
+ * fully initialised (receives `coordinator:ready` from the iframe with the session state).
22
+ *
23
+ * The iframe is hidden — it has no visual presence on the page.
24
+ * It serves purely as an isolated execution environment for secure
25
+ * card-data handling.
26
+ */
27
+ init: (sessionId: string, baseUrl: string, abortCtrl?: AbortController) => Promise<void>;
28
+ /**
29
+ * Send a command to the coordinator iframe.
30
+ * Only commands and configuration — never card data.
31
+ */
32
+ postMessage(message: ParentToCoordinatorMessage): void;
33
+ onMessage<T extends CoordinatorToParentMessage['type']>(type: T, callback: (message: FindByType<CoordinatorToParentMessage, T>) => void): void;
34
+ /**
35
+ * Clean up the coordinator iframe and all associated resources.
36
+ */
37
+ dispose(): void;
38
+ }
@@ -0,0 +1 @@
1
+ export declare const COORDINATOR_IFRAME_CHANNEL_NAME = "coordinator-channel";
@@ -0,0 +1,33 @@
1
+ /**
2
+ * IframeCoordinator lives entirely within the iframe isolation layer.
3
+ *
4
+ * It coordinates all card form elements via the Channel Messaging API,
5
+ * combines and validates card data within the iframe, encrypts sensitive
6
+ * data, and makes direct API calls to the Hellgate backend.
7
+ *
8
+ * SECURITY: Card data NEVER crosses the iframe boundary.
9
+ * - Card form elements send raw values only to the coordinator (same origin, via MessagePort)
10
+ * - The coordinator encrypts data and communicates with the backend directly
11
+ * - Only validation state (empty, complete, valid) is sent to the parent via postMessage
12
+ */
13
+ export declare class IframeCoordinator {
14
+ private parentOrigin;
15
+ private cardHandlerCoordinator;
16
+ private session;
17
+ private channel;
18
+ constructor(sessionId: string, apiBaseUrl: string, parentOrigin: string);
19
+ init: () => Promise<void>;
20
+ private setupChannelListener;
21
+ /**
22
+ * Listen for messages from the parent CardHandler.
23
+ * Only commands and configuration cross this boundary - never card data.
24
+ */
25
+ private setupParentMessageListener;
26
+ private handleParentMessage;
27
+ /**
28
+ * Send a message to the parent CardHandler.
29
+ * Only validation state and results - never card data.
30
+ */
31
+ private postMessageToParent;
32
+ dispose(): void;
33
+ }
@@ -0,0 +1 @@
1
+ export declare function initCoordinatorIframe(sessionId: string, apiBaseUrl: string, origin: string): void;
@@ -0,0 +1,2 @@
1
+ export { initCoordinatorIframe } from './iframe';
2
+ export { IframeCoordinator } from './iframe-coordinator';
@@ -0,0 +1,3 @@
1
+ export { Coordinator } from './coordinator';
2
+ export { IframeCoordinator } from './iframe/iframe-coordinator';
3
+ export type { CoordinatorFormState, CoordinatorToParentMessage, ParentToCoordinatorMessage, } from './typings';
@@ -0,0 +1,39 @@
1
+ import { CardHandlerToCoordinatorMessage, CoordinatorToCardHandlerMessage } from '../card/coordinator/typings';
2
+ import { SessionStateDTO } from '../session';
3
+ /**
4
+ * Message types sent FROM the parent CardHandler TO the coordinator iframe
5
+ * via window.postMessage (crosses iframe boundary)
6
+ *
7
+ * IMPORTANT: No card data flows through these messages.
8
+ * Only commands and configuration are sent.
9
+ */
10
+ export type ParentToCoordinatorMessage = {
11
+ type: 'coordinator:init';
12
+ sessionId: string;
13
+ baseUrl: string;
14
+ } | {
15
+ type: 'coordinator:dispose';
16
+ } | CardHandlerToCoordinatorMessage;
17
+ /**
18
+ * Message types sent FROM the coordinator iframe TO the parent CardHandler
19
+ * via window.postMessage (crosses iframe boundary)
20
+ *
21
+ * IMPORTANT: No card data flows through these messages.
22
+ * Only validation state and tokenization results are sent.
23
+ */
24
+ export type CoordinatorToParentMessage = {
25
+ type: 'coordinator:ready';
26
+ } | {
27
+ type: 'coordinator:error';
28
+ error: unknown;
29
+ } | {
30
+ type: 'coordinator:session_state_change';
31
+ state: SessionStateDTO;
32
+ } | CoordinatorToCardHandlerMessage;
33
+ export type CoordinatorFormState = {
34
+ empty: boolean;
35
+ complete: boolean;
36
+ valid: boolean;
37
+ error?: string;
38
+ errorCode?: string;
39
+ };