@thavguard/arc-pay 0.1.23 → 0.1.25

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/README.md CHANGED
@@ -54,6 +54,58 @@ with `Authorization: Bearer <pk_...>`, `Content-Type`, optional
54
54
  may use either `Authorization: Bearer <pk_...>` or `X-Api-Key: pk_...` for
55
55
  `/payments/{id}/tokenize`.
56
56
 
57
+ ### Hosted Fields appearance
58
+
59
+ Hosted Fields are secure iframe inputs. The merchant page owns layout and
60
+ container styling: labels, wrappers, spacing, borders, shadows, error text, and
61
+ the submit button should be regular merchant CSS. Arc Pay only styles the input
62
+ text inside each iframe through a typed, allowlisted `appearance` contract.
63
+
64
+ ```ts
65
+ const elements = arcpay.elements({
66
+ appearance: {
67
+ variables: {
68
+ fontFamily: "Inter, system-ui, sans-serif",
69
+ fontSize: "16px",
70
+ lineHeight: "24px",
71
+ colorText: "#111827",
72
+ colorPlaceholder: "#9ca3af",
73
+ colorDanger: "#dc2626",
74
+ caretColor: "#111827",
75
+ },
76
+ rules: {
77
+ focus: { "font-weight": "600" },
78
+ invalid: { color: "#dc2626" },
79
+ complete: { color: "#047857" },
80
+ },
81
+ },
82
+ });
83
+
84
+ const number = elements.create("cardNumber", {
85
+ placeholder: "1234 1234 1234 1234",
86
+ });
87
+ const expiry = elements.create("cardExpiry");
88
+ const cvc = elements.create("cardCvv", {
89
+ appearance: {
90
+ rules: {
91
+ base: { "text-align": "center" },
92
+ },
93
+ },
94
+ });
95
+
96
+ number.mount("#card-number");
97
+ expiry.mount("#card-expiry");
98
+ cvc.mount("#card-cvv");
99
+ ```
100
+
101
+ `appearance.theme` defaults to `"none"` so Arc Pay branding is not imposed on
102
+ merchant checkout pages. `theme: "arcpay"` is available for demos and quick
103
+ starts. Supported iframe properties are limited to text, color, caret,
104
+ placeholder, opacity, and `background-color`; container CSS such as border,
105
+ padding, margin, shadow, position, transform, and z-index is intentionally
106
+ dropped. Use element `change` events (`isEmpty`, `isComplete`, `isValid`,
107
+ `brand`, `lastFour`) to style your own wrappers.
108
+
57
109
  `@thavguard/arc-pay/server` intentionally does not expose `tokenizeCard()`.
58
110
  Tokenization belongs to Hosted Fields. Direct browser calls with a publishable
59
111
  key are only for explicitly approved raw-card forms; those forms handle
@@ -26,11 +26,36 @@ interface StyleSubset {
26
26
  base: Record<string, string>;
27
27
  invalid?: Record<string, string>;
28
28
  focus?: Record<string, string>;
29
+ complete?: Record<string, string>;
30
+ empty?: Record<string, string>;
31
+ }
32
+
33
+ type HostedFieldsTheme = "none" | "arcpay";
34
+ interface HostedFieldsAppearanceVariables {
35
+ fontFamily?: string;
36
+ fontSize?: string;
37
+ fontWeight?: string;
38
+ fontStyle?: string;
39
+ lineHeight?: string;
40
+ letterSpacing?: string;
41
+ textAlign?: string;
42
+ colorText?: string;
43
+ colorPlaceholder?: string;
44
+ colorDanger?: string;
45
+ colorSuccess?: string;
46
+ colorBackground?: string;
47
+ caretColor?: string;
48
+ }
49
+ type HostedFieldsAppearanceRule = "base" | "focus" | "invalid" | "complete" | "empty";
50
+ interface HostedFieldsAppearance {
51
+ theme?: HostedFieldsTheme;
52
+ variables?: HostedFieldsAppearanceVariables;
53
+ rules?: Partial<Record<HostedFieldsAppearanceRule, Record<string, string>>>;
29
54
  }
30
55
 
31
56
  interface ElementOptions {
32
- /** StyleSubset applied via arcpay:style postMessage. */
33
- style?: StyleSubset;
57
+ /** Iframe-safe input appearance. Container layout remains merchant-owned CSS. */
58
+ appearance?: HostedFieldsAppearance;
34
59
  placeholder?: string;
35
60
  }
36
61
  type ElementEvent = {
@@ -38,6 +63,8 @@ type ElementEvent = {
38
63
  } | {
39
64
  type: "change";
40
65
  isValid: boolean;
66
+ isEmpty: boolean;
67
+ isComplete: boolean;
41
68
  brand?: string;
42
69
  lastFour?: string;
43
70
  } | {
@@ -63,7 +90,7 @@ declare class Element {
63
90
  mount(target: string | HTMLElement): void;
64
91
  private handleMessage;
65
92
  update(options: {
66
- style?: StyleSubset;
93
+ appearance?: HostedFieldsAppearance;
67
94
  placeholder?: string;
68
95
  }): void;
69
96
  destroy(): void;
@@ -91,16 +118,21 @@ interface TokenizeResult {
91
118
  expiresAt: string;
92
119
  }
93
120
 
94
- type ElementsOptions = Record<string, never>;
121
+ interface ElementsOptions {
122
+ /** Default iframe-safe input appearance applied to elements created by this factory. */
123
+ appearance?: HostedFieldsAppearance;
124
+ }
95
125
  declare class Elements {
96
126
  private readonly elementMap;
97
127
  private readonly iframeBase;
98
128
  private readonly publishableKey;
99
129
  private readonly channelId;
100
130
  private tokenizeInFlight;
131
+ private readonly appearance?;
101
132
  constructor(opts: {
102
133
  publishableKey: string;
103
134
  iframeBase?: string;
135
+ appearance?: HostedFieldsAppearance;
104
136
  });
105
137
  create(field: FieldType, options?: ElementOptions): Element;
106
138
  tokenize(paymentId: string, idempotencyKey: string): Promise<TokenizeResult>;
@@ -122,4 +154,4 @@ declare const ArcPay: {
122
154
  __resetForTests: () => void;
123
155
  };
124
156
 
125
- export { ArcPay as A, type ElementEvent as E, type FieldType as F, type TokenizeResult as T, type ArcPayInstance as a, type ArcPayLoadOptions as b, type ElementOptions as c, Elements as d, type ElementsOptions as e, type Environment as f };
157
+ export { ArcPay as A, type ElementEvent as E, type FieldType as F, type HostedFieldsAppearance as H, type TokenizeResult as T, type ArcPayInstance as a, type ArcPayLoadOptions as b, type ElementOptions as c, Elements as d, type ElementsOptions as e, type Environment as f, type HostedFieldsAppearanceRule as g, type HostedFieldsAppearanceVariables as h, type HostedFieldsTheme as i };
@@ -26,11 +26,36 @@ interface StyleSubset {
26
26
  base: Record<string, string>;
27
27
  invalid?: Record<string, string>;
28
28
  focus?: Record<string, string>;
29
+ complete?: Record<string, string>;
30
+ empty?: Record<string, string>;
31
+ }
32
+
33
+ type HostedFieldsTheme = "none" | "arcpay";
34
+ interface HostedFieldsAppearanceVariables {
35
+ fontFamily?: string;
36
+ fontSize?: string;
37
+ fontWeight?: string;
38
+ fontStyle?: string;
39
+ lineHeight?: string;
40
+ letterSpacing?: string;
41
+ textAlign?: string;
42
+ colorText?: string;
43
+ colorPlaceholder?: string;
44
+ colorDanger?: string;
45
+ colorSuccess?: string;
46
+ colorBackground?: string;
47
+ caretColor?: string;
48
+ }
49
+ type HostedFieldsAppearanceRule = "base" | "focus" | "invalid" | "complete" | "empty";
50
+ interface HostedFieldsAppearance {
51
+ theme?: HostedFieldsTheme;
52
+ variables?: HostedFieldsAppearanceVariables;
53
+ rules?: Partial<Record<HostedFieldsAppearanceRule, Record<string, string>>>;
29
54
  }
30
55
 
31
56
  interface ElementOptions {
32
- /** StyleSubset applied via arcpay:style postMessage. */
33
- style?: StyleSubset;
57
+ /** Iframe-safe input appearance. Container layout remains merchant-owned CSS. */
58
+ appearance?: HostedFieldsAppearance;
34
59
  placeholder?: string;
35
60
  }
36
61
  type ElementEvent = {
@@ -38,6 +63,8 @@ type ElementEvent = {
38
63
  } | {
39
64
  type: "change";
40
65
  isValid: boolean;
66
+ isEmpty: boolean;
67
+ isComplete: boolean;
41
68
  brand?: string;
42
69
  lastFour?: string;
43
70
  } | {
@@ -63,7 +90,7 @@ declare class Element {
63
90
  mount(target: string | HTMLElement): void;
64
91
  private handleMessage;
65
92
  update(options: {
66
- style?: StyleSubset;
93
+ appearance?: HostedFieldsAppearance;
67
94
  placeholder?: string;
68
95
  }): void;
69
96
  destroy(): void;
@@ -91,16 +118,21 @@ interface TokenizeResult {
91
118
  expiresAt: string;
92
119
  }
93
120
 
94
- type ElementsOptions = Record<string, never>;
121
+ interface ElementsOptions {
122
+ /** Default iframe-safe input appearance applied to elements created by this factory. */
123
+ appearance?: HostedFieldsAppearance;
124
+ }
95
125
  declare class Elements {
96
126
  private readonly elementMap;
97
127
  private readonly iframeBase;
98
128
  private readonly publishableKey;
99
129
  private readonly channelId;
100
130
  private tokenizeInFlight;
131
+ private readonly appearance?;
101
132
  constructor(opts: {
102
133
  publishableKey: string;
103
134
  iframeBase?: string;
135
+ appearance?: HostedFieldsAppearance;
104
136
  });
105
137
  create(field: FieldType, options?: ElementOptions): Element;
106
138
  tokenize(paymentId: string, idempotencyKey: string): Promise<TokenizeResult>;
@@ -122,4 +154,4 @@ declare const ArcPay: {
122
154
  __resetForTests: () => void;
123
155
  };
124
156
 
125
- export { ArcPay as A, type ElementEvent as E, type FieldType as F, type TokenizeResult as T, type ArcPayInstance as a, type ArcPayLoadOptions as b, type ElementOptions as c, Elements as d, type ElementsOptions as e, type Environment as f };
157
+ export { ArcPay as A, type ElementEvent as E, type FieldType as F, type HostedFieldsAppearance as H, type TokenizeResult as T, type ArcPayInstance as a, type ArcPayLoadOptions as b, type ElementOptions as c, Elements as d, type ElementsOptions as e, type Environment as f, type HostedFieldsAppearanceRule as g, type HostedFieldsAppearanceVariables as h, type HostedFieldsTheme as i };
@@ -1,3 +1,3 @@
1
- var ArcPay=(function(exports){'use strict';var s=class extends Error{constructor(t){super(t.message),this.name="ArcPayError",this.type=t.type,this.code=t.code,this.param=t.param,this.paymentId=t.paymentId,this.declineCode=t.declineCode,this.retryable=t.retryable,this.requestId=t.requestId;}},C=e=>e instanceof s&&e.type==="validation_error";var N=e=>e instanceof s&&e.type==="authentication_error",O=e=>e instanceof s&&e.type==="authorization_error",H=e=>e instanceof s&&e.type==="state_error",U=e=>e instanceof s&&e.type==="rate_limit_error",W=e=>e instanceof s&&e.type==="api_error",$=e=>e instanceof s&&e.type==="network_error",K=e=>e instanceof s&&e.type==="challenge_aborted";var T=e=>e.startsWith("pk_test_")?"sandbox":"live",D=e=>{if(typeof e!="string"||e.length===0)throw new s({type:"validation_error",code:"invalid_publishable_key",message:"Publishable key must be a non-empty string",retryable:false});if(!e.startsWith("pk_test_")&&!e.startsWith("pk_live_"))throw new s({type:"validation_error",code:"invalid_publishable_key",message:"Publishable key must start with pk_test_ or pk_live_. Secret keys (sk_*) cannot be used in browser.",retryable:false})};var k="data-arcpay-sandbox-banner",A=()=>{if(typeof document=="undefined"||document.querySelector(`[${k}]`))return;let e=document.createElement("div");e.setAttribute(k,""),e.style.cssText="position:fixed;top:0;left:0;right:0;z-index:2147483647;background:#ffd166;color:#222;font:13px/1.4 system-ui,sans-serif;padding:6px 12px;display:flex;align-items:center;justify-content:center;box-shadow:0 1px 3px rgba(0,0,0,0.1);";let t=document.createElement("span");t.textContent="ARC PAY TEST MODE \u2014 payments are simulated",e.appendChild(t);let r=document.createElement("button");r.type="button",r.setAttribute("data-arcpay-banner-dismiss",""),r.textContent="\xD7",r.setAttribute("aria-label","Dismiss test mode banner"),r.style.cssText="margin-left:12px;background:transparent;border:0;font-size:18px;cursor:pointer;color:inherit;",r.addEventListener("click",()=>e.remove()),e.appendChild(r),document.body.appendChild(e);};var q="arcpay:",V=e=>typeof e=="object"&&e!==null&&"type"in e&&typeof e.type=="string"&&e.type.startsWith(q),E=(e,t,r)=>{if(r==="*")throw new s({type:"validation_error",code:"wildcard_origin_forbidden",message:"postToIframe: targetOrigin cannot be '*'",retryable:false});if(!e.contentWindow)throw new s({type:"validation_error",code:"iframe_not_loaded",message:"postToIframe: iframe.contentWindow is null (iframe not mounted)",retryable:false});e.contentWindow.postMessage(t,r);};var f=(e,t)=>e.origin!==t||!V(e.data)?null:e.data;var Y=new Set(["position","transform","pointer-events","pointerevents","z-index","zindex","top","left","right","bottom","inset"]),v=e=>{let t={};for(let[r,o]of Object.entries(e)){let i=r.toLowerCase();Y.has(i)||(t[r]=o);}return t},S=e=>{let t={base:v(e.base)};return e.invalid!==void 0&&(t.invalid=v(e.invalid)),e.focus!==void 0&&(t.focus=v(e.focus)),t};var F={cardNumber:"Arc Pay card number",cardExpiry:"Arc Pay card expiration date",cardCvv:"Arc Pay card security code"},g=class{constructor(t,r,o){this.field=t;this.options=r;this.context=o;this.iframe=null;this.listeners={ready:new Set,change:new Set,error:new Set};this.status="pending";this.messageHandler=null;}mount(t){if(this.iframe)throw new s({type:"validation_error",code:"already_mounted",message:`Element ${this.field} is already mounted`,retryable:false});let r=typeof t=="string"?document.querySelector(t):t;if(!(r instanceof HTMLElement))throw new s({type:"validation_error",code:"mount_target_not_found",message:`mount target not found: ${String(t)}`,retryable:false});let o=document.createElement("iframe");o.src=`${this.context.iframeBase}/iframe/${this.field}`,o.style.cssText="border:0;width:100%;height:100%;display:block;",o.setAttribute("allow","payment"),o.setAttribute("data-arcpay-element",this.field),o.setAttribute("title",F[this.field]),o.setAttribute("aria-label",F[this.field]),r.appendChild(o),this.iframe=o;let i=new URL(this.context.iframeBase).origin;this.messageHandler=n=>{var l;if(n.source!==((l=this.iframe)==null?void 0:l.contentWindow))return;let d=f(n,i);d&&this.handleMessage(d);},window.addEventListener("message",this.messageHandler),o.addEventListener("load",()=>{if(!this.iframe)return;let n={type:"arcpay:hello",origin:window.location.origin,publishableKey:this.context.publishableKey,channelId:this.context.channelId};E(this.iframe,n,i);},{once:true});}handleMessage(t){t.type==="arcpay:ready"?(this.status="ready",this.options.style&&this.send({type:"arcpay:style",payload:S(this.options.style)}),this.options.placeholder&&this.send({type:"arcpay:placeholder",field:this.field,placeholder:this.options.placeholder}),this.emit({type:"ready"})):t.type==="arcpay:rejected"?(this.status="error",this.emit({type:"error",reason:t.reason})):t.type==="arcpay:change"&&t.field===this.field&&this.emit({type:"change",isValid:t.isValid,brand:t.brand,lastFour:t.lastFour});}update(t){t.style&&this.send({type:"arcpay:style",payload:S(t.style)}),t.placeholder&&this.send({type:"arcpay:placeholder",field:this.field,placeholder:t.placeholder});}destroy(){this.iframe&&(this.iframe.remove(),this.iframe=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null);for(let t of Object.values(this.listeners))t.clear();this.status="pending";}on(t,r){return this.listeners[t].add(r),()=>this.listeners[t].delete(r)}focus(){this.send({type:"arcpay:focus"});}clear(){this.send({type:"arcpay:clear"});}isReady(){return this.status==="ready"}getIframeContentWindow(){var t,r;return (r=(t=this.iframe)==null?void 0:t.contentWindow)!=null?r:null}send(t){if(!this.iframe)throw new s({type:"validation_error",code:"not_mounted",message:`Element ${this.field} is not mounted`,retryable:false});E(this.iframe,t,new URL(this.context.iframeBase).origin);}emit(t){for(let r of this.listeners[t.type])r(t);}};var j="https://sdk.arcpay.space",X=()=>{var e;if(!((e=globalThis.crypto)!=null&&e.randomUUID))throw new s({type:"validation_error",code:"crypto_unavailable",message:"crypto.randomUUID is required for Hosted Fields",retryable:false});return globalThis.crypto.randomUUID()},h=class{constructor(t){this.elementMap=new Map;this.tokenizeInFlight=false;var r;this.publishableKey=t.publishableKey,this.iframeBase=(r=t.iframeBase)!=null?r:j,this.channelId=X();}create(t,r={}){if(this.elementMap.has(t))throw new s({type:"validation_error",code:"duplicate_element",message:`Element for ${t} already created`,retryable:false});let o={iframeBase:this.iframeBase,publishableKey:this.publishableKey,channelId:this.channelId},i=new g(t,r,o);return this.elementMap.set(t,i),i}async tokenize(t,r){if(this.tokenizeInFlight)throw new s({type:"validation_error",code:"tokenize_in_progress",message:"A tokenize() call is already in progress for this Elements instance",retryable:false});let o=this.elementMap.get("cardNumber"),i=this.elementMap.get("cardExpiry"),n=this.elementMap.get("cardCvv");if(!o||!i||!n)throw new s({type:"validation_error",code:"incomplete_elements",message:"All three elements (cardNumber, cardExpiry, cardCvv) must be created and mounted before tokenize()",retryable:false});if(!o.isReady()||!i.isReady()||!n.isReady())throw new s({type:"validation_error",code:"elements_not_ready",message:"Wait for all elements to fire 'ready' event before tokenize()",retryable:false});this.tokenizeInFlight=true;try{return await this.doTokenize(o,t,r)}finally{this.tokenizeInFlight=false;}}doTokenize(t,r,o){let i=new URL(this.iframeBase).origin,n=t.getIframeContentWindow();return new Promise((d,l)=>{let p=window.setTimeout(()=>{window.removeEventListener("message",c),l(new s({type:"network_error",code:"tokenize_timeout",message:"tokenize() timed out after 30 seconds",retryable:true,paymentId:r}));},3e4),c=m=>{if(n!==null&&m.source!==n)return;let a=f(m,i);a&&(a.type==="arcpay:tokenize-result"?(clearTimeout(p),window.removeEventListener("message",c),d({cardTokenId:a.cardTokenId,cardMask:a.cardMask,cardScheme:a.cardScheme,cardBin:a.cardBin,expiresIn:a.expiresIn,expiresAt:a.expiresAt})):a.type==="arcpay:tokenize-error"&&(clearTimeout(p),window.removeEventListener("message",c),l(new s({type:a.errorType==="validation_error"||a.errorType==="configuration_error"||a.errorType==="network_error"||a.errorType==="api_error"?a.errorType:"api_error",code:a.code,message:a.message,retryable:false,paymentId:r}))));};window.addEventListener("message",c),t.send({type:"arcpay:tokenize",paymentId:r,idempotencyKey:o});})}destroy(){for(let t of this.elementMap.values())t.destroy();this.elementMap.clear();}};var G=D,x=new Map,J=e=>(T(e)==="sandbox"&&A(),{publishableKey:e,environment:T(e),elements:()=>new h({publishableKey:e})});function Q(e){try{G(e);}catch(i){return Promise.reject(i)}let t=e,r=x.get(t);if(r)return r;let o=Promise.resolve(J(e));return x.set(t,o),o}var Z=()=>{x.clear();},ee={load:Q,__resetForTests:Z};var te=[1,4,8,15,16,24,32,48],re=e=>te.includes(e)?e:24,oe=e=>e>=1e3?"05":e>=600?"04":e>=500?"03":e>=390?"02":"01",B=(e="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")=>{if(typeof window=="undefined"||typeof navigator=="undefined"||typeof screen=="undefined")throw new Error("collectBrowserInfo must be called in a browser environment");return {accept_header:e,language:navigator.language||"en",screen_width:screen.width,screen_height:screen.height,color_depth:re(screen.colorDepth),timezone_offset_minutes:new Date().getTimezoneOffset(),java_enabled:false,user_agent:navigator.userAgent,window_size:oe(window.innerWidth||screen.width)}},b=e=>e!=null?e:null,_=e=>(e==null?void 0:e.type)==="three_ds_method"&&e.three_ds.phase==="method",w=e=>(e==null?void 0:e.type)==="three_ds_challenge"&&e.three_ds.phase==="challenge",y=e=>({action:e.three_ds.submit.url,method:e.three_ds.submit.method,target:e.three_ds.submit.target,fields:e.three_ds.submit.fields}),M=e=>{let t;try{t=new URL(e);}catch(r){throw new Error("3DS form action must be an absolute HTTPS URL")}if(t.protocol!=="https:")throw new Error("3DS form action must use HTTPS")},R=e=>{let t=b(e);return t?{kind:t.three_ds.phase,protocolVersion:t.three_ds.version,form:y(t),completionEndpoint:t.three_ds.completion_endpoint,threeDSServerTransId:t.three_ds.three_ds_server_trans_id}:null},I=(e,t="Y")=>{if(!_(e)||!e.three_ds.three_ds_server_trans_id)throw new Error("nextAction must be a three_ds_method action with three_ds_server_trans_id");return {completion_indicator:t,three_ds_server_trans_id:e.three_ds.three_ds_server_trans_id}},ne=e=>{if(e)return e;if(typeof document=="undefined")throw new Error("3DS browser helpers must be called in a browser environment");return document},se=e=>{e.submit();},u=(e,t={})=>{var p,c;let r=ne(t.document),o=(p=t.container)!=null?p:r.body,i=y(e);M(i.action);let n=r.createElement("form"),d=i.target==="hidden_iframe"?`arcpay-three-ds-method-${crypto.randomUUID()}`:(c=t.challengeTarget)!=null?c:"_self",l;n.method=i.method,n.action=i.action,n.target=d,n.hidden=true;for(let m of i.fields){let a=r.createElement("input");a.type="hidden",a.name=m.name,a.value=m.value,n.append(a);}return i.target==="hidden_iframe"&&(l=r.createElement("iframe"),l.name=d,l.title="3-D Secure method",l.hidden=true,o.append(l)),o.append(n),{form:n,iframe:l,submit:()=>{var m;return ((m=t.submitter)!=null?m:se)(n)},remove:()=>{n.remove(),l==null||l.remove();}}},ie=(e,t,r)=>new Promise((o,i)=>{if(!e.iframe){o("loaded");return}if(r!=null&&r.aborted){i(new DOMException("The operation was aborted","AbortError"));return}let n=false,d=()=>{var a;(a=e.iframe)==null||a.removeEventListener("load",p),r==null||r.removeEventListener("abort",c),clearTimeout(m);},l=a=>{n||(n=true,d(),o(a));},p=()=>l("loaded"),c=()=>{n||(n=true,d(),i(new DOMException("The operation was aborted","AbortError")));},m=setTimeout(()=>l("timeout"),t);e.iframe.addEventListener("load",p,{once:true}),r==null||r.addEventListener("abort",c,{once:true});}),z=async(e,t)=>{var i,n;if(!e)return {status:"no_action"};if(w(e)){let d=u(e,t);return d.submit(),{status:"challenge_submitted",action:e,mounted:d}}if(!_(e))return {status:"no_action"};let r=t.completeThreeDSMethod;if(!r)throw new Error("completeThreeDSMethod is required for 3DS Method actions");let o=u(e,t);try{o.submit();let d=await ie(o,(i=t.methodTimeoutMs)!=null?i:1e4,t.signal),l=(n=t.methodCompletionIndicator)!=null?n:d==="loaded"?"Y":"N",p=await r(I(e,l),e),c=b(p.next_action);if(c&&w(c)){let m=u(c,t);return m.submit(),{status:"challenge_submitted",action:c,response:p,mounted:m,methodResult:d}}return {status:"method_completed",response:p,methodResult:d}}finally{o.remove();}},P=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),L=e=>{let t=y(e);M(t.action);let r=t.target==="hidden_iframe"?"arcpay-three-ds-method":"_self",o=t.fields.map(n=>`<input type="hidden" name="${P(n.name)}" value="${P(n.value)}">`).join("");return `<!doctype html><html><head><meta charset="utf-8"></head><body>${t.target==="hidden_iframe"?'<iframe name="arcpay-three-ds-method" title="3-D Secure method" hidden></iframe>':""}<form method="POST" action="${P(t.action)}" target="${r}">${o}</form><script>document.forms[0].submit();</script></body></html>`};var ke="0.1.23";
2
- exports.ArcPay=ee;exports.ArcPayError=s;exports.Elements=h;exports.SDK_VERSION=ke;exports.buildThreeDSAutoSubmitHtml=L;exports.buildThreeDSBrowserForm=y;exports.buildThreeDSBrowserStep=R;exports.buildThreeDSMethodCompletion=I;exports.collectBrowserInfo=B;exports.getThreeDSAction=b;exports.isApiError=W;exports.isAuthenticationError=N;exports.isAuthorizationError=O;exports.isChallengeAborted=K;exports.isNetworkError=$;exports.isRateLimitError=U;exports.isStateError=H;exports.isThreeDSChallengeAction=w;exports.isThreeDSMethodAction=_;exports.isValidationError=C;exports.mountThreeDSBrowserForm=u;exports.runThreeDSBrowserFlow=z;return exports;})({});//# sourceMappingURL=arcpay.global.js.map
1
+ var ArcPay=(function(exports){'use strict';var i=class extends Error{constructor(t){super(t.message),this.name="ArcPayError",this.type=t.type,this.code=t.code,this.param=t.param,this.paymentId=t.paymentId,this.declineCode=t.declineCode,this.retryable=t.retryable,this.requestId=t.requestId;}},O=e=>e instanceof i&&e.type==="validation_error";var N=e=>e instanceof i&&e.type==="authentication_error",U=e=>e instanceof i&&e.type==="authorization_error",W=e=>e instanceof i&&e.type==="state_error",$=e=>e instanceof i&&e.type==="rate_limit_error",K=e=>e instanceof i&&e.type==="api_error",q=e=>e instanceof i&&e.type==="network_error",V=e=>e instanceof i&&e.type==="challenge_aborted";var S=e=>e.startsWith("pk_test_")?"sandbox":"live",D=e=>{if(typeof e!="string"||e.length===0)throw new i({type:"validation_error",code:"invalid_publishable_key",message:"Publishable key must be a non-empty string",retryable:false});if(!e.startsWith("pk_test_")&&!e.startsWith("pk_live_"))throw new i({type:"validation_error",code:"invalid_publishable_key",message:"Publishable key must start with pk_test_ or pk_live_. Secret keys (sk_*) cannot be used in browser.",retryable:false})};var k="data-arcpay-sandbox-banner",B=()=>{if(typeof document=="undefined"||document.querySelector(`[${k}]`))return;let e=document.createElement("div");e.setAttribute(k,""),e.style.cssText="position:fixed;top:0;left:0;right:0;z-index:2147483647;background:#ffd166;color:#222;font:13px/1.4 system-ui,sans-serif;padding:6px 12px;display:flex;align-items:center;justify-content:center;box-shadow:0 1px 3px rgba(0,0,0,0.1);";let t=document.createElement("span");t.textContent="ARC PAY TEST MODE \u2014 payments are simulated",e.appendChild(t);let r=document.createElement("button");r.type="button",r.setAttribute("data-arcpay-banner-dismiss",""),r.textContent="\xD7",r.setAttribute("aria-label","Dismiss test mode banner"),r.style.cssText="margin-left:12px;background:transparent;border:0;font-size:18px;cursor:pointer;color:inherit;",r.addEventListener("click",()=>e.remove()),e.appendChild(r),document.body.appendChild(e);};var Y="arcpay:",j=e=>typeof e=="object"&&e!==null&&"type"in e&&typeof e.type=="string"&&e.type.startsWith(Y),x=(e,t,r)=>{if(r==="*")throw new i({type:"validation_error",code:"wildcard_origin_forbidden",message:"postToIframe: targetOrigin cannot be '*'",retryable:false});if(!e.contentWindow)throw new i({type:"validation_error",code:"iframe_not_loaded",message:"postToIframe: iframe.contentWindow is null (iframe not mounted)",retryable:false});e.contentWindow.postMessage(t,r);};var w=(e,t)=>e.origin!==t||!j(e.data)?null:e.data;var X=new Set(["--arcpay-placeholder-color","background-color","caret-color","color","font-family","font-size","font-style","font-weight","letter-spacing","line-height","opacity","text-align","text-decoration","text-transform"]),G={base:{"font-family":'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',"font-size":"16px","line-height":"24px",color:"#111827","--arcpay-placeholder-color":"#9ca3af","caret-color":"#111827"},focus:{color:"#111827"},invalid:{color:"#dc2626"},complete:{color:"#111827"},empty:{color:"#111827"}},u=(e,t)=>{if(!(!e&&!t))return {...e!=null?e:{},...t!=null?t:{}}},y=(e,t,r)=>{r!==void 0&&(e[t]=r);},J=e=>{if(!(e===void 0||e==="none"||e==="arcpay"))throw new i({type:"validation_error",code:"invalid_hosted_fields_theme",message:`Unsupported Hosted Fields appearance theme: ${String(e)}`,retryable:false})},h=e=>{let t={};for(let[r,o]of Object.entries(e)){let n=r.toLowerCase();X.has(n)&&(t[n]=o);}return t},Q=e=>{let t={base:h(e.base)};return e.invalid!==void 0&&(t.invalid=h(e.invalid)),e.focus!==void 0&&(t.focus=h(e.focus)),e.complete!==void 0&&(t.complete=h(e.complete)),e.empty!==void 0&&(t.empty=h(e.empty)),t},P=e=>{var p;J(e==null?void 0:e.theme);let t=(e==null?void 0:e.theme)==="arcpay"?G:{base:{}},r={base:{}},o=e==null?void 0:e.variables;o&&(y(r.base,"font-family",o.fontFamily),y(r.base,"font-size",o.fontSize),y(r.base,"font-weight",o.fontWeight),y(r.base,"font-style",o.fontStyle),y(r.base,"line-height",o.lineHeight),y(r.base,"letter-spacing",o.letterSpacing),y(r.base,"text-align",o.textAlign),y(r.base,"color",o.colorText),y(r.base,"--arcpay-placeholder-color",o.colorPlaceholder),y(r.base,"background-color",o.colorBackground),y(r.base,"caret-color",o.caretColor),o.colorDanger!==void 0&&(r.invalid={color:o.colorDanger}),o.colorSuccess!==void 0&&(r.complete={color:o.colorSuccess}));let n=e==null?void 0:e.rules,s={base:{...t.base,...r.base,...(p=n==null?void 0:n.base)!=null?p:{}}},d=u(u(t.focus,r.focus),n==null?void 0:n.focus),l=u(u(t.invalid,r.invalid),n==null?void 0:n.invalid),m=u(u(t.complete,r.complete),n==null?void 0:n.complete),c=u(u(t.empty,r.empty),n==null?void 0:n.empty);return d!==void 0&&(s.focus=d),l!==void 0&&(s.invalid=l),m!==void 0&&(s.complete=m),c!==void 0&&(s.empty=c),Q(s)};var M={cardNumber:"Arc Pay card number",cardExpiry:"Arc Pay card expiration date",cardCvv:"Arc Pay card security code"},T=class{constructor(t,r,o){this.field=t;this.options=r;this.context=o;this.iframe=null;this.listeners={ready:new Set,change:new Set,error:new Set};this.status="pending";this.messageHandler=null;}mount(t){if(this.iframe)throw new i({type:"validation_error",code:"already_mounted",message:`Element ${this.field} is already mounted`,retryable:false});let r=typeof t=="string"?document.querySelector(t):t;if(!(r instanceof HTMLElement))throw new i({type:"validation_error",code:"mount_target_not_found",message:`mount target not found: ${String(t)}`,retryable:false});let o=document.createElement("iframe");o.src=`${this.context.iframeBase}/iframe/${this.field}`,o.style.cssText="border:0;width:100%;height:100%;display:block;",o.setAttribute("allow","payment"),o.setAttribute("data-arcpay-element",this.field),o.setAttribute("title",M[this.field]),o.setAttribute("aria-label",M[this.field]),r.appendChild(o),this.iframe=o;let n=new URL(this.context.iframeBase).origin;this.messageHandler=s=>{var l;if(s.source!==((l=this.iframe)==null?void 0:l.contentWindow))return;let d=w(s,n);d&&this.handleMessage(d);},window.addEventListener("message",this.messageHandler),o.addEventListener("load",()=>{if(!this.iframe)return;let s={type:"arcpay:hello",origin:window.location.origin,publishableKey:this.context.publishableKey,channelId:this.context.channelId};x(this.iframe,s,n);},{once:true});}handleMessage(t){t.type==="arcpay:ready"?(this.status="ready",this.options.appearance&&this.send({type:"arcpay:style",payload:P(this.options.appearance)}),this.options.placeholder&&this.send({type:"arcpay:placeholder",field:this.field,placeholder:this.options.placeholder}),this.emit({type:"ready"})):t.type==="arcpay:rejected"?(this.status="error",this.emit({type:"error",reason:t.reason})):t.type==="arcpay:change"&&t.field===this.field&&this.emit({type:"change",isValid:t.isValid,isEmpty:t.isEmpty,isComplete:t.isComplete,brand:t.brand,lastFour:t.lastFour});}update(t){t.appearance&&this.send({type:"arcpay:style",payload:P(t.appearance)}),t.placeholder&&this.send({type:"arcpay:placeholder",field:this.field,placeholder:t.placeholder});}destroy(){this.iframe&&(this.iframe.remove(),this.iframe=null),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null);for(let t of Object.values(this.listeners))t.clear();this.status="pending";}on(t,r){return this.listeners[t].add(r),()=>this.listeners[t].delete(r)}focus(){this.send({type:"arcpay:focus"});}clear(){this.send({type:"arcpay:clear"});}isReady(){return this.status==="ready"}getIframeContentWindow(){var t,r;return (r=(t=this.iframe)==null?void 0:t.contentWindow)!=null?r:null}send(t){if(!this.iframe)throw new i({type:"validation_error",code:"not_mounted",message:`Element ${this.field} is not mounted`,retryable:false});x(this.iframe,t,new URL(this.context.iframeBase).origin);}emit(t){for(let r of this.listeners[t.type])r(t);}};var Z="https://sdk.arcpay.space",ee=()=>{var e;if(!((e=globalThis.crypto)!=null&&e.randomUUID))throw new i({type:"validation_error",code:"crypto_unavailable",message:"crypto.randomUUID is required for Hosted Fields",retryable:false});return globalThis.crypto.randomUUID()},f=class{constructor(t){this.elementMap=new Map;this.tokenizeInFlight=false;var r;this.publishableKey=t.publishableKey,this.iframeBase=(r=t.iframeBase)!=null?r:Z,this.channelId=ee(),this.appearance=t.appearance;}create(t,r={}){var s;if(this.elementMap.has(t))throw new i({type:"validation_error",code:"duplicate_element",message:`Element for ${t} already created`,retryable:false});let o={iframeBase:this.iframeBase,publishableKey:this.publishableKey,channelId:this.channelId},n=new T(t,{...r,appearance:(s=r.appearance)!=null?s:this.appearance},o);return this.elementMap.set(t,n),n}async tokenize(t,r){if(this.tokenizeInFlight)throw new i({type:"validation_error",code:"tokenize_in_progress",message:"A tokenize() call is already in progress for this Elements instance",retryable:false});let o=this.elementMap.get("cardNumber"),n=this.elementMap.get("cardExpiry"),s=this.elementMap.get("cardCvv");if(!o||!n||!s)throw new i({type:"validation_error",code:"incomplete_elements",message:"All three elements (cardNumber, cardExpiry, cardCvv) must be created and mounted before tokenize()",retryable:false});if(!o.isReady()||!n.isReady()||!s.isReady())throw new i({type:"validation_error",code:"elements_not_ready",message:"Wait for all elements to fire 'ready' event before tokenize()",retryable:false});this.tokenizeInFlight=true;try{return await this.doTokenize(o,t,r)}finally{this.tokenizeInFlight=false;}}doTokenize(t,r,o){let n=new URL(this.iframeBase).origin,s=t.getIframeContentWindow();return new Promise((d,l)=>{let m=window.setTimeout(()=>{window.removeEventListener("message",c),l(new i({type:"network_error",code:"tokenize_timeout",message:"tokenize() timed out after 30 seconds",retryable:true,paymentId:r}));},3e4),c=p=>{if(s!==null&&p.source!==s)return;let a=w(p,n);a&&(a.type==="arcpay:tokenize-result"?(clearTimeout(m),window.removeEventListener("message",c),d({cardTokenId:a.cardTokenId,cardMask:a.cardMask,cardScheme:a.cardScheme,cardBin:a.cardBin,expiresIn:a.expiresIn,expiresAt:a.expiresAt})):a.type==="arcpay:tokenize-error"&&(clearTimeout(m),window.removeEventListener("message",c),l(new i({type:a.errorType==="validation_error"||a.errorType==="configuration_error"||a.errorType==="network_error"||a.errorType==="api_error"?a.errorType:"api_error",code:a.code,message:a.message,retryable:false,paymentId:r}))));};window.addEventListener("message",c),t.send({type:"arcpay:tokenize",paymentId:r,idempotencyKey:o});})}destroy(){for(let t of this.elementMap.values())t.destroy();this.elementMap.clear();}};var te=D,A=new Map,re=e=>(S(e)==="sandbox"&&B(),{publishableKey:e,environment:S(e),elements:(t={})=>new f({publishableKey:e,...t})});function oe(e){try{te(e);}catch(n){return Promise.reject(n)}let t=e,r=A.get(t);if(r)return r;let o=Promise.resolve(re(e));return A.set(t,o),o}var ne=()=>{A.clear();},se={load:oe,__resetForTests:ne};var ie=[1,4,8,15,16,24,32,48],ae=e=>ie.includes(e)?e:24,le=e=>e>=1e3?"05":e>=600?"04":e>=500?"03":e>=390?"02":"01",R=(e="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")=>{if(typeof window=="undefined"||typeof navigator=="undefined"||typeof screen=="undefined")throw new Error("collectBrowserInfo must be called in a browser environment");return {accept_header:e,language:navigator.language||"en",screen_width:screen.width,screen_height:screen.height,color_depth:ae(screen.colorDepth),timezone_offset_minutes:new Date().getTimezoneOffset(),java_enabled:false,user_agent:navigator.userAgent,window_size:le(window.innerWidth||screen.width)}},v=e=>e!=null?e:null,E=e=>(e==null?void 0:e.type)==="three_ds_method"&&e.three_ds.phase==="method",_=e=>(e==null?void 0:e.type)==="three_ds_challenge"&&e.three_ds.phase==="challenge",b=e=>({action:e.three_ds.submit.url,method:e.three_ds.submit.method,target:e.three_ds.submit.target,fields:e.three_ds.submit.fields}),z=e=>{let t;try{t=new URL(e);}catch(r){throw new Error("3DS form action must be an absolute HTTPS URL")}if(t.protocol!=="https:")throw new Error("3DS form action must use HTTPS")},C=e=>{let t=v(e);return t?{kind:t.three_ds.phase,protocolVersion:t.three_ds.version,form:b(t),completionEndpoint:t.three_ds.completion_endpoint,threeDSServerTransId:t.three_ds.three_ds_server_trans_id}:null},I=(e,t="Y")=>{if(!E(e)||!e.three_ds.three_ds_server_trans_id)throw new Error("nextAction must be a three_ds_method action with three_ds_server_trans_id");return {completion_indicator:t,three_ds_server_trans_id:e.three_ds.three_ds_server_trans_id}},de=e=>{if(e)return e;if(typeof document=="undefined")throw new Error("3DS browser helpers must be called in a browser environment");return document},ce=e=>{e.submit();},g=(e,t={})=>{var m,c;let r=de(t.document),o=(m=t.container)!=null?m:r.body,n=b(e);z(n.action);let s=r.createElement("form"),d=n.target==="hidden_iframe"?`arcpay-three-ds-method-${crypto.randomUUID()}`:(c=t.challengeTarget)!=null?c:"_self",l;s.method=n.method,s.action=n.action,s.target=d,s.hidden=true;for(let p of n.fields){let a=r.createElement("input");a.type="hidden",a.name=p.name,a.value=p.value,s.append(a);}return n.target==="hidden_iframe"&&(l=r.createElement("iframe"),l.name=d,l.title="3-D Secure method",l.hidden=true,o.append(l)),o.append(s),{form:s,iframe:l,submit:()=>{var p;return ((p=t.submitter)!=null?p:ce)(s)},remove:()=>{s.remove(),l==null||l.remove();}}},pe=(e,t,r)=>new Promise((o,n)=>{if(!e.iframe){o("loaded");return}if(r!=null&&r.aborted){n(new DOMException("The operation was aborted","AbortError"));return}let s=false,d=()=>{var a;(a=e.iframe)==null||a.removeEventListener("load",m),r==null||r.removeEventListener("abort",c),clearTimeout(p);},l=a=>{s||(s=true,d(),o(a));},m=()=>l("loaded"),c=()=>{s||(s=true,d(),n(new DOMException("The operation was aborted","AbortError")));},p=setTimeout(()=>l("timeout"),t);e.iframe.addEventListener("load",m,{once:true}),r==null||r.addEventListener("abort",c,{once:true});}),H=async(e,t)=>{var n,s;if(!e)return {status:"no_action"};if(_(e)){let d=g(e,t);return d.submit(),{status:"challenge_submitted",action:e,mounted:d}}if(!E(e))return {status:"no_action"};let r=t.completeThreeDSMethod;if(!r)throw new Error("completeThreeDSMethod is required for 3DS Method actions");let o=g(e,t);try{o.submit();let d=await pe(o,(n=t.methodTimeoutMs)!=null?n:1e4,t.signal),l=(s=t.methodCompletionIndicator)!=null?s:d==="loaded"?"Y":"N",m=await r(I(e,l),e),c=v(m.next_action);if(c&&_(c)){let p=g(c,t);return p.submit(),{status:"challenge_submitted",action:c,response:m,mounted:p,methodResult:d}}return {status:"method_completed",response:m,methodResult:d}}finally{o.remove();}},F=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),L=e=>{let t=b(e);z(t.action);let r=t.target==="hidden_iframe"?"arcpay-three-ds-method":"_self",o=t.fields.map(s=>`<input type="hidden" name="${F(s.name)}" value="${F(s.value)}">`).join("");return `<!doctype html><html><head><meta charset="utf-8"></head><body>${t.target==="hidden_iframe"?'<iframe name="arcpay-three-ds-method" title="3-D Secure method" hidden></iframe>':""}<form method="POST" action="${F(t.action)}" target="${r}">${o}</form><script>document.forms[0].submit();</script></body></html>`};var ze="0.1.25";
2
+ exports.ArcPay=se;exports.ArcPayError=i;exports.Elements=f;exports.SDK_VERSION=ze;exports.buildThreeDSAutoSubmitHtml=L;exports.buildThreeDSBrowserForm=b;exports.buildThreeDSBrowserStep=C;exports.buildThreeDSMethodCompletion=I;exports.collectBrowserInfo=R;exports.getThreeDSAction=v;exports.isApiError=K;exports.isAuthenticationError=N;exports.isAuthorizationError=U;exports.isChallengeAborted=V;exports.isNetworkError=q;exports.isRateLimitError=$;exports.isStateError=W;exports.isThreeDSChallengeAction=_;exports.isThreeDSMethodAction=E;exports.isValidationError=O;exports.mountThreeDSBrowserForm=g;exports.runThreeDSBrowserFlow=H;return exports;})({});//# sourceMappingURL=arcpay.global.js.map
3
3
  //# sourceMappingURL=arcpay.global.js.map