@privateav/sdk 3.4.9 → 3.4.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # PrivateAV SDK v3.4.9
1
+ # PrivateAV SDK v3.4.11
2
2
 
3
3
  A lightweight SDK for integrating PrivateAV age verification into your website or application.
4
4
 
@@ -14,6 +14,9 @@ A lightweight SDK for integrating PrivateAV age verification into your website o
14
14
 
15
15
  ## Changelog
16
16
 
17
+ ### 3.4.11
18
+ - Fixed CDN documentation URLs (files are at package root, not `/dist/`)
19
+
17
20
  ### 3.4.9
18
21
  - Prevents `onCancel` from firing after a successful new-tab verification when the popup closes.
19
22
 
@@ -26,7 +29,7 @@ npm install @privateav/sdk
26
29
  Or load directly from jsDelivr CDN (no bundler required):
27
30
 
28
31
  ```html
29
- <script src="https://cdn.jsdelivr.net/npm/@privateav/sdk@latest/dist/privateav.min.js"></script>
32
+ <script src="https://cdn.jsdelivr.net/npm/@privateav/sdk@latest/privateav.min.js"></script>
30
33
  ```
31
34
 
32
35
  ## Quick Start
@@ -48,7 +51,7 @@ await sp.verify();
48
51
  ### With CDN (no bundler)
49
52
 
50
53
  ```html
51
- <script src="https://cdn.jsdelivr.net/npm/@privateav/sdk@latest/dist/privateav.min.js"></script>
54
+ <script src="https://cdn.jsdelivr.net/npm/@privateav/sdk@latest/privateav.min.js"></script>
52
55
  <script>
53
56
  const sp = new PrivateAV({
54
57
  apiKey: 'pk_...',
@@ -200,7 +203,7 @@ For reliable verification tracking, configure webhooks in your dashboard:
200
203
  <html>
201
204
  <head>
202
205
  <title>Age Verification</title>
203
- <script src="https://cdn.jsdelivr.net/npm/@privateav/sdk@latest/dist/privateav.min.js"></script>
206
+ <script src="https://cdn.jsdelivr.net/npm/@privateav/sdk@latest/privateav.min.js"></script>
204
207
  </head>
205
208
  <body>
206
209
  <button id="verify-btn">Verify Your Age</button>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@privateav/sdk",
3
- "version": "3.4.9",
3
+ "version": "3.4.11",
4
4
  "description": "PrivateAV SDK - Lightweight redirect-based age verification",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/privateav.min.js CHANGED
@@ -1,3 +1,3 @@
1
- /* PrivateAV SDK v3.4.9 */
1
+ /* PrivateAV SDK v3.4.11 */
2
2
  "use strict";var PrivateAVSDK=(()=>{var y=Object.defineProperty,dt=Object.defineProperties,pt=Object.getOwnPropertyDescriptor,gt=Object.getOwnPropertyDescriptors,ut=Object.getOwnPropertyNames,v=Object.getOwnPropertySymbols;var T=Object.prototype.hasOwnProperty,W=Object.prototype.propertyIsEnumerable;var B=(n,t,e)=>t in n?y(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e,u=(n,t)=>{for(var e in t||(t={}))T.call(t,e)&&B(n,e,t[e]);if(v)for(var e of v(t))W.call(t,e)&&B(n,e,t[e]);return n},S=(n,t)=>dt(n,gt(t));var H=(n,t)=>{var e={};for(var r in n)T.call(n,r)&&t.indexOf(r)<0&&(e[r]=n[r]);if(n!=null&&v)for(var r of v(n))t.indexOf(r)<0&&W.call(n,r)&&(e[r]=n[r]);return e};var A=(n,t)=>()=>(n&&(t=n(n=0)),t);var F=(n,t)=>{for(var e in t)y(n,e,{get:t[e],enumerable:!0})},ft=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ut(t))!T.call(n,i)&&i!==e&&y(n,i,{get:()=>t[i],enumerable:!(r=pt(t,i))||r.enumerable});return n};var ht=n=>ft(y({},"__esModule",{value:!0}),n);function mt(n,t){return t.includes(n)}function G(n,t,e=[],r="SDK"){var o;let{origin:i}=n;return mt(i,t)||e.length>0&&e.some(a=>{if(a.startsWith("*.")){let l=a.slice(2);return i.endsWith(`.${l}`)||i===`https://${l}`||i===`http://${l}`}return i===a})?!0:(console.warn(`${r} Security: Blocked PostMessage from untrusted origin: ${i}`,{trustedOrigins:t,allowedCustomOrigins:e,eventType:(o=n.data)==null?void 0:o.type}),!1)}function J(n,t,e,r){let{data:i}=n;return!i||typeof i!="object"?{isValid:!1,error:"Invalid message format"}:(r?[e,r]:[e]).includes(i.type)?!i.sessionId||i.sessionId!==t?{isValid:!1,error:"Session ID mismatch"}:!i.status||!["verified","failed","cancelled"].includes(i.status)?{isValid:!1,error:"Invalid status value"}:{isValid:!0}:{isValid:!1,error:"Invalid message type"}}function X(n,t="SDK"){n==="production"&&window.location.protocol!=="https:"&&console.warn(`${t} Warning: HTTPS recommended for production environment`,{current:window.location.href})}function x(n,t,e="SDK"){try{let r=new URL(n);if(r.protocol!=="https:"&&!(r.hostname==="localhost"||r.hostname==="127.0.0.1"))return{isValid:!1,error:`HTTPS required for return URLs in ${t}`};let i=[/data:/i,/javascript:/i,/vbscript:/i,/file:/i,/ftp:/i];for(let o of i)if(o.test(n))return{isValid:!1,error:"Blocked suspicious URL scheme"};return{isValid:!0}}catch(r){return{isValid:!1,error:"Invalid URL format"}}}function p(n,t,e="SDK"){let r={timestamp:new Date().toISOString(),userAgent:typeof navigator!="undefined"?navigator.userAgent:"unknown",url:typeof window!="undefined"?window.location.href:"unknown"};console.warn(`${e} Security Event: ${n}`,u(u({},r),t))}var P,Y,R=A(()=>{"use strict";P=class{constructor(){this.attempts=new Map;this.maxAttempts=5;this.timeWindow=6e4}isAllowed(t,e="SDK"){let r=Date.now(),o=(this.attempts.get(t)||[]).filter(s=>r-s<this.timeWindow);return o.length>=this.maxAttempts?(console.warn(`${e} Security: Rate limit exceeded for ${t}`),!1):(o.push(r),this.attempts.set(t,o),!0)}reset(t){this.attempts.delete(t)}},Y=new P});var Q={};F(Q,{createSignedState:()=>vt,generateHMAC:()=>V,generateSecureToken:()=>Z,parseSignedState:()=>yt,verifyHMAC:()=>z});async function V(n,t){let e=new TextEncoder,r=e.encode(t),i=e.encode(n),o=await crypto.subtle.importKey("raw",r,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",o,i);return Array.from(new Uint8Array(s)).map(a=>a.toString(16).padStart(2,"0")).join("")}async function z(n,t,e){try{let r=await V(n,e);return wt(t,r)}catch(r){return!1}}function wt(n,t){if(n.length!==t.length)return!1;let e=0;for(let r=0;r<n.length;r++)e|=n.charCodeAt(r)^t.charCodeAt(r);return e===0}function Z(n=32){let t=new Uint8Array(n);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}async function vt(n,t){let e=S(u({},n),{timestamp:Date.now(),nonce:Z(16)}),r=JSON.stringify(e),i=await V(r,t);return btoa(JSON.stringify({data:e,signature:i}))}async function yt(n,t,e=et,r="SDK"){try{let o=atob(n),s=JSON.parse(o);if(!s.data||!s.signature)return console.warn(`${r}: Invalid signed state format`),null;let{data:a,signature:l}=s,d=JSON.stringify(a);if(!await z(d,l,t))return console.warn(`${r}: State signature verification failed`),null;if(a.timestamp){let h=Date.now()-a.timestamp;if(h>e)return console.warn(`${r}: State parameter expired`,{age:h,maxAge:e}),null}let i=a,{timestamp:g,nonce:f}=i;return H(i,["timestamp","nonce"])}catch(o){return console.warn(`${r}: Failed to parse signed state`,o),null}}var tt=A(()=>{"use strict";L()});function ot(n,t){if(!n.apiKey)throw new Error("apiKey is required");if(n.apiKey.length>it)throw new Error(`apiKey exceeds maximum length of ${it} characters`);if(!St.test(n.apiKey))throw new Error("Invalid apiKey format. Expected pk_xxx (public) or sk_xxx (private)");if(typeof window!="undefined"&&n.apiKey.startsWith("sk_"))throw new Error(`Secret keys (sk_) should never be used in browser code for security reasons. Secret keys expose your account to unauthorized access if used client-side. Please use your public key (pk_) instead. If you need to use features that require a secret key (like custom challenge age), create the session server-side and pass the sessionId to startVerificationWithSession(). See: ${t.docsUrl}/server-side-sessions`);if(!n.returnUrl)throw new Error("returnUrl is required");if(n.returnUrl.length>U)throw new Error(`returnUrl exceeds maximum length of ${U} characters`);let e=Ut(),r=x(n.returnUrl,e,t.brandName);if(!r.isValid)throw new Error(`returnUrl validation failed: ${r.error}`);if(n.cancelUrl){if(n.cancelUrl.length>U)throw new Error(`cancelUrl exceeds maximum length of ${U} characters`);let i=x(n.cancelUrl,e,t.brandName);if(!i.isValid)throw new Error(`cancelUrl validation failed: ${i.error}`)}if(n.defaultChallengeAge!==void 0){if(n.defaultChallengeAge<nt)throw new Error(`defaultChallengeAge must be at least ${nt}`);if(n.defaultChallengeAge>rt)throw new Error(`defaultChallengeAge cannot exceed ${rt}`)}if(n.defaultVerificationMode&&!["L1","L2"].includes(n.defaultVerificationMode))throw new Error("defaultVerificationMode must be L1 or L2");if(n.mode&&!["redirect","new-tab"].includes(n.mode))throw new Error("mode must be redirect or new-tab");if(n.newTabTarget&&!["popup","tab"].includes(n.newTabTarget))throw new Error("newTabTarget must be popup or tab")}function Ut(){if(typeof window=="undefined")return"production";let n=window.location.hostname;return n.includes("staging")||n.includes("stage")?"staging":"production"}async function st(n,t,e,r="SDK"){let{createSignedState:i}=await Promise.resolve().then(()=>(tt(),Q));return i(n,e)}var nt,rt,U,it,et,St,L=A(()=>{"use strict";R();nt=25,rt=150,U=2048,it=128,et=6e5,St=/^(pk_|sk_)[a-zA-Z0-9_]+$/});var Ct={};F(Ct,{PrivateAV:()=>m,VERSION:()=>ct,default:()=>bt});function q(){crypto.randomUUID||(crypto.randomUUID=function(){let n=new Uint8Array(16);crypto.getRandomValues(n),n[6]=n[6]&15|64,n[8]=n[8]&63|128;let t=Array.from(n).map(e=>e.toString(16).padStart(2,"0")).join("");return[t.slice(0,8),t.slice(8,12),t.slice(12,16),t.slice(16,20),t.slice(20,32)].join("-")})}function j(n="SDK"){let t=[];if(!window.crypto||!window.crypto.getRandomValues)throw new Error(`${n} requires Web Crypto API support`);if(!window.crypto.subtle)throw new Error(`${n} requires Web Crypto subtle API for HMAC operations`);crypto.randomUUID||t.push("crypto.randomUUID not supported, using polyfill"),window.URLSearchParams||t.push("URLSearchParams not supported, consider adding a polyfill for IE 11 support"),t.length>0&&console.warn(`${n} Browser Compatibility:`,t.join("; "))}L();function E(n,t){let e=t.verifyUiUrl;if(!e||!e.startsWith("https://"))throw new Error(`HTTPS required for ${n} environment`);return e}function Et(n,t){let e=t.apiUrl;if(!e||!e.startsWith("https://"))throw new Error(`HTTPS required for API URLs in ${n} environment`);return e}function at(n,t,e="SDK"){let r=window.location.protocol==="https:";switch(n){case"production":r||console.warn(`${e} Warning: HTTPS recommended for production environment`);break;case"staging":r||console.warn(`${e} Warning: HTTPS strongly recommended in staging environment`);break}try{E(n,t),Et(n,t)}catch(i){let o=i instanceof Error?i.message:String(i);throw new Error(`Environment configuration validation failed: ${o}`)}}R();var C=class C{constructor(t,e,r){this.popupWindow=null;this.messageListener=null;this.popupMonitorInterval=null;this.unloadListener=null;this.isVerificationInProgress=!1;this.currentSessionId=null;this.hasReceivedResult=!1;this.lastVerifyUrl=null;this.lastSessionToken=null;this.lastExternalUserId=null;this.lastSandboxMode=null;this.temporaryHandoffToken=null;this.brandUrls=e,this.brandConstants=r,ot(t,{brandName:this.brandConstants.name,docsUrl:this.brandConstants.docsUrl});let i=t.environment||this.detectEnvironment();i!=="staging"&&i!=="production"&&(console.warn(`${this.brandConstants.name} SDK: Unknown environment '${i}', defaulting to 'production'`),i="production"),this.config=S(u({},t),{environment:i,mode:t.mode||"redirect",newTabTarget:t.newTabTarget||"popup"}),at(this.config.environment,this.getUrlConfig(),this.brandConstants.name),X(this.config.environment,this.brandConstants.name),p("SDK_INITIALIZED",{environment:this.config.environment,mode:this.config.mode,origin:window.location.origin,protocol:window.location.protocol,hostname:window.location.hostname},this.brandConstants.name),this.setupAutoCleanup()}async verify(t={}){var i,o,s,a,l,d;let e=this.isPublicKey(),r;if(e)r=await this.createInternalSession(t);else throw new Error("Private API keys (sk_) should use the direct API, not the SDK. The SDK is designed for browser-based public key usage only.");if(!r)throw new Error("Failed to obtain sessionId from server");if(this.isVerificationInProgress){let c=new Error(`Verification already in progress for session ${(i=this.currentSessionId)==null?void 0:i.substring(0,8)}...`);throw p("RACE_CONDITION_PREVENTED",{currentSession:((o=this.currentSessionId)==null?void 0:o.substring(0,8))+"...",attemptedSession:"new-session-attempt",origin:window.location.origin},this.brandConstants.name),(a=(s=this.config).onError)==null||a.call(s,c),c}this.isVerificationInProgress=!0,this.currentSessionId=r,this.lastExternalUserId=t.externalUserId||null;try{let c=`${this.config.apiKey}:${window.location.origin}`;if(!Y.isAllowed(c,this.brandConstants.name)){let f=new Error("Too many verification attempts. Please wait before trying again.");throw p("RATE_LIMIT_EXCEEDED",{apiKey:this.config.apiKey.substring(0,8)+"...",origin:window.location.origin,sessionId:r?r.substring(0,8)+"...":"undefined"},this.brandConstants.name),(d=(l=this.config).onError)==null||d.call(l,f),f}let g=await this.buildVerificationUrl(t,r);p("VERIFICATION_INITIATED",{environment:this.config.environment,mode:this.config.mode,sessionId:r?r.substring(0,8)+"...":"undefined",origin:window.location.origin},this.brandConstants.name),this.config.mode==="new-tab"?this.openNewTab(g,r):(this.unlockVerification(),this.redirect(g))}catch(c){throw this.unlockVerification(),c}}async buildVerificationUrl(t,e){var d;let r=this.config.verifyUrl||E(this.config.environment,this.getUrlConfig()),i=t.challengeAge!==void 0,o=t.verificationMode!==void 0,s=i||o,a=await st({merchantId:this.config.apiKey,sessionId:e,returnUrl:this.config.returnUrl,cancelUrl:this.config.cancelUrl,challengeAge:t.challengeAge||this.config.defaultChallengeAge,verificationMode:t.verificationMode||this.config.defaultVerificationMode,hasOverrides:s,externalUserId:t.externalUserId,timestamp:Date.now(),apiUrl:this.getPortalApiUrl(),engineUrl:this.getEngineUrl(),wsUrl:this.getWebSocketUrl(),environment:this.config.environment,features:{testMode:!1,warmupPeriodMs:500,qualityThreshold:.6,sandboxMode:(d=this.lastSandboxMode)!=null?d:!1},handoffToken:this.temporaryHandoffToken||void 0,sessionToken:this.lastSessionToken||void 0,verifyUrl:this.lastVerifyUrl||void 0},this.config.environment,this.getHmacSecret(),this.brandConstants.name);if(this.lastVerifyUrl)try{let c=this.applyLocalVerifyOverride(this.lastVerifyUrl),g=new URL(c);return g.searchParams.set("state",a),g.searchParams.set("mode",this.config.mode),t.skipIntro&&g.searchParams.set("skip_intro","true"),t.autoReturn&&g.searchParams.set("auto_return","true"),g.toString()}catch(c){}let l=new URLSearchParams({state:a,sessionId:e,mode:this.config.mode});return t.skipIntro&&l.set("skip_intro","true"),t.autoReturn&&l.set("auto_return","true"),`${r}/?${l.toString()}`}redirect(t){window.location.href=t}openNewTab(t,e){var l,d;if(this.cleanup(),this.hasReceivedResult=!1,this.popupMonitorInterval&&(clearInterval(this.popupMonitorInterval),this.popupMonitorInterval=null),(this.config.newTabTarget||"popup")==="tab"?this.popupWindow=window.open(t,"_blank"):this.popupWindow=window.open(t,this.brandConstants.popupName,"width=600,height=700"),!this.popupWindow){(d=(l=this.config).onError)==null||d.call(l,new Error("Failed to open verification window. Please check popup blocker settings."));return}let i=this.getTrustedOrigins(),o=this.getAllowedCustomOrigins(t),s=this.brandConstants.messageType,a=this.brandConstants.legacyMessageType;this.messageListener=c=>{var D,M,_,O,$,N,K;let g=(D=c.data)==null?void 0:D.type;if(!g||typeof g!="string"||!(a?[s,a]:[s]).includes(g))return;if(!G(c,i,o,this.brandConstants.name)){p("POSTMESSAGE_ORIGIN_BLOCKED",{origin:c.origin,environment:this.config.environment,expectedOrigins:`${this.brandConstants.name} trusted origins for ${this.config.environment}`,messageType:(M=c.data)==null?void 0:M.type},this.brandConstants.name);return}let I=J(c,e,s,a);if(!I.isValid){p("POSTMESSAGE_VALIDATION_FAILED",{error:I.error,origin:c.origin,sessionId:e.substring(0,8)+"...",messageType:(_=c.data)==null?void 0:_.type},this.brandConstants.name);return}let h=c.data.status;if(h==="cancelled"){this.handleCancellation(e,"postmessage");return}let w={sessionId:c.data.sessionId,status:h,timestamp:c.data.timestamp,externalUserId:c.data.externalUserId};this.hasReceivedResult=!0,p("VERIFICATION_COMPLETED",{status:w.status,sessionId:e.substring(0,8)+"...",origin:c.origin},this.brandConstants.name),this.cleanup({closePopup:!1}),this.unlockVerification(),this.popupMonitorInterval&&(clearInterval(this.popupMonitorInterval),this.popupMonitorInterval=null),w.status==="verified"?($=(O=this.config).onComplete)==null||$.call(O,w):(K=(N=this.config).onError)==null||K.call(N,new Error(`Verification failed: ${w.status}`))},window.addEventListener("message",this.messageListener),this.popupMonitorInterval=setInterval(()=>{this.popupWindow&&this.popupWindow.closed&&(p("POPUP_CLOSED_BY_USER",{sessionId:e.substring(0,8)+"...",environment:this.config.environment},this.brandConstants.name),this.hasReceivedResult||this.handleCancellation(e,"popup-closed"))},500)}setupAutoCleanup(){if(this.unloadListener=()=>{p("SDK_AUTO_CLEANUP",{environment:this.config.environment,trigger:"page_unload"},this.brandConstants.name),this.cleanup(),this.unlockVerification()},window.addEventListener("beforeunload",this.unloadListener),window.addEventListener("pagehide",this.unloadListener),window.history&&window.history.pushState){let t=window.history.pushState;window.history.pushState=(...e)=>(this.cleanup(),this.unlockVerification(),t.apply(window.history,e))}}detectEnvironment(){let t=window.location.hostname;return t.includes("staging")||t.includes("stage")?"staging":"production"}getEnvironment(){return this.config.environment}unlockVerification(){this.isVerificationInProgress=!1,this.currentSessionId=null,p("VERIFICATION_UNLOCKED",{environment:this.config.environment,origin:window.location.origin},this.brandConstants.name)}cleanup(t={}){let e=t.closePopup!==!1;this.popupWindow&&(e&&!this.popupWindow.closed&&this.popupWindow.close(),(e||this.popupWindow.closed)&&(this.popupWindow=null)),this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.popupMonitorInterval&&(clearInterval(this.popupMonitorInterval),this.popupMonitorInterval=null)}handleCancellation(t,e){if(this.hasReceivedResult)return;this.hasReceivedResult=!0,p("VERIFICATION_CANCELLED",{source:e,sessionId:t.substring(0,8)+"...",environment:this.config.environment,origin:window.location.origin},this.brandConstants.name),this.cleanup(),this.unlockVerification();let r=!0;if(this.config.onCancel)try{this.config.onCancel()===!1&&(r=!1)}catch(i){p("CANCEL_CALLBACK_FAILED",{error:i instanceof Error?i.message:String(i),sessionId:t.substring(0,8)+"..."},this.brandConstants.name)}r&&this.redirectToCancelUrl(t)}redirectToCancelUrl(t){if(this.config.cancelUrl)try{let e=decodeURIComponent(this.config.cancelUrl),r=new URL(e);r.searchParams.set("sessionId",t),r.searchParams.set("status","cancelled"),r.searchParams.set("timestamp",Date.now().toString()),this.lastExternalUserId&&r.searchParams.set("externalUserId",this.lastExternalUserId),window.location.href=r.toString()}catch(e){p("CANCEL_REDIRECT_FAILED",{error:e instanceof Error?e.message:String(e),sessionId:t.substring(0,8)+"..."},this.brandConstants.name)}}removeAutoCleanupListeners(){this.unloadListener&&(window.removeEventListener("beforeunload",this.unloadListener),window.removeEventListener("pagehide",this.unloadListener),this.unloadListener=null)}destroy(){p("SDK_DESTROYED",{environment:this.config.environment,origin:window.location.origin},this.brandConstants.name),this.cleanup(),this.unlockVerification(),this.removeAutoCleanupListeners()}getPortalApiUrl(){return this.config.apiUrl?this.config.apiUrl:this.getUrlConfig().apiUrl}getEngineUrl(){return this.getUrlConfig().engineUrl}getWebSocketUrl(){return this.getUrlConfig().wsUrl}isPublicKey(){return this.config.apiKey.startsWith("pk_")}async createInternalSession(t){var e,r;try{let i=this.getPortalApiUrl(),o=await fetch(`${i}/api/v1/sessions/create`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({merchantId:this.config.apiKey,returnUrl:this.config.returnUrl,cancelUrl:this.config.cancelUrl,challengeAge:t.challengeAge,verificationMode:t.verificationMode,merchantName:document.title||window.location.hostname,externalUserId:t.externalUserId})});if(!o.ok){let l=await o.json().catch(()=>({})),d=l==null?void 0:l.code;throw this.isBillingBlockError(d)&&this.openBillingBlockPage(d,l==null?void 0:l.portalUrl),new Error(`Failed to create session: ${o.status} ${o.statusText}. ${l.message||""}`)}let s=await o.json(),a=s.sessionId;if(!a)throw new Error("Server did not return a sessionId");return s.verifyUrl&&(this.lastVerifyUrl=s.verifyUrl),s.sessionToken&&(this.lastSessionToken=s.sessionToken),s.handoffToken&&(this.temporaryHandoffToken=s.handoffToken),typeof s.sandboxMode=="boolean"?this.lastSandboxMode=s.sandboxMode:this.lastSandboxMode=null,p("INTERNAL_SESSION_CREATED",{sessionId:a.substring(0,8)+"...",environment:this.config.environment,apiKeyType:"public"},this.brandConstants.name),a}catch(i){let o=i instanceof Error?i.message:String(i);throw p("INTERNAL_SESSION_FAILED",{error:o,environment:this.config.environment,apiKeyType:"public"},this.brandConstants.name),(r=(e=this.config).onError)==null||r.call(e,i),new Error(`Failed to create verification session: ${o}`)}}isBillingBlockError(t){return t==="SUBSCRIPTION_REQUIRED"||t==="PLAN_LIMIT_REACHED"||t==="SANDBOX_LIMIT_REACHED"}openBillingBlockPage(t,e){var r,i,o,s;try{let a=this.config.verifyUrl||E(this.config.environment,this.getUrlConfig()),l=this.applyLocalVerifyOverride(a),d=new URL(l);if(d.searchParams.set("blocked",t),e&&d.searchParams.set("portalUrl",e),this.config.mode==="new-tab"){((this.config.newTabTarget||"popup")==="tab"?window.open(d.toString(),"_blank"):window.open(d.toString(),this.brandConstants.popupName,"width=600,height=700"))||(i=(r=this.config).onError)==null||i.call(r,new Error("Failed to open billing notice window. Please check popup blocker settings."));return}this.redirect(d.toString())}catch(a){let l=a instanceof Error?a.message:String(a);(s=(o=this.config).onError)==null||s.call(o,new Error(`Failed to open billing notice: ${l}`))}}getUrlConfig(){return this.brandUrls[this.config.environment]||this.brandUrls.production}getTrustedOrigins(){return this.getUrlConfig().trustedOrigins}getAllowedCustomOrigins(t){let e=new Set,r=this.getLocalOrigin(this.config.verifyUrl||null),i=this.getLocalOrigin(t||null);return r&&e.add(r),i&&e.add(i),Array.from(e)}getLocalOrigin(t){if(!t)return null;try{let e=new URL(t);if(C.LOCAL_HOSTNAMES.has(e.hostname))return e.origin}catch(e){return null}return null}applyLocalVerifyOverride(t){let e=this.getLocalOrigin(this.config.verifyUrl||null);if(!e)return t;try{let r=new URL(e),i=new URL(t);return i.protocol=r.protocol,i.host=r.host,i.toString()}catch(r){return t}}getHmacSecret(){return this.config.environment==="staging"?this.brandConstants.hmacSecretStaging:this.brandConstants.hmacSecretProd}};C.LOCAL_HOSTNAMES=new Set(["localhost","127.0.0.1","::1"]);var b=C;var lt={production:{apiUrl:"https://api.privateav.com",verifyUiUrl:"https://verify.privateav.com",engineUrl:"https://engine.privateav.com",wsUrl:"wss://engine.privateav.com/api/websocket/stream",trustedOrigins:["https://verify.privateav.com","https://portal.privateav.com","https://api.privateav.com"]},staging:{apiUrl:"https://api.staging.privateav.com",verifyUiUrl:"https://verify.staging.privateav.com",engineUrl:"https://engine.staging.privateav.com",wsUrl:"wss://engine.staging.privateav.com/api/websocket/stream",trustedOrigins:["https://verify.staging.privateav.com","https://portal.staging.privateav.com","https://api.staging.privateav.com"]}},k={name:"PrivateAV",hmacSecretProd:"privateav-prod-hmac-2025",hmacSecretStaging:"privateav-stage-hmac-2025",messageType:"privateav:verification:complete",legacyMessageType:"privateav-verification",popupName:"privateav-verify",docsUrl:"https://docs.privateav.com"};var m=class extends b{constructor(t){super(t,lt,k)}},ct="3.4.9";m.VERSION=ct;typeof window!="undefined"&&(q(),j(`${k.name} SDK`));var bt=m;return ht(Ct);})();
3
3
  if(typeof PrivateAVSDK !== "undefined" && PrivateAVSDK.PrivateAV) { window.PrivateAV = PrivateAVSDK.PrivateAV; window.PrivateAV.VERSION = PrivateAVSDK.VERSION; }
package/sdk.min.js CHANGED
@@ -1,3 +1,3 @@
1
- /* PrivateAV SDK v3.4.9 */
1
+ /* PrivateAV SDK v3.4.11 */
2
2
  "use strict";var PrivateAVSDK=(()=>{var y=Object.defineProperty,dt=Object.defineProperties,pt=Object.getOwnPropertyDescriptor,gt=Object.getOwnPropertyDescriptors,ut=Object.getOwnPropertyNames,v=Object.getOwnPropertySymbols;var T=Object.prototype.hasOwnProperty,W=Object.prototype.propertyIsEnumerable;var B=(n,t,e)=>t in n?y(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e,u=(n,t)=>{for(var e in t||(t={}))T.call(t,e)&&B(n,e,t[e]);if(v)for(var e of v(t))W.call(t,e)&&B(n,e,t[e]);return n},S=(n,t)=>dt(n,gt(t));var H=(n,t)=>{var e={};for(var r in n)T.call(n,r)&&t.indexOf(r)<0&&(e[r]=n[r]);if(n!=null&&v)for(var r of v(n))t.indexOf(r)<0&&W.call(n,r)&&(e[r]=n[r]);return e};var A=(n,t)=>()=>(n&&(t=n(n=0)),t);var F=(n,t)=>{for(var e in t)y(n,e,{get:t[e],enumerable:!0})},ft=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ut(t))!T.call(n,i)&&i!==e&&y(n,i,{get:()=>t[i],enumerable:!(r=pt(t,i))||r.enumerable});return n};var ht=n=>ft(y({},"__esModule",{value:!0}),n);function mt(n,t){return t.includes(n)}function G(n,t,e=[],r="SDK"){var o;let{origin:i}=n;return mt(i,t)||e.length>0&&e.some(a=>{if(a.startsWith("*.")){let l=a.slice(2);return i.endsWith(`.${l}`)||i===`https://${l}`||i===`http://${l}`}return i===a})?!0:(console.warn(`${r} Security: Blocked PostMessage from untrusted origin: ${i}`,{trustedOrigins:t,allowedCustomOrigins:e,eventType:(o=n.data)==null?void 0:o.type}),!1)}function J(n,t,e,r){let{data:i}=n;return!i||typeof i!="object"?{isValid:!1,error:"Invalid message format"}:(r?[e,r]:[e]).includes(i.type)?!i.sessionId||i.sessionId!==t?{isValid:!1,error:"Session ID mismatch"}:!i.status||!["verified","failed","cancelled"].includes(i.status)?{isValid:!1,error:"Invalid status value"}:{isValid:!0}:{isValid:!1,error:"Invalid message type"}}function X(n,t="SDK"){n==="production"&&window.location.protocol!=="https:"&&console.warn(`${t} Warning: HTTPS recommended for production environment`,{current:window.location.href})}function x(n,t,e="SDK"){try{let r=new URL(n);if(r.protocol!=="https:"&&!(r.hostname==="localhost"||r.hostname==="127.0.0.1"))return{isValid:!1,error:`HTTPS required for return URLs in ${t}`};let i=[/data:/i,/javascript:/i,/vbscript:/i,/file:/i,/ftp:/i];for(let o of i)if(o.test(n))return{isValid:!1,error:"Blocked suspicious URL scheme"};return{isValid:!0}}catch(r){return{isValid:!1,error:"Invalid URL format"}}}function p(n,t,e="SDK"){let r={timestamp:new Date().toISOString(),userAgent:typeof navigator!="undefined"?navigator.userAgent:"unknown",url:typeof window!="undefined"?window.location.href:"unknown"};console.warn(`${e} Security Event: ${n}`,u(u({},r),t))}var P,Y,R=A(()=>{"use strict";P=class{constructor(){this.attempts=new Map;this.maxAttempts=5;this.timeWindow=6e4}isAllowed(t,e="SDK"){let r=Date.now(),o=(this.attempts.get(t)||[]).filter(s=>r-s<this.timeWindow);return o.length>=this.maxAttempts?(console.warn(`${e} Security: Rate limit exceeded for ${t}`),!1):(o.push(r),this.attempts.set(t,o),!0)}reset(t){this.attempts.delete(t)}},Y=new P});var Q={};F(Q,{createSignedState:()=>vt,generateHMAC:()=>V,generateSecureToken:()=>Z,parseSignedState:()=>yt,verifyHMAC:()=>z});async function V(n,t){let e=new TextEncoder,r=e.encode(t),i=e.encode(n),o=await crypto.subtle.importKey("raw",r,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",o,i);return Array.from(new Uint8Array(s)).map(a=>a.toString(16).padStart(2,"0")).join("")}async function z(n,t,e){try{let r=await V(n,e);return wt(t,r)}catch(r){return!1}}function wt(n,t){if(n.length!==t.length)return!1;let e=0;for(let r=0;r<n.length;r++)e|=n.charCodeAt(r)^t.charCodeAt(r);return e===0}function Z(n=32){let t=new Uint8Array(n);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}async function vt(n,t){let e=S(u({},n),{timestamp:Date.now(),nonce:Z(16)}),r=JSON.stringify(e),i=await V(r,t);return btoa(JSON.stringify({data:e,signature:i}))}async function yt(n,t,e=et,r="SDK"){try{let o=atob(n),s=JSON.parse(o);if(!s.data||!s.signature)return console.warn(`${r}: Invalid signed state format`),null;let{data:a,signature:l}=s,d=JSON.stringify(a);if(!await z(d,l,t))return console.warn(`${r}: State signature verification failed`),null;if(a.timestamp){let h=Date.now()-a.timestamp;if(h>e)return console.warn(`${r}: State parameter expired`,{age:h,maxAge:e}),null}let i=a,{timestamp:g,nonce:f}=i;return H(i,["timestamp","nonce"])}catch(o){return console.warn(`${r}: Failed to parse signed state`,o),null}}var tt=A(()=>{"use strict";L()});function ot(n,t){if(!n.apiKey)throw new Error("apiKey is required");if(n.apiKey.length>it)throw new Error(`apiKey exceeds maximum length of ${it} characters`);if(!St.test(n.apiKey))throw new Error("Invalid apiKey format. Expected pk_xxx (public) or sk_xxx (private)");if(typeof window!="undefined"&&n.apiKey.startsWith("sk_"))throw new Error(`Secret keys (sk_) should never be used in browser code for security reasons. Secret keys expose your account to unauthorized access if used client-side. Please use your public key (pk_) instead. If you need to use features that require a secret key (like custom challenge age), create the session server-side and pass the sessionId to startVerificationWithSession(). See: ${t.docsUrl}/server-side-sessions`);if(!n.returnUrl)throw new Error("returnUrl is required");if(n.returnUrl.length>U)throw new Error(`returnUrl exceeds maximum length of ${U} characters`);let e=Ut(),r=x(n.returnUrl,e,t.brandName);if(!r.isValid)throw new Error(`returnUrl validation failed: ${r.error}`);if(n.cancelUrl){if(n.cancelUrl.length>U)throw new Error(`cancelUrl exceeds maximum length of ${U} characters`);let i=x(n.cancelUrl,e,t.brandName);if(!i.isValid)throw new Error(`cancelUrl validation failed: ${i.error}`)}if(n.defaultChallengeAge!==void 0){if(n.defaultChallengeAge<nt)throw new Error(`defaultChallengeAge must be at least ${nt}`);if(n.defaultChallengeAge>rt)throw new Error(`defaultChallengeAge cannot exceed ${rt}`)}if(n.defaultVerificationMode&&!["L1","L2"].includes(n.defaultVerificationMode))throw new Error("defaultVerificationMode must be L1 or L2");if(n.mode&&!["redirect","new-tab"].includes(n.mode))throw new Error("mode must be redirect or new-tab");if(n.newTabTarget&&!["popup","tab"].includes(n.newTabTarget))throw new Error("newTabTarget must be popup or tab")}function Ut(){if(typeof window=="undefined")return"production";let n=window.location.hostname;return n.includes("staging")||n.includes("stage")?"staging":"production"}async function st(n,t,e,r="SDK"){let{createSignedState:i}=await Promise.resolve().then(()=>(tt(),Q));return i(n,e)}var nt,rt,U,it,et,St,L=A(()=>{"use strict";R();nt=25,rt=150,U=2048,it=128,et=6e5,St=/^(pk_|sk_)[a-zA-Z0-9_]+$/});var Ct={};F(Ct,{PrivateAV:()=>m,VERSION:()=>ct,default:()=>bt});function q(){crypto.randomUUID||(crypto.randomUUID=function(){let n=new Uint8Array(16);crypto.getRandomValues(n),n[6]=n[6]&15|64,n[8]=n[8]&63|128;let t=Array.from(n).map(e=>e.toString(16).padStart(2,"0")).join("");return[t.slice(0,8),t.slice(8,12),t.slice(12,16),t.slice(16,20),t.slice(20,32)].join("-")})}function j(n="SDK"){let t=[];if(!window.crypto||!window.crypto.getRandomValues)throw new Error(`${n} requires Web Crypto API support`);if(!window.crypto.subtle)throw new Error(`${n} requires Web Crypto subtle API for HMAC operations`);crypto.randomUUID||t.push("crypto.randomUUID not supported, using polyfill"),window.URLSearchParams||t.push("URLSearchParams not supported, consider adding a polyfill for IE 11 support"),t.length>0&&console.warn(`${n} Browser Compatibility:`,t.join("; "))}L();function E(n,t){let e=t.verifyUiUrl;if(!e||!e.startsWith("https://"))throw new Error(`HTTPS required for ${n} environment`);return e}function Et(n,t){let e=t.apiUrl;if(!e||!e.startsWith("https://"))throw new Error(`HTTPS required for API URLs in ${n} environment`);return e}function at(n,t,e="SDK"){let r=window.location.protocol==="https:";switch(n){case"production":r||console.warn(`${e} Warning: HTTPS recommended for production environment`);break;case"staging":r||console.warn(`${e} Warning: HTTPS strongly recommended in staging environment`);break}try{E(n,t),Et(n,t)}catch(i){let o=i instanceof Error?i.message:String(i);throw new Error(`Environment configuration validation failed: ${o}`)}}R();var C=class C{constructor(t,e,r){this.popupWindow=null;this.messageListener=null;this.popupMonitorInterval=null;this.unloadListener=null;this.isVerificationInProgress=!1;this.currentSessionId=null;this.hasReceivedResult=!1;this.lastVerifyUrl=null;this.lastSessionToken=null;this.lastExternalUserId=null;this.lastSandboxMode=null;this.temporaryHandoffToken=null;this.brandUrls=e,this.brandConstants=r,ot(t,{brandName:this.brandConstants.name,docsUrl:this.brandConstants.docsUrl});let i=t.environment||this.detectEnvironment();i!=="staging"&&i!=="production"&&(console.warn(`${this.brandConstants.name} SDK: Unknown environment '${i}', defaulting to 'production'`),i="production"),this.config=S(u({},t),{environment:i,mode:t.mode||"redirect",newTabTarget:t.newTabTarget||"popup"}),at(this.config.environment,this.getUrlConfig(),this.brandConstants.name),X(this.config.environment,this.brandConstants.name),p("SDK_INITIALIZED",{environment:this.config.environment,mode:this.config.mode,origin:window.location.origin,protocol:window.location.protocol,hostname:window.location.hostname},this.brandConstants.name),this.setupAutoCleanup()}async verify(t={}){var i,o,s,a,l,d;let e=this.isPublicKey(),r;if(e)r=await this.createInternalSession(t);else throw new Error("Private API keys (sk_) should use the direct API, not the SDK. The SDK is designed for browser-based public key usage only.");if(!r)throw new Error("Failed to obtain sessionId from server");if(this.isVerificationInProgress){let c=new Error(`Verification already in progress for session ${(i=this.currentSessionId)==null?void 0:i.substring(0,8)}...`);throw p("RACE_CONDITION_PREVENTED",{currentSession:((o=this.currentSessionId)==null?void 0:o.substring(0,8))+"...",attemptedSession:"new-session-attempt",origin:window.location.origin},this.brandConstants.name),(a=(s=this.config).onError)==null||a.call(s,c),c}this.isVerificationInProgress=!0,this.currentSessionId=r,this.lastExternalUserId=t.externalUserId||null;try{let c=`${this.config.apiKey}:${window.location.origin}`;if(!Y.isAllowed(c,this.brandConstants.name)){let f=new Error("Too many verification attempts. Please wait before trying again.");throw p("RATE_LIMIT_EXCEEDED",{apiKey:this.config.apiKey.substring(0,8)+"...",origin:window.location.origin,sessionId:r?r.substring(0,8)+"...":"undefined"},this.brandConstants.name),(d=(l=this.config).onError)==null||d.call(l,f),f}let g=await this.buildVerificationUrl(t,r);p("VERIFICATION_INITIATED",{environment:this.config.environment,mode:this.config.mode,sessionId:r?r.substring(0,8)+"...":"undefined",origin:window.location.origin},this.brandConstants.name),this.config.mode==="new-tab"?this.openNewTab(g,r):(this.unlockVerification(),this.redirect(g))}catch(c){throw this.unlockVerification(),c}}async buildVerificationUrl(t,e){var d;let r=this.config.verifyUrl||E(this.config.environment,this.getUrlConfig()),i=t.challengeAge!==void 0,o=t.verificationMode!==void 0,s=i||o,a=await st({merchantId:this.config.apiKey,sessionId:e,returnUrl:this.config.returnUrl,cancelUrl:this.config.cancelUrl,challengeAge:t.challengeAge||this.config.defaultChallengeAge,verificationMode:t.verificationMode||this.config.defaultVerificationMode,hasOverrides:s,externalUserId:t.externalUserId,timestamp:Date.now(),apiUrl:this.getPortalApiUrl(),engineUrl:this.getEngineUrl(),wsUrl:this.getWebSocketUrl(),environment:this.config.environment,features:{testMode:!1,warmupPeriodMs:500,qualityThreshold:.6,sandboxMode:(d=this.lastSandboxMode)!=null?d:!1},handoffToken:this.temporaryHandoffToken||void 0,sessionToken:this.lastSessionToken||void 0,verifyUrl:this.lastVerifyUrl||void 0},this.config.environment,this.getHmacSecret(),this.brandConstants.name);if(this.lastVerifyUrl)try{let c=this.applyLocalVerifyOverride(this.lastVerifyUrl),g=new URL(c);return g.searchParams.set("state",a),g.searchParams.set("mode",this.config.mode),t.skipIntro&&g.searchParams.set("skip_intro","true"),t.autoReturn&&g.searchParams.set("auto_return","true"),g.toString()}catch(c){}let l=new URLSearchParams({state:a,sessionId:e,mode:this.config.mode});return t.skipIntro&&l.set("skip_intro","true"),t.autoReturn&&l.set("auto_return","true"),`${r}/?${l.toString()}`}redirect(t){window.location.href=t}openNewTab(t,e){var l,d;if(this.cleanup(),this.hasReceivedResult=!1,this.popupMonitorInterval&&(clearInterval(this.popupMonitorInterval),this.popupMonitorInterval=null),(this.config.newTabTarget||"popup")==="tab"?this.popupWindow=window.open(t,"_blank"):this.popupWindow=window.open(t,this.brandConstants.popupName,"width=600,height=700"),!this.popupWindow){(d=(l=this.config).onError)==null||d.call(l,new Error("Failed to open verification window. Please check popup blocker settings."));return}let i=this.getTrustedOrigins(),o=this.getAllowedCustomOrigins(t),s=this.brandConstants.messageType,a=this.brandConstants.legacyMessageType;this.messageListener=c=>{var D,M,_,O,$,N,K;let g=(D=c.data)==null?void 0:D.type;if(!g||typeof g!="string"||!(a?[s,a]:[s]).includes(g))return;if(!G(c,i,o,this.brandConstants.name)){p("POSTMESSAGE_ORIGIN_BLOCKED",{origin:c.origin,environment:this.config.environment,expectedOrigins:`${this.brandConstants.name} trusted origins for ${this.config.environment}`,messageType:(M=c.data)==null?void 0:M.type},this.brandConstants.name);return}let I=J(c,e,s,a);if(!I.isValid){p("POSTMESSAGE_VALIDATION_FAILED",{error:I.error,origin:c.origin,sessionId:e.substring(0,8)+"...",messageType:(_=c.data)==null?void 0:_.type},this.brandConstants.name);return}let h=c.data.status;if(h==="cancelled"){this.handleCancellation(e,"postmessage");return}let w={sessionId:c.data.sessionId,status:h,timestamp:c.data.timestamp,externalUserId:c.data.externalUserId};this.hasReceivedResult=!0,p("VERIFICATION_COMPLETED",{status:w.status,sessionId:e.substring(0,8)+"...",origin:c.origin},this.brandConstants.name),this.cleanup({closePopup:!1}),this.unlockVerification(),this.popupMonitorInterval&&(clearInterval(this.popupMonitorInterval),this.popupMonitorInterval=null),w.status==="verified"?($=(O=this.config).onComplete)==null||$.call(O,w):(K=(N=this.config).onError)==null||K.call(N,new Error(`Verification failed: ${w.status}`))},window.addEventListener("message",this.messageListener),this.popupMonitorInterval=setInterval(()=>{this.popupWindow&&this.popupWindow.closed&&(p("POPUP_CLOSED_BY_USER",{sessionId:e.substring(0,8)+"...",environment:this.config.environment},this.brandConstants.name),this.hasReceivedResult||this.handleCancellation(e,"popup-closed"))},500)}setupAutoCleanup(){if(this.unloadListener=()=>{p("SDK_AUTO_CLEANUP",{environment:this.config.environment,trigger:"page_unload"},this.brandConstants.name),this.cleanup(),this.unlockVerification()},window.addEventListener("beforeunload",this.unloadListener),window.addEventListener("pagehide",this.unloadListener),window.history&&window.history.pushState){let t=window.history.pushState;window.history.pushState=(...e)=>(this.cleanup(),this.unlockVerification(),t.apply(window.history,e))}}detectEnvironment(){let t=window.location.hostname;return t.includes("staging")||t.includes("stage")?"staging":"production"}getEnvironment(){return this.config.environment}unlockVerification(){this.isVerificationInProgress=!1,this.currentSessionId=null,p("VERIFICATION_UNLOCKED",{environment:this.config.environment,origin:window.location.origin},this.brandConstants.name)}cleanup(t={}){let e=t.closePopup!==!1;this.popupWindow&&(e&&!this.popupWindow.closed&&this.popupWindow.close(),(e||this.popupWindow.closed)&&(this.popupWindow=null)),this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.popupMonitorInterval&&(clearInterval(this.popupMonitorInterval),this.popupMonitorInterval=null)}handleCancellation(t,e){if(this.hasReceivedResult)return;this.hasReceivedResult=!0,p("VERIFICATION_CANCELLED",{source:e,sessionId:t.substring(0,8)+"...",environment:this.config.environment,origin:window.location.origin},this.brandConstants.name),this.cleanup(),this.unlockVerification();let r=!0;if(this.config.onCancel)try{this.config.onCancel()===!1&&(r=!1)}catch(i){p("CANCEL_CALLBACK_FAILED",{error:i instanceof Error?i.message:String(i),sessionId:t.substring(0,8)+"..."},this.brandConstants.name)}r&&this.redirectToCancelUrl(t)}redirectToCancelUrl(t){if(this.config.cancelUrl)try{let e=decodeURIComponent(this.config.cancelUrl),r=new URL(e);r.searchParams.set("sessionId",t),r.searchParams.set("status","cancelled"),r.searchParams.set("timestamp",Date.now().toString()),this.lastExternalUserId&&r.searchParams.set("externalUserId",this.lastExternalUserId),window.location.href=r.toString()}catch(e){p("CANCEL_REDIRECT_FAILED",{error:e instanceof Error?e.message:String(e),sessionId:t.substring(0,8)+"..."},this.brandConstants.name)}}removeAutoCleanupListeners(){this.unloadListener&&(window.removeEventListener("beforeunload",this.unloadListener),window.removeEventListener("pagehide",this.unloadListener),this.unloadListener=null)}destroy(){p("SDK_DESTROYED",{environment:this.config.environment,origin:window.location.origin},this.brandConstants.name),this.cleanup(),this.unlockVerification(),this.removeAutoCleanupListeners()}getPortalApiUrl(){return this.config.apiUrl?this.config.apiUrl:this.getUrlConfig().apiUrl}getEngineUrl(){return this.getUrlConfig().engineUrl}getWebSocketUrl(){return this.getUrlConfig().wsUrl}isPublicKey(){return this.config.apiKey.startsWith("pk_")}async createInternalSession(t){var e,r;try{let i=this.getPortalApiUrl(),o=await fetch(`${i}/api/v1/sessions/create`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({merchantId:this.config.apiKey,returnUrl:this.config.returnUrl,cancelUrl:this.config.cancelUrl,challengeAge:t.challengeAge,verificationMode:t.verificationMode,merchantName:document.title||window.location.hostname,externalUserId:t.externalUserId})});if(!o.ok){let l=await o.json().catch(()=>({})),d=l==null?void 0:l.code;throw this.isBillingBlockError(d)&&this.openBillingBlockPage(d,l==null?void 0:l.portalUrl),new Error(`Failed to create session: ${o.status} ${o.statusText}. ${l.message||""}`)}let s=await o.json(),a=s.sessionId;if(!a)throw new Error("Server did not return a sessionId");return s.verifyUrl&&(this.lastVerifyUrl=s.verifyUrl),s.sessionToken&&(this.lastSessionToken=s.sessionToken),s.handoffToken&&(this.temporaryHandoffToken=s.handoffToken),typeof s.sandboxMode=="boolean"?this.lastSandboxMode=s.sandboxMode:this.lastSandboxMode=null,p("INTERNAL_SESSION_CREATED",{sessionId:a.substring(0,8)+"...",environment:this.config.environment,apiKeyType:"public"},this.brandConstants.name),a}catch(i){let o=i instanceof Error?i.message:String(i);throw p("INTERNAL_SESSION_FAILED",{error:o,environment:this.config.environment,apiKeyType:"public"},this.brandConstants.name),(r=(e=this.config).onError)==null||r.call(e,i),new Error(`Failed to create verification session: ${o}`)}}isBillingBlockError(t){return t==="SUBSCRIPTION_REQUIRED"||t==="PLAN_LIMIT_REACHED"||t==="SANDBOX_LIMIT_REACHED"}openBillingBlockPage(t,e){var r,i,o,s;try{let a=this.config.verifyUrl||E(this.config.environment,this.getUrlConfig()),l=this.applyLocalVerifyOverride(a),d=new URL(l);if(d.searchParams.set("blocked",t),e&&d.searchParams.set("portalUrl",e),this.config.mode==="new-tab"){((this.config.newTabTarget||"popup")==="tab"?window.open(d.toString(),"_blank"):window.open(d.toString(),this.brandConstants.popupName,"width=600,height=700"))||(i=(r=this.config).onError)==null||i.call(r,new Error("Failed to open billing notice window. Please check popup blocker settings."));return}this.redirect(d.toString())}catch(a){let l=a instanceof Error?a.message:String(a);(s=(o=this.config).onError)==null||s.call(o,new Error(`Failed to open billing notice: ${l}`))}}getUrlConfig(){return this.brandUrls[this.config.environment]||this.brandUrls.production}getTrustedOrigins(){return this.getUrlConfig().trustedOrigins}getAllowedCustomOrigins(t){let e=new Set,r=this.getLocalOrigin(this.config.verifyUrl||null),i=this.getLocalOrigin(t||null);return r&&e.add(r),i&&e.add(i),Array.from(e)}getLocalOrigin(t){if(!t)return null;try{let e=new URL(t);if(C.LOCAL_HOSTNAMES.has(e.hostname))return e.origin}catch(e){return null}return null}applyLocalVerifyOverride(t){let e=this.getLocalOrigin(this.config.verifyUrl||null);if(!e)return t;try{let r=new URL(e),i=new URL(t);return i.protocol=r.protocol,i.host=r.host,i.toString()}catch(r){return t}}getHmacSecret(){return this.config.environment==="staging"?this.brandConstants.hmacSecretStaging:this.brandConstants.hmacSecretProd}};C.LOCAL_HOSTNAMES=new Set(["localhost","127.0.0.1","::1"]);var b=C;var lt={production:{apiUrl:"https://api.privateav.com",verifyUiUrl:"https://verify.privateav.com",engineUrl:"https://engine.privateav.com",wsUrl:"wss://engine.privateav.com/api/websocket/stream",trustedOrigins:["https://verify.privateav.com","https://portal.privateav.com","https://api.privateav.com"]},staging:{apiUrl:"https://api.staging.privateav.com",verifyUiUrl:"https://verify.staging.privateav.com",engineUrl:"https://engine.staging.privateav.com",wsUrl:"wss://engine.staging.privateav.com/api/websocket/stream",trustedOrigins:["https://verify.staging.privateav.com","https://portal.staging.privateav.com","https://api.staging.privateav.com"]}},k={name:"PrivateAV",hmacSecretProd:"privateav-prod-hmac-2025",hmacSecretStaging:"privateav-stage-hmac-2025",messageType:"privateav:verification:complete",legacyMessageType:"privateav-verification",popupName:"privateav-verify",docsUrl:"https://docs.privateav.com"};var m=class extends b{constructor(t){super(t,lt,k)}},ct="3.4.9";m.VERSION=ct;typeof window!="undefined"&&(q(),j(`${k.name} SDK`));var bt=m;return ht(Ct);})();
3
3
  if(typeof PrivateAVSDK !== "undefined" && PrivateAVSDK.PrivateAV) { window.PrivateAV = PrivateAVSDK.PrivateAV; window.PrivateAV.VERSION = PrivateAVSDK.VERSION; }