@salla.sa/embedded-sdk 0.2.1 → 0.2.3
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 +1 -0
- package/dist/cjs/index.js +3 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +504 -513
- package/dist/esm/index.js.map +1 -1
- package/dist/system/index.js +3 -3
- package/dist/system/index.js.map +1 -1
- package/dist/types/index.d.ts +151 -110
- package/dist/umd/index.js +3 -3
- package/dist/umd/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,6 +69,7 @@ The SDK provides modules for authentication, UI components, navigation, and page
|
|
|
69
69
|
- **UI**: `loading`, `toast`, `modal`, `confirm`
|
|
70
70
|
- **Page**: `setTitle()`, `navigate()`, `redirect()`, `resize()`
|
|
71
71
|
- **Nav**: `setAction()`, `onActionClick()`, `clearAction()`
|
|
72
|
+
- **Checkout**: `getAddons()`, `create()`, `onResult()`
|
|
72
73
|
|
|
73
74
|
## TypeScript
|
|
74
75
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s="embedded::",y={INIT:`${s}iframe.ready`,RESIZE:`${s}iframe.resize`,READY:`${s}ready`,DESTROY:`${s}destroy`},O={PROVIDE:`${s}context.provide`,THEME_CHANGE:`${s}theme.change`},g={LOADING:`${s}ui.loading`,TOAST:`${s}ui.toast`,CONFIRM:`${s}ui.confirm`,CONFIRM_RESPONSE:`${s}ui.confirm.response`},j="0.1.0",H={version:j},z={REFRESH:`${s}auth.refresh`},m={NAVIGATE:`${s}page.navigate`,REDIRECT:`${s}page.redirect`,SET_TITLE:`${s}page.setTitle`},v={SET_ACTION:`${s}nav.setAction`,CLEAR_ACTION:`${s}nav.clearAction`,ACTION_CLICK:`${s}nav.actionClick`},_={CREATE:`${s}checkout.create`},N=H.version,K=1e4,G=["localhost","merchants.workers.dev","s.salla.sa",".salla.group",".salla.sa"];let w={showVersion:!0,debug:!1};function X(e){w={...w,...e}}function x(e){return`%c${e}`}function D(e,t="#fff"){return`background-color: ${e}; color: ${t}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`}function b(e,...t){if(e==="debug"&&!w.debug)return;const r=[],i=[];r.push(x("EmbeddedSDK")),i.push(D("#10b981","#fff")),w.showVersion&&(r.push(x(`v${N}`)),i.push(D("#6b7280","#fff")));const n=r.join("").trim();(console[e]||console.log)(n,...i,...t)}const u={log:(...e)=>{b("log",...e)},warn:(...e)=>{b("warn",...e)},error:(...e)=>{b("error",...e)},info:(...e)=>{b("info",...e)},debug:(...e)=>{b("debug",...e)}};function W(e){try{const r=new URL(e).hostname;return G.some(i=>i.startsWith(".")?r.endsWith(i)||r===i.slice(1):r===i||r.startsWith(`${i}:`))}catch{return!1}}function Y(){return typeof window>"u"||window.parent===window?null:window.parent}function o(e,t,r="*",i,n){const a=Y();if(!a){u.warn("Not running in an iframe, cannot post to host");return}const l={event:e,payload:t||{},timestamp:Date.now(),source:"embedded-app",...i&&{requestId:i},metadata:{version:N}};a.postMessage(l,r)}const f=new Map;let A=!1;function P(e){if(process.env.NODE_ENV==="production"&&!W(e.origin))return;const t=e.data;if(!t||typeof t.event!="string"||!t.payload||typeof t.timestamp!="number"||!t.source){u.warn("Invalid message structure received:",t);return}const r=f.get(t.event);r&&r.forEach(n=>{try{n(t)}catch(a){u.error("Error in message handler:",a)}});const i=f.get("*");i&&i.forEach(n=>{try{n(t)}catch(a){u.error("Error in wildcard handler:",a)}})}function B(){A||typeof window>"u"||(window.addEventListener("message",P),A=!0)}function R(e,t){B(),f.has(e)||f.set(e,new Set);const r=f.get(e);return r.add(t),()=>{r.delete(t),r.size===0&&f.delete(e)}}function Z(e,t=K){return new Promise((r,i)=>{const n=setTimeout(()=>{a(),i(new Error(`[EmbeddedSDK] Timeout waiting for "${e}" message`))},t),a=R(e,l=>{clearTimeout(n),a(),r(l)})})}function J(){f.clear(),A&&typeof window<"u"&&(window.removeEventListener("message",P),A=!1)}function Q(){return typeof window>"u"?!1:window.parent!==window}const h=new Map,ee=3e4;function te(){const e=Date.now(),t=Math.random().toString(36).slice(2,9);return`req_${e}_${t}`}function re(e,t={},r=ee){const i=te();return new Promise((n,a)=>{const l=setTimeout(()=>{h.get(i)&&(h.delete(i),a(new Error(`[EmbeddedSDK] Request "${e}" timed out after ${r}ms`)))},r);h.set(i,{resolve:n,reject:a,timeout:l,event:e}),o(e,t,"*",i)})}function ie(e,t,r){const i=h.get(e);if(!i){u.warn(`Received response for unknown request: ${e}`);return}clearTimeout(i.timeout),h.delete(e),i.resolve(t)}function ne(e="SDK cleanup"){h.forEach((t,r)=>{clearTimeout(t.timeout),t.reject(new Error(`[EmbeddedSDK] Request ${r} cancelled: ${e}`))}),h.clear()}const ae="https://api.salla.dev";class E extends Error{constructor(t,r,i){super(t),this.status=r,this.response=i,this.name="ApiError"}}async function se(e,t={}){const{method:r="GET",headers:i={},body:n,timeout:a=3e4}=t,l=`${ae}${e}`,S=new AbortController,k=setTimeout(()=>{S.abort()},a);try{const c=await fetch(l,{method:r,headers:{"Content-Type":"application/json",...i},body:n?JSON.stringify(n):void 0,signal:S.signal});clearTimeout(k);let T;const I=c.headers.get("content-type");if(I!=null&&I.includes("application/json")?T=await c.json():T=await c.text(),!c.ok)throw new E(`API request failed: ${c.statusText}`,c.status,T);return T}catch(c){throw clearTimeout(k),c instanceof E?c:c instanceof Error?c.name==="AbortError"?new E(`Request timeout after ${a}ms`):new E(`Request failed: ${c.message}`):new E("Unknown error occurred")}}function C(e){return{isVerified:!1,isError:!0,error:e,data:null}}async function oe(e){const{token:t,appId:r,refreshOnError:i=!0}=e;if(!t){const n="Token is required. Provide it as a parameter or in URL as ?token=XXX";return u.error("Error in introspect:",n),C(n)}if(!r){const n="App ID is required. Provide it as a parameter or in URL as ?app_id=XXX";return u.error("Error in introspect:",n),C(n)}try{const n=await se("/exchange-authority/v1/introspect",{method:"POST",headers:{"S-Source":r,"Content-Type":"application/json"},body:{env:"prod",token:t,iss:"merchant-dashboard",subject:"embedded-page"}}),a=n.success;return{isVerified:a,isError:!a,error:a?void 0:"API request failed",data:a?n.data:null}}catch(n){i&&($().ui.toast.error((n==null?void 0:n.toString())??"Introspect error"),o(z.REFRESH,{})),u.error("Error in introspect:",n);const a=n instanceof Error?n.message:n;return C(a)}}function ue(e){return{getToken(){return new URLSearchParams(window.location.search).get("token")},getAppId(){return new URLSearchParams(window.location.search).get("app_id")},refresh(){o(z.REFRESH,{})},async introspect(t={}){const r=t.token??this.getToken()??"",i=t.appId??this.getAppId()??"";return oe({token:r,appId:i,refreshOnError:t.refreshOnError})}}}const M=["success","error","warning","info"];function ce(e){const t=[];return e.type===void 0||e.type===null?t.push("Toast type is required"):(typeof e.type!="string"||!M.includes(e.type))&&t.push(`Invalid toast type "${e.type}". Expected: ${M.join(" | ")}`),e.message===void 0||e.message===null?t.push("Toast message is required"):typeof e.message!="string"?t.push("Toast message must be a string"):e.message.trim()===""&&t.push("Toast message cannot be empty"),e.duration!==void 0&&e.duration!==null&&(typeof e.duration!="number"?t.push("Toast duration must be a number"):e.duration<0&&t.push("Toast duration cannot be negative")),{valid:t.length===0,errors:t}}function le(e){const t=[];return typeof e!="object"||e===null?(t.push("Checkout payload must be an object"),{valid:!1,errors:t}):(e.amount!==void 0&&e.amount!==null&&(typeof e.amount!="number"?t.push("Checkout amount must be a number"):e.amount<0&&t.push("Checkout amount cannot be negative")),e.currency!==void 0&&e.currency!==null&&(typeof e.currency!="string"?t.push("Checkout currency must be a string"):e.currency.trim()===""&&t.push("Checkout currency cannot be empty")),e.items!==void 0&&e.items!==null&&(Array.isArray(e.items)||t.push("Checkout items must be an array")),{valid:t.length===0,errors:t})}function de(e){const t=[];return e.path===void 0||e.path===null?t.push("Navigation path is required"):typeof e.path!="string"?t.push("Navigation path must be a string"):e.path.trim()===""&&t.push("Navigation path cannot be empty"),e.replace!==void 0&&typeof e.replace!="boolean"&&t.push("Navigation replace option must be a boolean"),{valid:t.length===0,errors:t}}function fe(e){const t=[];if(e.url===void 0||e.url===null)t.push("Redirect URL is required");else if(typeof e.url!="string")t.push("Redirect URL must be a string");else if(e.url.trim()==="")t.push("Redirect URL cannot be empty");else try{new URL(e.url)}catch{t.push(`Invalid redirect URL: "${e.url}"`)}return{valid:t.length===0,errors:t}}function he(e){const t=[];return e.title?typeof e.title!="string"&&t.push("Nav action title must be a string"):t.push("Nav action title is required"),e.value?typeof e.value!="string"&&t.push("Nav action value must be a string"):t.push("Nav action value is required"),e.subTitle!==void 0&&e.subTitle!==null&&typeof e.subTitle!="string"&&t.push("Nav action subTitle must be a string"),e.icon!==void 0&&e.icon!==null&&typeof e.icon!="string"&&t.push("Nav action icon must be a string"),e.disabled!==void 0&&e.disabled!==null&&typeof e.disabled!="boolean"&&t.push("Nav action disabled must be a boolean"),e.extendedActions!==void 0&&e.extendedActions!==null&&(Array.isArray(e.extendedActions)?e.extendedActions.forEach((r,i)=>{if(typeof r!="object"||r===null){t.push(`Extended action at index ${i} must be an object`);return}const n=r;(!n.title||typeof n.title!="string")&&t.push(`Extended action at index ${i} is missing required "title" property`),(!n.value||typeof n.value!="string")&&t.push(`Extended action at index ${i} is missing required "value" property`),n.subTitle!==void 0&&typeof n.subTitle!="string"&&t.push(`Extended action at index ${i} subTitle must be a string`),n.icon!==void 0&&typeof n.icon!="string"&&t.push(`Extended action at index ${i} icon must be a string`),n.disabled!==void 0&&typeof n.disabled!="boolean"&&t.push(`Extended action at index ${i} disabled must be a boolean`)}):t.push("Nav action extendedActions must be an array")),{valid:t.length===0,errors:t}}const U=["danger","warning","info"];function ge(e){const t=[];return e.title===void 0||e.title===null?t.push("Confirm dialog title is required"):typeof e.title!="string"?t.push("Confirm dialog title must be a string"):e.title.trim()===""&&t.push("Confirm dialog title cannot be empty"),e.message===void 0||e.message===null?t.push("Confirm dialog message is required"):typeof e.message!="string"?t.push("Confirm dialog message must be a string"):e.message.trim()===""&&t.push("Confirm dialog message cannot be empty"),e.confirmText!==void 0&&e.confirmText!==null&&typeof e.confirmText!="string"&&t.push("Confirm dialog confirmText must be a string"),e.cancelText!==void 0&&e.cancelText!==null&&typeof e.cancelText!="string"&&t.push("Confirm dialog cancelText must be a string"),e.variant!==void 0&&e.variant!==null&&(typeof e.variant!="string"||!U.includes(e.variant))&&t.push(`Invalid confirm variant "${e.variant}". Expected: ${U.join(" | ")}`),{valid:t.length===0,errors:t}}function d(e,t){u.error(`Validation failed for ${e}:
|
|
2
|
-
`+
|
|
3
|
-
`))}function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o="embedded::",v={INIT:`${o}iframe.ready`,RESIZE:`${o}iframe.resize`,READY:`${o}ready`,DESTROY:`${o}destroy`},L={PROVIDE:`${o}context.provide`,THEME_CHANGE:`${o}theme.change`},g={LOADING:`${o}ui.loading`,TOAST:`${o}ui.toast`,CONFIRM:`${o}ui.confirm`,CONFIRM_RESPONSE:`${o}ui.confirm.response`},X={},V={REFRESH:`${o}auth.refresh`},m={NAVIGATE:`${o}page.navigate`,REDIRECT:`${o}page.redirect`,SET_TITLE:`${o}page.setTitle`},S={SET_ACTION:`${o}nav.setAction`,CLEAR_ACTION:`${o}nav.clearAction`,ACTION_CLICK:`${o}nav.actionClick`},p={CREATE:`${o}checkout.create`,RESPONSE:`${o}checkout.response`,GET_ADDONS:`${o}checkout.getAddons`,GET_ADDONS_RESPONSE:`${o}checkout.getAddons.response`},N=X.version||"",W=1e4,Y=["localhost","merchants.workers.dev","s.salla.sa",".salla.group",".salla.sa"];let A={showVersion:!0,debug:!1};function B(t){A={...A,...t}}function k(t){return`%c${t}`}function q(t,e="#fff"){return`background-color: ${t}; color: ${e}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`}function b(t,...e){if(t==="debug"&&!A.debug)return;const r=[],i=[];r.push(k("EmbeddedSDK")),i.push(q("#10b981","#fff")),A.showVersion&&(r.push(k(`v${N}`)),i.push(q("#6b7280","#fff")));const n=r.join("").trim();(console[t]||console.log)(n,...i,...e)}const a={log:(...t)=>{b("log",...t)},warn:(...t)=>{b("warn",...t)},error:(...t)=>{b("error",...t)},info:(...t)=>{b("info",...t)},debug:(...t)=>{b("debug",...t)}};function Z(t){try{const r=new URL(t).hostname;return Y.some(i=>i.startsWith(".")?r.endsWith(i)||r===i.slice(1):r===i||r.startsWith(`${i}:`))}catch{return!1}}function Q(){return typeof window>"u"||window.parent===window?null:window.parent}function u(t,e,r="*",i,n){const s=Q();if(!s){a.warn("Not running in an iframe, cannot post to host");return}const c={event:t,payload:e||{},timestamp:Date.now(),source:"embedded-app",...i&&{requestId:i},metadata:{version:N}};s.postMessage(c,r)}const l=new Map;let R=!1;function H(t){if(process.env.NODE_ENV==="production"&&!Z(t.origin))return;const e=t.data;if(!e||typeof e.event!="string"||!e.payload||typeof e.timestamp!="number"||!e.source){a.warn("Invalid message structure received:",e);return}const r=l.get(e.event);r&&r.forEach(n=>{try{n(e)}catch(s){a.error("Error in message handler:",s)}});const i=l.get("*");i&&i.forEach(n=>{try{n(e)}catch(s){a.error("Error in wildcard handler:",s)}})}function J(){R||typeof window>"u"||(window.addEventListener("message",H),R=!0)}function y(t,e){J(),l.has(t)||l.set(t,new Set);const r=l.get(t);return r.add(e),()=>{r.delete(e),r.size===0&&l.delete(t)}}function ee(t,e=W){return new Promise((r,i)=>{const n=setTimeout(()=>{s(),i(new Error(`[EmbeddedSDK] Timeout waiting for "${t}" message`))},e),s=y(t,c=>{clearTimeout(n),s(),r(c)})})}function te(){l.clear(),R&&typeof window<"u"&&(window.removeEventListener("message",H),R=!1)}function re(){return typeof window>"u"?!1:window.parent!==window}function ie(t,e,r){const i={event:t,payload:e,timestamp:Date.now(),source:"merchant-dashboard",...r,metadata:{version:N,synthetic:!0}},n=l.get(t);n==null||n.forEach(s=>{try{s(i)}catch(c){a.error("Error in message handler:",c)}})}const h=new Map,ne=3e4;function j(){const t=Date.now(),e=Math.random().toString(36).slice(2,9);return`req_${t}_${e}`}function F(t,e={},r=ne){const i=j();return new Promise((n,s)=>{const c=setTimeout(()=>{h.get(i)&&(h.delete(i),s(new Error(`[EmbeddedSDK] Request "${t}" timed out after ${r}ms`)))},r);h.set(i,{resolve:n,reject:s,timeout:c,event:t}),u(t,e,"*",i)})}function G(t,e,r){const i=h.get(t);if(!i){a.warn(`Received response for unknown request: ${t}`);return}clearTimeout(i.timeout),h.delete(t),i.resolve(e)}function se(t="SDK cleanup"){h.forEach((e,r)=>{clearTimeout(e.timeout),e.reject(new Error(`[EmbeddedSDK] Request ${r} cancelled: ${t}`))}),h.clear()}function I(){const t=new Set;return{subscribe(e){return t.add(e),()=>{t.delete(e)}},notify(...e){t.forEach(r=>{try{r(...e)}catch(i){a.error("Error in subscription callback:",i)}})},clear(){t.clear()},size(){return t.size}}}const ae="https://api.salla.dev";class T extends Error{constructor(e,r,i){super(e),this.status=r,this.response=i,this.name="ApiError"}}async function oe(t,e={}){const{method:r="GET",headers:i={},body:n,timeout:s=3e4}=e,c=`${ae}${t}`,C=new AbortController,D=setTimeout(()=>{C.abort()},s);try{const d=await fetch(c,{method:r,headers:{"Content-Type":"application/json",...i},body:n?JSON.stringify(n):void 0,signal:C.signal});clearTimeout(D);let w;const $=d.headers.get("content-type");if($!=null&&$.includes("application/json")?w=await d.json():w=await d.text(),!d.ok)throw new T(`API request failed: ${d.statusText}`,d.status,w);return w}catch(d){throw clearTimeout(D),d instanceof T?d:d instanceof Error?d.name==="AbortError"?new T(`Request timeout after ${s}ms`):new T(`Request failed: ${d.message}`):new T("Unknown error occurred")}}function O(t){return{isVerified:!1,isError:!0,error:t,data:null}}async function ue(t){const{token:e,appId:r,refreshOnError:i=!0}=t;if(!e){const n="Token is required. Provide it as a parameter or in URL as ?token=XXX";return a.error("Error in introspect:",n),O(n)}if(!r){const n="App ID is required. Provide it as a parameter or in URL as ?app_id=XXX";return a.error("Error in introspect:",n),O(n)}try{const n=await oe("/exchange-authority/v1/introspect",{method:"POST",headers:{"S-Source":r,"Content-Type":"application/json"},body:{env:"prod",token:e,iss:"merchant-dashboard",subject:"embedded-page"}}),s=n.success;return{isVerified:s,isError:!s,error:s?void 0:"API request failed",data:s?n.data:null}}catch(n){i&&(x().ui.toast.error((n==null?void 0:n.toString())??"Introspect error"),u(V.REFRESH,{})),a.error("Error in introspect:",n);const s=n instanceof Error?n.message:n;return O(s)}}function ce(t){return{getToken(){return new URLSearchParams(window.location.search).get("token")},getAppId(){return new URLSearchParams(window.location.search).get("app_id")},refresh(){u(V.REFRESH,{})},async introspect(e={}){const r=e.token??this.getToken()??"",i=e.appId??this.getAppId()??"";return ue({token:r,appId:i,refreshOnError:e.refreshOnError})}}}const M=["success","error","warning","info"];function de(t){const e=[];return t.type===void 0||t.type===null?e.push("Toast type is required"):(typeof t.type!="string"||!M.includes(t.type))&&e.push(`Invalid toast type "${t.type}". Expected: ${M.join(" | ")}`),t.message===void 0||t.message===null?e.push("Toast message is required"):typeof t.message!="string"?e.push("Toast message must be a string"):t.message.trim()===""&&e.push("Toast message cannot be empty"),t.duration!==void 0&&t.duration!==null&&(typeof t.duration!="number"?e.push("Toast duration must be a number"):t.duration<0&&e.push("Toast duration cannot be negative")),{valid:e.length===0,errors:e}}function z(t,e){const r=[];return typeof t!="object"||t===null?(r.push(`${e} must be an object`),r):((typeof t.type!="string"||t.type.trim()==="")&&r.push(`${e} must have a valid type`),(typeof t.slug!="string"||t.slug.trim()==="")&&r.push(`${e} must have a valid slug`),t.quantity!==void 0&&(typeof t.quantity!="number"||t.quantity<1)&&r.push(`${e} must have a quantity >= 1`),r)}function le(t){const e=[];if(typeof t!="object"||t===null)return e.push("Checkout options must be an object"),{valid:!1,errors:e};const r="item"in t,i="items"in t;if(!r&&!i)return e.push("Checkout requires either 'item' or 'items'"),{valid:!1,errors:e};if(r){const n=z(t.item,"Item");return e.push(...n),{valid:e.length===0,errors:e}}return Array.isArray(t.items)?t.items.length===0?(e.push("At least one item is required"),{valid:!1,errors:e}):(t.items.forEach((n,s)=>{const c=z(n,`Item at index ${s}`);e.push(...c)}),{valid:e.length===0,errors:e}):(e.push("Checkout items must be an array"),{valid:!1,errors:e})}function fe(t){const e=[];return t.path===void 0||t.path===null?e.push("Navigation path is required"):typeof t.path!="string"?e.push("Navigation path must be a string"):t.path.trim()===""&&e.push("Navigation path cannot be empty"),t.replace!==void 0&&typeof t.replace!="boolean"&&e.push("Navigation replace option must be a boolean"),{valid:e.length===0,errors:e}}function he(t){const e=[];if(t.url===void 0||t.url===null)e.push("Redirect URL is required");else if(typeof t.url!="string")e.push("Redirect URL must be a string");else if(t.url.trim()==="")e.push("Redirect URL cannot be empty");else try{new URL(t.url)}catch{e.push(`Invalid redirect URL: "${t.url}"`)}return{valid:e.length===0,errors:e}}function ge(t){const e=[];return t.title?typeof t.title!="string"&&e.push("Nav action title must be a string"):e.push("Nav action title is required"),t.value?typeof t.value!="string"&&e.push("Nav action value must be a string"):e.push("Nav action value is required"),t.subTitle!==void 0&&t.subTitle!==null&&typeof t.subTitle!="string"&&e.push("Nav action subTitle must be a string"),t.icon!==void 0&&t.icon!==null&&typeof t.icon!="string"&&e.push("Nav action icon must be a string"),t.disabled!==void 0&&t.disabled!==null&&typeof t.disabled!="boolean"&&e.push("Nav action disabled must be a boolean"),t.extendedActions!==void 0&&t.extendedActions!==null&&(Array.isArray(t.extendedActions)?t.extendedActions.forEach((r,i)=>{if(typeof r!="object"||r===null){e.push(`Extended action at index ${i} must be an object`);return}const n=r;(!n.title||typeof n.title!="string")&&e.push(`Extended action at index ${i} is missing required "title" property`),(!n.value||typeof n.value!="string")&&e.push(`Extended action at index ${i} is missing required "value" property`),n.subTitle!==void 0&&typeof n.subTitle!="string"&&e.push(`Extended action at index ${i} subTitle must be a string`),n.icon!==void 0&&typeof n.icon!="string"&&e.push(`Extended action at index ${i} icon must be a string`),n.disabled!==void 0&&typeof n.disabled!="boolean"&&e.push(`Extended action at index ${i} disabled must be a boolean`)}):e.push("Nav action extendedActions must be an array")),{valid:e.length===0,errors:e}}const P=["danger","warning","info"];function me(t){const e=[];return t.title===void 0||t.title===null?e.push("Confirm dialog title is required"):typeof t.title!="string"?e.push("Confirm dialog title must be a string"):t.title.trim()===""&&e.push("Confirm dialog title cannot be empty"),t.message===void 0||t.message===null?e.push("Confirm dialog message is required"):typeof t.message!="string"?e.push("Confirm dialog message must be a string"):t.message.trim()===""&&e.push("Confirm dialog message cannot be empty"),t.confirmText!==void 0&&t.confirmText!==null&&typeof t.confirmText!="string"&&e.push("Confirm dialog confirmText must be a string"),t.cancelText!==void 0&&t.cancelText!==null&&typeof t.cancelText!="string"&&e.push("Confirm dialog cancelText must be a string"),t.variant!==void 0&&t.variant!==null&&(typeof t.variant!="string"||!P.includes(t.variant))&&e.push(`Invalid confirm variant "${t.variant}". Expected: ${P.join(" | ")}`),{valid:e.length===0,errors:e}}function f(t,e){a.error(`Validation failed for ${t}:
|
|
2
|
+
`+e.map(r=>` • ${r}`).join(`
|
|
3
|
+
`))}function pe(){return{navigate(t,e){const r=fe({path:t,...e});if(!r.valid){f(m.NAVIGATE,r.errors);return}u(m.NAVIGATE,{path:t,state:e==null?void 0:e.state,replace:e==null?void 0:e.replace})},redirect(t){const e=he({url:t});if(!e.valid){f(m.REDIRECT,e.errors);return}u(m.REDIRECT,{url:t})},navTo(t,e){if(t.startsWith("http://")||t.startsWith("https://")){this.redirect(t);return}this.navigate(t,e)},resize(t){if(typeof t!="number"||t<0){f(v.RESIZE,["Height must be a non-negative number"]);return}u(v.RESIZE,{height:t})},autoResize(){const t=document.documentElement.scrollHeight;this.resize(t)},setTitle(t){if(typeof t!="string"||!t.trim()){f(m.SET_TITLE,["Title must be a non-empty string"]);return}u(m.SET_TITLE,{title:t})}}}function Ee(){const t=I();return y(S.ACTION_CLICK,e=>{t.notify(e.payload.value)}),{setAction(e){var i;const r=ge(e);if(!r.valid){f(S.SET_ACTION,r.errors);return}u(S.SET_ACTION,{title:e.title,value:e.value,subTitle:e.subTitle,icon:e.icon,disabled:e.disabled,extendedActions:(i=e.extendedActions)==null?void 0:i.map(n=>({title:n.title,value:n.value,subTitle:n.subTitle,icon:n.icon,disabled:n.disabled}))})},clearAction(){u(S.CLEAR_ACTION,{})},onActionClick(e){return t.subscribe(e)}}}function ye(){return{show(){u(g.LOADING,{action:"show"})},hide(){u(g.LOADING,{action:"hide"})}}}function be(){const t=e=>{const r=de(e);if(!r.valid){f(g.TOAST,r.errors);return}u(g.TOAST,{type:e.type,message:e.message,duration:e.duration})};return{show:t,success(e,r){t({type:"success",message:e,duration:r})},error(e,r){t({type:"error",message:e,duration:r})},warning(e,r){t({type:"warning",message:e,duration:r})},info(e,r){t({type:"info",message:e,duration:r})}}}function Te(){return async t=>{const e=me(t);return e.valid?F(g.CONFIRM,{title:t.title,message:t.message,confirmText:t.confirmText??"Confirm",cancelText:t.cancelText??"Cancel",variant:t.variant??"info"}):(f(g.CONFIRM,e.errors),Promise.reject(new Error(e.errors.join(", "))))}}function ve(){return{loading:ye(),toast:be(),confirm:Te()}}function we(){const t=I(),e=[];return e.push(y(p.RESPONSE,r=>{t.notify({success:r.payload.success,order_id:r.payload.order_id,status:r.payload.status,error:r.payload.error,context:r.payload.context})})),e.push(y(p.GET_ADDONS_RESPONSE,r=>{r.requestId&&G(r.requestId,{success:r.payload.success,addons:r.payload.addons,error:r.payload.error})})),{create(r,i){const n=Array.isArray(r)?r:[r],s=le({items:n});if(!s.valid)throw f(p.CREATE,s.errors),new Error(s.errors[0]);u(p.CREATE,{items:n.map(c=>({type:c.type,slug:c.slug,quantity:c.quantity??1})),...(i==null?void 0:i.context)!==void 0&&{context:i.context}},"*",j())},onResult(r){return t.subscribe(r)},async getAddons(){try{return await F(p.GET_ADDONS,{},3e4)}catch(r){return{success:!1,error:{code:"REQUEST_FAILED",message:r instanceof Error?r.message:"Unknown error"}}}},destroy(){e.forEach(r=>r()),e.length=0,t.clear()}}}const U={theme:"light",width:0,locale:"ar",currency:"SAR"};class K{constructor(){this.initialized=!1,this.initializing=!1,this.debugMode=!1,this.appReady=!1,this.layout={...U},this.postInitHooks=[],this.themeSubscription=I(),this.initSubscription=I(),this.auth=ce(),this.page=pe(),this.nav=Ee(),this.ui=ve(),this.checkout=we(),this.registerPostInitHook(e=>{const r=e.payload.pendingCheckoutResult;r&&(a.debug("Dispatching pending checkout result:",r),queueMicrotask(()=>{ie(p.RESPONSE,{success:r.success,status:r.status,error:r.error,context:r.context})}))}),this.setupListeners()}registerPostInitHook(e){this.postInitHooks.push(e)}setupListeners(){y(L.THEME_CHANGE,e=>{this.layout.theme=e.payload.theme,a.debug("Theme changed:",e.payload.theme),this.themeSubscription.notify(e.payload.theme)}),y(g.CONFIRM_RESPONSE,e=>{a.debug("Received confirm response:",e),e.requestId&&G(e.requestId,{confirmed:e.payload.confirmed})})}getState(){return{ready:this.initialized,initializing:this.initializing,layout:{...this.layout}}}isReady(){return this.initialized}onThemeChange(e){return this.themeSubscription.subscribe(e)}onInit(e){if(this.initialized)try{e(this.getState())}catch(r){a.error("Error in init callback:",r)}return this.initSubscription.subscribe(e)}ready(){if(this.appReady){a.debug("App already signaled as ready");return}if(!this.initialized){a.warn("Cannot signal ready before init() is called");return}this.appReady=!0,u(v.READY,{}),a.debug("Sent ready signal to host")}async init(e={}){if(this.initialized)return a.debug("Already initialized, returning current layout"),{layout:{...this.layout}};if(this.initializing)return a.warn("Initialization already in progress"),new Promise(r=>{const i=this.onInit(n=>{i(),r({layout:{...n.layout}})})});this.initializing=!0,this.debugMode=e.debug??!1,B({debug:this.debugMode}),re()||a.warn("Not running in an iframe. Some features may not work."),a.debug("Initializing SDK...");try{u(v.INIT,{height:document.documentElement.scrollHeight}),a.debug("Sent iframe.ready message, waiting for context...");const r=await ee(L.PROVIDE);a.debug("Received context from host:",r);const{layout:i}=r.payload;return this.layout={theme:(i==null?void 0:i.theme)??"light",width:(i==null?void 0:i.width)??0,locale:(i==null?void 0:i.locale)??"ar",currency:(i==null?void 0:i.currency)??"SAR"},this.postInitHooks.forEach(n=>{try{n(r)}catch(s){a.error("Error in post-init hook:",s)}}),this.initialized=!0,this.initializing=!1,a.debug("Initialization complete. Layout:",this.layout),this.initSubscription.notify(this.getState()),{layout:{...this.layout}}}catch(r){throw this.initializing=!1,r}}destroy(){a.debug("Destroying SDK instance"),this.initialized&&(u(v.DESTROY,{}),a.debug("Sent destroy event to host")),this.checkout.destroy(),se("SDK destroyed"),te(),this.themeSubscription.clear(),this.initSubscription.clear(),this.postInitHooks=[],this.initialized=!1,this.initializing=!1,this.appReady=!1,this.layout={...U}}}let E=null;function x(){return E||(E=new K),E}function Se(){E&&(E.destroy(),E=null)}const _=x(),Ae=N;typeof window<"u"&&(window.salla=window.salla||window.Salla||{},window.Salla=window.salla,window.salla.embedded||(window.salla.embedded=_),window.Salla.embedded||(window.Salla.embedded=_));exports.EmbeddedApp=K;exports.embedded=_;exports.getEmbeddedApp=x;exports.resetEmbeddedApp=Se;exports.version=Ae;
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/core/events.ts","../../src/modules/ui/events.ts","../../src/modules/auth/events.ts","../../src/modules/page/events.ts","../../src/modules/nav/events.ts","../../src/modules/checkout/events.ts","../../src/core/constants.ts","../../src/core/logger.ts","../../src/core/messenger.ts","../../src/core/requests.ts","../../src/core/api.ts","../../src/modules/auth/functions/introspect.ts","../../src/modules/auth/index.ts","../../src/core/validation/toast.ts","../../src/core/validation/checkout.ts","../../src/core/validation/navigation.ts","../../src/core/validation/nav-action.ts","../../src/core/validation/confirm.ts","../../src/core/validation/utils.ts","../../src/modules/page/index.ts","../../src/modules/nav/index.ts","../../src/modules/ui/components/loading.ts","../../src/modules/ui/components/toast.ts","../../src/modules/ui/components/confirm.ts","../../src/modules/ui/index.ts","../../src/modules/checkout/index.ts","../../src/core/EmbeddedApp.ts","../../src/index.ts"],"sourcesContent":["/**\n * @fileoverview Core event constants.\n * Event naming convention: `embedded::{module}.{action}`\n */\n\n/**\n * Event prefix for all embedded events.\n */\nexport const EVENT_PREFIX = \"embedded::\" as const;\n\n/**\n * Iframe lifecycle events.\n */\nexport const IFRAME_EVENTS = {\n /** Initialize handshake - iframe signals it's ready to receive context */\n INIT: `${EVENT_PREFIX}iframe.ready`,\n /** Request iframe resize */\n RESIZE: `${EVENT_PREFIX}iframe.resize`,\n /** App signals it's fully loaded and ready */\n READY: `${EVENT_PREFIX}ready`,\n /** App requests to be destroyed and navigate away */\n DESTROY: `${EVENT_PREFIX}destroy`,\n} as const;\n\n/**\n * Context events (Host → Iframe).\n */\nexport const CONTEXT_EVENTS = {\n /** Context data provision */\n PROVIDE: `${EVENT_PREFIX}context.provide`,\n /** Theme change notification */\n THEME_CHANGE: `${EVENT_PREFIX}theme.change`,\n} as const;\n","/**\n * @fileoverview UI module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * UI state events.\n */\nexport const UI_EVENTS = {\n /** Set loading state */\n LOADING: `${EVENT_PREFIX}ui.loading`,\n /** Show toast notification */\n TOAST: `${EVENT_PREFIX}ui.toast`,\n /** Show confirm dialog (async request) */\n CONFIRM: `${EVENT_PREFIX}ui.confirm`,\n /** Confirm dialog response (from host) */\n CONFIRM_RESPONSE: `${EVENT_PREFIX}ui.confirm.response`,\n} as const;\n","/**\n * @fileoverview Authentication module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Authentication events.\n */\nexport const AUTH_EVENTS = {\n /** Request token refresh (re-renders iframe with new token) */\n REFRESH: `${EVENT_PREFIX}auth.refresh`,\n} as const;\n","/**\n * @fileoverview Page module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Page navigation events.\n */\nexport const PAGE_EVENTS = {\n /** Navigate using React Router (SPA navigation) */\n NAVIGATE: `${EVENT_PREFIX}page.navigate`,\n /** Redirect using window.location (full page reload) */\n REDIRECT: `${EVENT_PREFIX}page.redirect`,\n /** Set page title */\n SET_TITLE: `${EVENT_PREFIX}page.setTitle`,\n} as const;\n","/**\n * @fileoverview Nav module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Navigation action events.\n */\nexport const NAV_EVENTS = {\n /** Set primary action button in navbar */\n SET_ACTION: `${EVENT_PREFIX}nav.setAction`,\n /** Clear the primary action button */\n CLEAR_ACTION: `${EVENT_PREFIX}nav.clearAction`,\n /** Notification when action button is clicked (host → iframe) */\n ACTION_CLICK: `${EVENT_PREFIX}nav.actionClick`,\n} as const;\n","/**\n * @fileoverview Checkout module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Checkout events.\n */\nexport const CHECKOUT_EVENTS = {\n /** Initialize checkout flow */\n CREATE: `${EVENT_PREFIX}checkout.create`,\n} as const;\n","import pkg from \"../../package.json\" assert { type: \"json\" };\n\n/**\n * @fileoverview Constants for the Embedded SDK.\n * Re-exports all module events for backward compatibility.\n */\n\n// Re-export core events\nexport { EVENT_PREFIX, IFRAME_EVENTS, CONTEXT_EVENTS } from \"./events\";\n\n// Re-export module events\nexport { AUTH_EVENTS } from \"../modules/auth/events\";\nexport { PAGE_EVENTS } from \"../modules/page/events\";\nexport { NAV_EVENTS } from \"../modules/nav/events\";\nexport { UI_EVENTS } from \"../modules/ui/events\";\nexport { CHECKOUT_EVENTS } from \"../modules/checkout/events\";\n\n/**\n * SDK version for debugging and compatibility checks.\n */\nexport const SDK_VERSION: string = pkg.version;\n\n/**\n * Default timeout for waiting for host responses (ms).\n */\nexport const DEFAULT_TIMEOUT = 10000;\n\n/**\n * Trusted domains for message validation.\n * The host will validate based on iframe URL, but SDK validates for host messages.\n */\nexport const TRUSTED_DOMAINS = [\n \"localhost\",\n \"merchants.workers.dev\",\n \"s.salla.sa\",\n \".salla.group\",\n \".salla.sa\",\n] as const;\n","/**\n * @fileoverview Unified logging utility for the Embedded SDK.\n */\n\nimport { SDK_VERSION } from \"./constants\";\n\n/**\n * Logger configuration.\n */\ninterface LoggerConfig {\n /** Whether to show the version badge */\n showVersion?: boolean;\n /** Whether debug mode is enabled */\n debug?: boolean;\n}\n\n/**\n * Log level types supported by the logger.\n */\ntype LogType = \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n\n/**\n * Global logger configuration.\n */\nlet loggerConfig: LoggerConfig = {\n showVersion: true,\n debug: false,\n};\n\n/**\n * Set the logger configuration.\n *\n * @param config - Logger configuration options\n */\nexport function setLoggerConfig(config: LoggerConfig): void {\n loggerConfig = { ...loggerConfig, ...config };\n}\n\n/**\n * Get the current logger configuration.\n */\nexport function getLoggerConfig(): Readonly<LoggerConfig> {\n return { ...loggerConfig };\n}\n\n/**\n * Create styled badge for console output.\n *\n * @param text - Badge text\n * @returns Formatted badge string\n */\nfunction createBadge(text: string): string {\n return `%c${text}`;\n}\n\n/**\n * Get CSS styles for a badge.\n *\n * @param backgroundColor - CSS color for background\n * @param textColor - CSS color for text\n * @returns CSS style string\n */\nfunction getBadgeStyle(backgroundColor: string, textColor = \"#fff\"): string {\n return `background-color: ${backgroundColor}; color: ${textColor}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`;\n}\n\n/**\n * Unified logging function that supports all console log types.\n *\n * @param type - Log type (log, warn, error, info, debug)\n * @param args - Arguments to log\n */\nexport function log(type: LogType, ...args: unknown[]): void {\n // Skip debug logs if debug mode is disabled\n if (type === \"debug\" && !loggerConfig.debug) {\n return;\n }\n\n const badges: string[] = [];\n const styles: string[] = [];\n\n // Add EmbeddedSDK badge (green)\n badges.push(createBadge(\"EmbeddedSDK\"));\n styles.push(getBadgeStyle(\"#10b981\", \"#fff\"));\n\n // Add version badge (gray) if enabled\n if (loggerConfig.showVersion) {\n badges.push(createBadge(`v${SDK_VERSION}`));\n styles.push(getBadgeStyle(\"#6b7280\", \"#fff\"));\n }\n\n // Combine badges without space\n const badgeString = badges.join(\"\").trim();\n\n // Get the appropriate console method\n const consoleMethod = console[type] || console.log;\n\n // Call console method with badges and styles\n consoleMethod(badgeString, ...styles, ...args);\n}\n\n/**\n * Convenience methods for each log type.\n */\nexport const logger = {\n log: (...args: unknown[]) => {\n log(\"log\", ...args);\n },\n warn: (...args: unknown[]) => {\n log(\"warn\", ...args);\n },\n error: (...args: unknown[]) => {\n log(\"error\", ...args);\n },\n info: (...args: unknown[]) => {\n log(\"info\", ...args);\n },\n debug: (...args: unknown[]) => {\n log(\"debug\", ...args);\n },\n};\n","/**\n * @fileoverview PostMessage utilities for communicating with the host.\n */\n\nimport { DEFAULT_TIMEOUT, SDK_VERSION, TRUSTED_DOMAINS } from \"./constants\";\nimport type { BaseMessage, MessageCallback, Unsubscribe } from \"./types\";\nimport { logger } from \"./logger\";\n\n/**\n * Check if an origin is trusted.\n */\nfunction isTrustedOrigin(origin: string): boolean {\n try {\n const url = new URL(origin);\n const hostname = url.hostname;\n\n return TRUSTED_DOMAINS.some((domain) => {\n if (domain.startsWith(\".\")) {\n // Suffix match (e.g., \".salla.sa\" matches \"app.salla.sa\")\n return hostname.endsWith(domain) || hostname === domain.slice(1);\n }\n // Exact match\n return hostname === domain || hostname.startsWith(`${domain}:`);\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Get the parent window (host) reference.\n * Returns null if not in an iframe.\n */\nfunction getParentWindow(): Window | null {\n if (typeof window === \"undefined\") return null;\n if (window.parent === window) return null;\n return window.parent;\n}\n\n/**\n * Send a message to the host (parent window).\n *\n * @param event - The event name\n * @param data - Additional data to send with the message (will be wrapped in payload)\n * @param targetOrigin - Target origin for security (defaults to \"*\")\n * @param requestId - Optional request ID for request/response patterns\n * @param metadata - Optional metadata for additional context\n */\nexport function postToHost<T extends Record<string, unknown>>(\n event: string,\n data?: T,\n targetOrigin: string = \"*\",\n requestId?: string,\n metadata?: Record<string, unknown>,\n): void {\n const parent = getParentWindow();\n\n if (!parent) {\n logger.warn(\"Not running in an iframe, cannot post to host\");\n return;\n }\n\n const message: BaseMessage = {\n event,\n payload: data || {},\n timestamp: Date.now(),\n source: \"embedded-app\",\n ...(requestId && { requestId }),\n metadata: {\n version: SDK_VERSION,\n ...(metadata || {}),\n },\n };\n\n parent.postMessage(message, targetOrigin);\n}\n\n/**\n * Message listener registry.\n */\nconst listeners: Map<string, Set<MessageCallback>> = new Map();\n\n/**\n * Global message handler.\n */\nlet isListening = false;\n\nfunction handleMessage(event: MessageEvent): void {\n // Validate origin in production\n if (process.env.NODE_ENV === \"production\" && !isTrustedOrigin(event.origin)) {\n return;\n }\n\n const data = event.data as BaseMessage;\n\n // Validate message structure\n if (\n !data ||\n typeof data.event !== \"string\" ||\n !data.payload ||\n typeof data.timestamp !== \"number\" ||\n !data.source\n ) {\n logger.warn(\"Invalid message structure received:\", data);\n return;\n }\n\n const eventListeners = listeners.get(data.event);\n if (eventListeners) {\n eventListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n logger.error(\"Error in message handler:\", error);\n }\n });\n }\n\n // Also notify wildcard listeners\n const wildcardListeners = listeners.get(\"*\");\n if (wildcardListeners) {\n wildcardListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n logger.error(\"Error in wildcard handler:\", error);\n }\n });\n }\n}\n\n/**\n * Start listening for messages if not already.\n */\nfunction startListening(): void {\n if (isListening || typeof window === \"undefined\") return;\n\n window.addEventListener(\"message\", handleMessage);\n isListening = true;\n}\n\n/**\n * Subscribe to messages from the host.\n *\n * @param event - The event name to listen for, or \"*\" for all events\n * @param callback - Callback function when message is received\n * @returns Unsubscribe function\n */\nexport function onMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n callback: MessageCallback<T>,\n): Unsubscribe {\n startListening();\n\n if (!listeners.has(event)) {\n listeners.set(event, new Set());\n }\n\n const eventListeners = listeners.get(event)!;\n eventListeners.add(callback as MessageCallback);\n\n return () => {\n eventListeners.delete(callback as MessageCallback);\n if (eventListeners.size === 0) {\n listeners.delete(event);\n }\n };\n}\n\n/**\n * Wait for a specific message from the host.\n *\n * @param event - The event name to wait for\n * @param timeout - Timeout in milliseconds (defaults to DEFAULT_TIMEOUT)\n * @returns Promise that resolves with the message data\n */\nexport function waitForMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n timeout: number = DEFAULT_TIMEOUT,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n unsubscribe();\n reject(new Error(`[EmbeddedSDK] Timeout waiting for \"${event}\" message`));\n }, timeout);\n\n const unsubscribe = onMessage<T>(event, (data) => {\n clearTimeout(timer);\n unsubscribe();\n resolve(data);\n });\n });\n}\n\n/**\n * Remove all message listeners.\n */\nexport function removeAllListeners(): void {\n listeners.clear();\n\n if (isListening && typeof window !== \"undefined\") {\n window.removeEventListener(\"message\", handleMessage);\n isListening = false;\n }\n}\n\n/**\n * Check if running inside an iframe.\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") return false;\n return window.parent !== window;\n}\n","/**\n * @fileoverview Request-response tracking for async operations over postMessage.\n * Enables Promise-based APIs for operations that need host responses (e.g., confirm dialogs).\n */\n\nimport { postToHost } from \"./messenger\";\nimport { logger } from \"./logger\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Pending request entry with resolve/reject functions and timeout.\n */\ninterface PendingRequest<T = unknown> {\n resolve: (value: T) => void;\n reject: (reason: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n event: string;\n}\n\n// ============================================================================\n// State\n// ============================================================================\n\n/**\n * Map of pending requests by requestId.\n */\nconst pendingRequests = new Map<string, PendingRequest>();\n\n/**\n * Default timeout for requests (30 seconds).\n */\nconst DEFAULT_REQUEST_TIMEOUT = 30000;\n\n// ============================================================================\n// Request ID Generation\n// ============================================================================\n\n/**\n * Generate a unique request ID.\n * Format: req_{timestamp}_{random}\n */\nexport function generateRequestId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 9);\n return `req_${timestamp}_${random}`;\n}\n\n// ============================================================================\n// Request/Response Functions\n// ============================================================================\n\n/**\n * Send a request to the host and return a Promise that resolves when the response is received.\n *\n * @param event - The event name to send\n * @param data - Additional data to send with the request\n * @param timeout - Timeout in milliseconds (defaults to 30000)\n * @returns Promise that resolves with the response data\n *\n * @example\n * ```typescript\n * const result = await sendRequest<{ confirmed: boolean }>(\n * 'embedded::ui.confirm',\n * { title: 'Delete?', message: 'Are you sure?' }\n * );\n * if (result.confirmed) {\n * // User confirmed\n * }\n * ```\n */\nexport function sendRequest<T>(\n event: string,\n data: Record<string, unknown> = {},\n timeout: number = DEFAULT_REQUEST_TIMEOUT,\n): Promise<T> {\n const requestId = generateRequestId();\n\n return new Promise<T>((resolve, reject) => {\n // Set up timeout\n const timer = setTimeout(() => {\n const pending = pendingRequests.get(requestId);\n if (pending) {\n pendingRequests.delete(requestId);\n reject(\n new Error(\n `[EmbeddedSDK] Request \"${event}\" timed out after ${timeout}ms`,\n ),\n );\n }\n }, timeout);\n\n // Store the pending request\n pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timer,\n event,\n });\n\n // Send the request to host with requestId as base field\n postToHost(event, data, \"*\", requestId);\n });\n}\n\n/**\n * Handle a response from the host for a pending request.\n * Called by the message listener when a response event is received.\n *\n * @param requestId - The request ID from the response\n * @param result - The result data to resolve with\n * @param error - Optional error message to reject with\n *\n * @example\n * ```typescript\n * // In message listener:\n * onMessage('embedded::ui.confirm.response', (msg) => {\n * handleResponse(msg.requestId, { confirmed: msg.confirmed });\n * });\n * ```\n */\nexport function handleResponse<T = unknown>(\n requestId: string,\n result: T,\n error?: string,\n): void {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n // Request may have already timed out or been handled\n logger.warn(`Received response for unknown request: ${requestId}`);\n return;\n }\n\n // Clear the timeout\n clearTimeout(pending.timeout);\n\n // Remove from pending requests\n pendingRequests.delete(requestId);\n\n // Resolve or reject the promise\n if (error) {\n pending.reject(new Error(error));\n } else {\n pending.resolve(result);\n }\n}\n\n/**\n * Check if there are any pending requests.\n * Useful for cleanup or debugging.\n */\nexport function hasPendingRequests(): boolean {\n return pendingRequests.size > 0;\n}\n\n/**\n * Get the count of pending requests.\n * Useful for debugging.\n */\nexport function getPendingRequestCount(): number {\n return pendingRequests.size;\n}\n\n/**\n * Cancel all pending requests.\n * Useful for cleanup when the SDK is being destroyed.\n *\n * @param reason - Optional reason for cancellation\n */\nexport function cancelAllRequests(reason: string = \"SDK cleanup\"): void {\n pendingRequests.forEach((pending, requestId) => {\n clearTimeout(pending.timeout);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n });\n pendingRequests.clear();\n}\n\n/**\n * Cancel a specific pending request.\n *\n * @param requestId - The request ID to cancel\n * @param reason - Optional reason for cancellation\n * @returns true if the request was found and cancelled, false otherwise\n */\nexport function cancelRequest(\n requestId: string,\n reason: string = \"Cancelled\",\n): boolean {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n return false;\n }\n\n clearTimeout(pending.timeout);\n pendingRequests.delete(requestId);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n\n return true;\n}\n","/**\n * @fileoverview API client wrapper for making requests to Salla API.\n */\n\n/**\n * Base URL for Salla API.\n */\nconst API_BASE_URL = \"https://api.salla.dev\";\n\n/**\n * Options for API requests.\n */\nexport interface ApiRequestOptions {\n /** Request method */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n /** Request headers */\n headers?: Record<string, string>;\n /** Request body */\n body?: unknown;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * API error class for handling API request failures.\n */\nexport class ApiError extends Error {\n constructor(\n message: string,\n public status?: number,\n public response?: unknown,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\n/**\n * Make a request to the Salla API.\n *\n * @param endpoint - API endpoint path (e.g., \"/exchange-authority/v1/introspect\")\n * @param options - Request options\n * @returns Promise that resolves with the response data\n * @throws {ApiError} If the request fails\n *\n * @example\n * ```typescript\n * const response = await apiRequest(\"/exchange-authority/v1/introspect\", {\n * method: \"POST\",\n * headers: { \"S-Source\": \"app-id\", \"Content-Type\": \"application/json\" },\n * body: { token: \"xxx\", env: \"prod\" }\n * });\n * ```\n */\nexport async function apiRequest<T = unknown>(\n endpoint: string,\n options: ApiRequestOptions = {},\n): Promise<T> {\n const { method = \"GET\", headers = {}, body, timeout = 30000 } = options;\n\n const url = `${API_BASE_URL}${endpoint}`;\n\n // Create AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...headers,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n let data: unknown;\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n // Check if response is successful\n if (!response.ok) {\n throw new ApiError(\n `API request failed: ${response.statusText}`,\n response.status,\n data,\n );\n }\n\n return data as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new ApiError(`Request timeout after ${timeout}ms`);\n }\n throw new ApiError(`Request failed: ${error.message}`);\n }\n\n throw new ApiError(\"Unknown error occurred\");\n }\n}\n","/**\n * @fileoverview Introspect function for token verification.\n */\n\nimport { apiRequest } from \"../../../core/api\";\nimport { logger } from \"../../../core/logger\";\nimport { getEmbeddedApp } from \"../../../core/EmbeddedApp\";\nimport { postToHost } from \"../../../core/messenger\";\nimport { AUTH_EVENTS } from \"../events\";\nimport type { IntrospectResponse, IntrospectResponseData } from \"../types\";\n\n/**\n * Raw API response from the introspect endpoint.\n */\ninterface RawIntrospectApiResponse {\n status: number;\n success: boolean;\n data: IntrospectResponseData;\n}\n\n/**\n * Options for the introspect function.\n */\nexport interface IntrospectParams {\n /** Application ID (audience) */\n appId: string;\n /** Short-lived token */\n token: string;\n /** Automatically refresh token on error (default: true) */\n refreshOnError?: boolean;\n}\n\n/**\n * Create error response for introspect.\n */\nfunction createErrorResponse(errorMessage: unknown): IntrospectResponse {\n return {\n isVerified: false,\n isError: true,\n error: errorMessage,\n data: null,\n };\n}\n\n/**\n * Introspect (verify) a short-lived token with Salla's API.\n * This function verifies the token and returns token information.\n *\n * @param params - Introspect parameters including token, appId, and refreshOnError\n * @returns Promise that resolves with the introspect response\n */\nexport async function introspect(\n params: IntrospectParams,\n): Promise<IntrospectResponse> {\n const { token, appId, refreshOnError = true } = params;\n\n if (!token) {\n const errorMessage =\n \"Token is required. Provide it as a parameter or in URL as ?token=XXX\";\n logger.error(\"Error in introspect:\", errorMessage);\n return createErrorResponse(errorMessage);\n }\n\n if (!appId) {\n const errorMessage =\n \"App ID is required. Provide it as a parameter or in URL as ?app_id=XXX\";\n logger.error(\"Error in introspect:\", errorMessage);\n return createErrorResponse(errorMessage);\n }\n\n try {\n const apiResponse = await apiRequest<RawIntrospectApiResponse>(\n \"/exchange-authority/v1/introspect\",\n {\n method: \"POST\",\n headers: {\n \"S-Source\": appId,\n \"Content-Type\": \"application/json\",\n },\n body: {\n env: \"prod\",\n token,\n iss: \"merchant-dashboard\",\n subject: \"embedded-page\",\n },\n },\n );\n\n // Transform API response to SDK response format\n const isVerified = apiResponse.success;\n return {\n isVerified,\n isError: !isVerified,\n error: !isVerified ? \"API request failed\" : undefined,\n data: isVerified ? apiResponse.data : null,\n };\n } catch (error) {\n // Default error handler: refresh token if refreshOnError is enabled\n if (refreshOnError) {\n getEmbeddedApp().ui.toast.error(error?.toString() ?? \"Introspect error\");\n postToHost(AUTH_EVENTS.REFRESH, {});\n }\n logger.error(\"Error in introspect:\", error);\n\n // Resolve with error response instead of rejecting\n const errorMessage =\n error instanceof Error\n ? error.message\n : typeof error === \"string\"\n ? error\n : error;\n\n return createErrorResponse(errorMessage);\n }\n}\n","/**\n * @fileoverview Auth module for token and authentication management.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { AUTH_EVENTS } from \"./events\";\nimport type {\n AuthModule,\n StateGetter,\n IntrospectOptions,\n IntrospectResponse,\n} from \"./types\";\nimport { introspect as introspectFunction } from \"./functions/introspect\";\n\nexport type {\n AuthModule,\n IntrospectOptions,\n IntrospectResponse,\n} from \"./types\";\n\n/**\n * Create the auth module.\n *\n * @param _getState - Function to get current SDK state (kept for consistency)\n * @returns Auth module instance\n */\nexport function createAuthModule(_getState: StateGetter): AuthModule {\n return {\n /**\n * Get the token from the URL query parameter.\n * The token is passed to the iframe via ?token=XXX\n *\n * @example\n * ```typescript\n * const token = embedded.auth.getToken();\n * if (token) {\n * await verifyWithBackend(token);\n * }\n * ```\n */\n getToken(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"token\");\n },\n\n /**\n * Get the app ID from the URL query parameter.\n * The app ID is passed to the iframe via ?app_id=XXX\n */\n getAppId(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"app_id\");\n },\n\n /**\n * Request a token refresh from the host.\n * This will re-render the iframe with a new token URL.\n *\n * @example\n * ```typescript\n * // When token is about to expire\n * embedded.auth.refresh();\n * ```\n */\n refresh(): void {\n postToHost(AUTH_EVENTS.REFRESH, {});\n },\n\n /**\n * Introspect (verify) a short-lived token with Salla's API.\n * This method verifies the token and returns token information.\n *\n * @param options - Optional parameters (appId, token, and refreshOnError). If not provided, will be extracted from URL params.\n * @returns Promise that resolves with the introspect response. On API error, resolves with isVerified: false, isError: true, and empty data.\n */\n async introspect(\n options: IntrospectOptions = {},\n ): Promise<IntrospectResponse> {\n const token = options.token ?? this.getToken() ?? \"\";\n const appId = options.appId ?? this.getAppId() ?? \"\";\n return introspectFunction({\n token,\n appId,\n refreshOnError: options.refreshOnError,\n });\n },\n };\n}\n","/**\n * @fileoverview Toast notification validation.\n */\n\nimport type { ToastType } from \"../types\";\nimport type { ValidationResult, ToastValidationInput } from \"./types\";\n\nconst VALID_TOAST_TYPES: ToastType[] = [\"success\", \"error\", \"warning\", \"info\"];\n\n/**\n * Validate toast notification options.\n */\nexport function validateToast(options: ToastValidationInput): ValidationResult {\n const errors: string[] = [];\n\n // Type validation\n if (options.type === undefined || options.type === null) {\n errors.push(\"Toast type is required\");\n } else if (\n typeof options.type !== \"string\" ||\n !VALID_TOAST_TYPES.includes(options.type as ToastType)\n ) {\n errors.push(\n `Invalid toast type \"${options.type}\". Expected: ${VALID_TOAST_TYPES.join(\" | \")}`,\n );\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Toast message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Toast message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Toast message cannot be empty\");\n }\n\n // Duration validation (optional)\n if (options.duration !== undefined && options.duration !== null) {\n if (typeof options.duration !== \"number\") {\n errors.push(\"Toast duration must be a number\");\n } else if (options.duration < 0) {\n errors.push(\"Toast duration cannot be negative\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Checkout payload validation.\n */\n\nimport type { ValidationResult, CheckoutValidationInput } from \"./types\";\n\n/**\n * Validate checkout payload.\n */\nexport function validateCheckout(\n payload: CheckoutValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n if (typeof payload !== \"object\" || payload === null) {\n errors.push(\"Checkout payload must be an object\");\n return { valid: false, errors };\n }\n\n // Amount validation (optional but if provided must be valid)\n if (payload.amount !== undefined && payload.amount !== null) {\n if (typeof payload.amount !== \"number\") {\n errors.push(\"Checkout amount must be a number\");\n } else if (payload.amount < 0) {\n errors.push(\"Checkout amount cannot be negative\");\n }\n }\n\n // Currency validation (optional but if provided must be valid)\n if (payload.currency !== undefined && payload.currency !== null) {\n if (typeof payload.currency !== \"string\") {\n errors.push(\"Checkout currency must be a string\");\n } else if (payload.currency.trim() === \"\") {\n errors.push(\"Checkout currency cannot be empty\");\n }\n }\n\n // Items validation (optional but if provided must be array)\n if (payload.items !== undefined && payload.items !== null) {\n if (!Array.isArray(payload.items)) {\n errors.push(\"Checkout items must be an array\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Page navigation and redirect validation.\n */\n\nimport type {\n ValidationResult,\n NavigateValidationInput,\n RedirectValidationInput,\n} from \"./types\";\n\n/**\n * Validate page navigation options.\n */\nexport function validateNavigate(\n options: NavigateValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Path validation\n if (options.path === undefined || options.path === null) {\n errors.push(\"Navigation path is required\");\n } else if (typeof options.path !== \"string\") {\n errors.push(\"Navigation path must be a string\");\n } else if (options.path.trim() === \"\") {\n errors.push(\"Navigation path cannot be empty\");\n }\n\n // Replace validation (optional)\n if (options.replace !== undefined && typeof options.replace !== \"boolean\") {\n errors.push(\"Navigation replace option must be a boolean\");\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Validate page redirect options.\n */\nexport function validateRedirect(\n options: RedirectValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // URL validation\n if (options.url === undefined || options.url === null) {\n errors.push(\"Redirect URL is required\");\n } else if (typeof options.url !== \"string\") {\n errors.push(\"Redirect URL must be a string\");\n } else if (options.url.trim() === \"\") {\n errors.push(\"Redirect URL cannot be empty\");\n } else {\n // Validate URL format\n try {\n new URL(options.url);\n } catch {\n errors.push(`Invalid redirect URL: \"${options.url}\"`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Nav action validation.\n */\n\nimport type { ValidationResult, NavActionValidationInput } from \"./types\";\n\n/**\n * Validate nav action options.\n */\nexport function validateNavAction(\n options: NavActionValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation (required, non-empty)\n if (!options.title) {\n errors.push(\"Nav action title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Nav action title must be a string\");\n }\n\n // Value validation (required, non-empty)\n if (!options.value) {\n errors.push(\"Nav action value is required\");\n } else if (typeof options.value !== \"string\") {\n errors.push(\"Nav action value must be a string\");\n }\n\n // subTitle validation (optional)\n if (options.subTitle !== undefined && options.subTitle !== null) {\n if (typeof options.subTitle !== \"string\") {\n errors.push(\"Nav action subTitle must be a string\");\n }\n }\n\n // icon validation (optional)\n if (options.icon !== undefined && options.icon !== null) {\n if (typeof options.icon !== \"string\") {\n errors.push(\"Nav action icon must be a string\");\n }\n }\n\n // disabled validation (optional)\n if (options.disabled !== undefined && options.disabled !== null) {\n if (typeof options.disabled !== \"boolean\") {\n errors.push(\"Nav action disabled must be a boolean\");\n }\n }\n\n // Extended actions validation (optional)\n if (\n options.extendedActions !== undefined &&\n options.extendedActions !== null\n ) {\n if (!Array.isArray(options.extendedActions)) {\n errors.push(\"Nav action extendedActions must be an array\");\n } else {\n options.extendedActions.forEach((action: unknown, index: number) => {\n if (typeof action !== \"object\" || action === null) {\n errors.push(`Extended action at index ${index} must be an object`);\n return;\n }\n const ext = action as {\n title?: unknown;\n subTitle?: unknown;\n value?: unknown;\n icon?: unknown;\n disabled?: unknown;\n };\n if (!ext.title || typeof ext.title !== \"string\") {\n errors.push(\n `Extended action at index ${index} is missing required \"title\" property`,\n );\n }\n if (!ext.value || typeof ext.value !== \"string\") {\n errors.push(\n `Extended action at index ${index} is missing required \"value\" property`,\n );\n }\n if (ext.subTitle !== undefined && typeof ext.subTitle !== \"string\") {\n errors.push(\n `Extended action at index ${index} subTitle must be a string`,\n );\n }\n if (ext.icon !== undefined && typeof ext.icon !== \"string\") {\n errors.push(\n `Extended action at index ${index} icon must be a string`,\n );\n }\n if (ext.disabled !== undefined && typeof ext.disabled !== \"boolean\") {\n errors.push(\n `Extended action at index ${index} disabled must be a boolean`,\n );\n }\n });\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Confirm dialog validation.\n */\n\nimport type { ValidationResult, ConfirmValidationInput } from \"./types\";\n\nconst VALID_CONFIRM_VARIANTS = [\"danger\", \"warning\", \"info\"];\n\n/**\n * Validate confirm dialog options.\n */\nexport function validateConfirm(\n options: ConfirmValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation\n if (options.title === undefined || options.title === null) {\n errors.push(\"Confirm dialog title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Confirm dialog title must be a string\");\n } else if (options.title.trim() === \"\") {\n errors.push(\"Confirm dialog title cannot be empty\");\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Confirm dialog message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Confirm dialog message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Confirm dialog message cannot be empty\");\n }\n\n // Confirm text validation (optional)\n if (options.confirmText !== undefined && options.confirmText !== null) {\n if (typeof options.confirmText !== \"string\") {\n errors.push(\"Confirm dialog confirmText must be a string\");\n }\n }\n\n // Cancel text validation (optional)\n if (options.cancelText !== undefined && options.cancelText !== null) {\n if (typeof options.cancelText !== \"string\") {\n errors.push(\"Confirm dialog cancelText must be a string\");\n }\n }\n\n // Variant validation (optional)\n if (options.variant !== undefined && options.variant !== null) {\n if (\n typeof options.variant !== \"string\" ||\n !VALID_CONFIRM_VARIANTS.includes(options.variant)\n ) {\n errors.push(\n `Invalid confirm variant \"${options.variant}\". Expected: ${VALID_CONFIRM_VARIANTS.join(\" | \")}`,\n );\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Validation utility functions.\n */\n\nimport { logger } from \"../logger\";\n\n/**\n * Log validation errors to console with helpful formatting.\n *\n * @param method - The SDK method that failed validation\n * @param errors - Array of error messages\n */\nexport function logValidationErrors(method: string, errors: string[]): void {\n logger.error(\n `Validation failed for ${method}:\\n` +\n errors.map((e) => ` • ${e}`).join(\"\\n\"),\n );\n}\n","/**\n * @fileoverview Page module for navigation and resize.\n */\n\nimport { IFRAME_EVENTS } from \"../../core/events\";\nimport { postToHost } from \"../../core/messenger\";\nimport {\n validateNavigate,\n validateRedirect,\n logValidationErrors,\n} from \"../../core/validation\";\nimport { PAGE_EVENTS } from \"./events\";\nimport type { PageModule, NavToOptions } from \"./types\";\n\nexport type { PageModule, NavToOptions } from \"./types\";\n\n/**\n * Create the page module.\n *\n * @returns Page module instance\n */\nexport function createPageModule(): PageModule {\n return {\n /**\n * Navigate to a path using React Router (SPA navigation).\n */\n navigate(path: string, options?: NavToOptions): void {\n const validation = validateNavigate({ path, ...options });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.NAVIGATE, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.NAVIGATE, {\n path,\n state: options?.state,\n replace: options?.replace,\n });\n },\n\n /**\n * Redirect to a URL (full page reload).\n */\n redirect(url: string): void {\n const validation = validateRedirect({ url });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.REDIRECT, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.REDIRECT, { url });\n },\n\n /**\n * Navigate to a path - auto-detects internal vs external.\n */\n navTo(path: string, options?: NavToOptions): void {\n // External URLs use redirect\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n this.redirect(path);\n return;\n }\n\n // Internal navigation\n this.navigate(path, options);\n },\n\n /**\n * Update the iframe height.\n */\n resize(height: number): void {\n if (typeof height !== \"number\" || height < 0) {\n logValidationErrors(IFRAME_EVENTS.RESIZE, [\n \"Height must be a non-negative number\",\n ]);\n return;\n }\n postToHost(IFRAME_EVENTS.RESIZE, { height });\n },\n\n /**\n * Auto-resize iframe to content height.\n */\n autoResize(): void {\n const height = document.documentElement.scrollHeight;\n this.resize(height);\n },\n\n /**\n * Set the page title in the host document.\n */\n setTitle(title: string): void {\n if (typeof title !== \"string\" || !title.trim()) {\n logValidationErrors(PAGE_EVENTS.SET_TITLE, [\n \"Title must be a non-empty string\",\n ]);\n return;\n }\n postToHost(PAGE_EVENTS.SET_TITLE, { title });\n },\n };\n}\n","/**\n * @fileoverview Nav module for navigation actions.\n */\n\nimport { postToHost, onMessage } from \"../../core/messenger\";\nimport { validateNavAction, logValidationErrors } from \"../../core/validation\";\nimport type { NavActionClickMessage, Unsubscribe } from \"../../core/types\";\nimport { NAV_EVENTS } from \"./events\";\nimport { logger } from \"../../core/logger\";\nimport type {\n NavModule,\n PrimaryActionConfig,\n ActionClickCallback,\n} from \"./types\";\n\nexport type { NavModule, PrimaryActionConfig } from \"./types\";\n\n/**\n * Create the nav module.\n *\n * @returns Nav module instance\n */\nexport function createNavModule(): NavModule {\n const clickCallbacks = new Set<ActionClickCallback>();\n\n // Set up listener for action click events from host\n onMessage<NavActionClickMessage>(NAV_EVENTS.ACTION_CLICK, (data) => {\n // Call all registered callbacks with the action value\n clickCallbacks.forEach((callback) => {\n try {\n callback(data.payload.value);\n } catch (error) {\n logger.error(\"Error in action click callback:\", error);\n }\n });\n });\n\n const navModule: NavModule = {\n /**\n * Set the primary action button.\n */\n setAction(config: PrimaryActionConfig): void {\n const validation = validateNavAction(config);\n if (!validation.valid) {\n logValidationErrors(NAV_EVENTS.SET_ACTION, validation.errors);\n return;\n }\n\n postToHost(NAV_EVENTS.SET_ACTION, {\n title: config.title,\n value: config.value,\n subTitle: config.subTitle,\n icon: config.icon,\n disabled: config.disabled,\n extendedActions: config.extendedActions?.map((ext) => ({\n title: ext.title,\n value: ext.value,\n subTitle: ext.subTitle,\n icon: ext.icon,\n disabled: ext.disabled,\n })),\n });\n },\n\n /**\n * Clear the primary action button.\n */\n clearAction(): void {\n postToHost(NAV_EVENTS.CLEAR_ACTION, {});\n },\n\n /**\n * Subscribe to action button clicks.\n */\n onActionClick(callback: ActionClickCallback): Unsubscribe {\n clickCallbacks.add(callback);\n return () => {\n clickCallbacks.delete(callback);\n };\n },\n };\n\n return navModule;\n}\n","/**\n * @fileoverview Loading component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { UI_EVENTS } from \"../events\";\nimport type { LoadingSubModule } from \"../types\";\n\n/**\n * Create the loading sub-module.\n */\nexport function createLoadingSubModule(): LoadingSubModule {\n return {\n /**\n * Show loading indicator.\n */\n show(): void {\n postToHost(UI_EVENTS.LOADING, { action: \"show\" });\n },\n\n /**\n * Hide loading indicator.\n */\n hide(): void {\n postToHost(UI_EVENTS.LOADING, { action: \"hide\" });\n },\n };\n}\n","/**\n * @fileoverview Toast notification component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { validateToast, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ToastSubModule, ToastOptions } from \"../types\";\n\n/**\n * Create the toast sub-module.\n */\nexport function createToastSubModule(): ToastSubModule {\n const showToast = (options: ToastOptions): void => {\n const validation = validateToast(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.TOAST, validation.errors);\n return;\n }\n postToHost(UI_EVENTS.TOAST, {\n type: options.type,\n message: options.message,\n duration: options.duration,\n });\n };\n\n return {\n /**\n * Show a toast notification.\n */\n show: showToast,\n\n /**\n * Show success toast.\n */\n success(message: string, duration?: number): void {\n showToast({ type: \"success\", message, duration });\n },\n\n /**\n * Show error toast.\n */\n error(message: string, duration?: number): void {\n showToast({ type: \"error\", message, duration });\n },\n\n /**\n * Show warning toast.\n */\n warning(message: string, duration?: number): void {\n showToast({ type: \"warning\", message, duration });\n },\n\n /**\n * Show info toast.\n */\n info(message: string, duration?: number): void {\n showToast({ type: \"info\", message, duration });\n },\n };\n}\n","/**\n * @fileoverview Confirm dialog component.\n */\n\nimport { sendRequest } from \"../../../core/requests\";\nimport { validateConfirm, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ConfirmOptions, ConfirmResult } from \"../../../core/types\";\n\n/**\n * Create the confirm function.\n */\nexport function createConfirmFunction(): (\n options: ConfirmOptions,\n) => Promise<ConfirmResult> {\n return async (options: ConfirmOptions): Promise<ConfirmResult> => {\n const validation = validateConfirm(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.CONFIRM, validation.errors);\n return Promise.reject(new Error(validation.errors.join(\", \")));\n }\n\n return sendRequest<ConfirmResult>(UI_EVENTS.CONFIRM, {\n title: options.title,\n message: options.message,\n confirmText: options.confirmText ?? \"Confirm\",\n cancelText: options.cancelText ?? \"Cancel\",\n variant: options.variant ?? \"info\",\n });\n };\n}\n","/**\n * @fileoverview UI module with nested sub-modules for loading, toast, and confirm.\n */\n\nimport {\n createLoadingSubModule,\n createToastSubModule,\n createConfirmFunction,\n} from \"./components\";\nimport type { UIModule } from \"./types\";\n\nexport type {\n UIModule,\n LoadingSubModule,\n ToastSubModule,\n LoadingMode,\n ToastOptions,\n ToastType,\n} from \"./types\";\n\n/**\n * Create the UI module with nested sub-modules.\n *\n * @returns UI module instance\n */\nexport function createUIModule(): UIModule {\n return {\n loading: createLoadingSubModule(),\n toast: createToastSubModule(),\n confirm: createConfirmFunction(),\n };\n}\n","/**\n * @fileoverview Checkout module for checkout flow integration.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { validateCheckout, logValidationErrors } from \"../../core/validation\";\nimport { CHECKOUT_EVENTS } from \"./events\";\nimport type { CheckoutModule, CheckoutPayload } from \"./types\";\n\nexport type { CheckoutModule, CheckoutPayload } from \"./types\";\n\n/**\n * Create the checkout module.\n *\n * @returns Checkout module instance\n */\nexport function createCheckoutModule(): CheckoutModule {\n return {\n /**\n * Create/initiate a checkout.\n */\n create(payload: CheckoutPayload): void {\n const validation = validateCheckout(payload);\n if (!validation.valid) {\n logValidationErrors(CHECKOUT_EVENTS.CREATE, validation.errors);\n return;\n }\n postToHost(CHECKOUT_EVENTS.CREATE, payload);\n },\n };\n}\n","/**\n * @fileoverview Main EmbeddedApp singleton class.\n * This is the core of the SDK that manages initialization and state.\n */\n\nimport { IFRAME_EVENTS, CONTEXT_EVENTS } from \"./events\";\nimport { UI_EVENTS } from \"../modules/ui/events\";\nimport {\n postToHost,\n waitForMessage,\n removeAllListeners,\n isInIframe,\n onMessage,\n} from \"./messenger\";\nimport type {\n InitOptions,\n EmbeddedConfig,\n EmbeddedState,\n LayoutInfo,\n ContextProvideResponse,\n ThemeChangeMessage,\n ConfirmResponseMessage,\n InitCallback,\n} from \"./types\";\nimport { handleResponse, cancelAllRequests } from \"./requests\";\nimport { logger, setLoggerConfig } from \"./logger\";\n\n// Import modules\nimport { createAuthModule, type AuthModule } from \"../modules/auth\";\nimport { createPageModule, type PageModule } from \"../modules/page\";\nimport { createNavModule, type NavModule } from \"../modules/nav\";\nimport { createUIModule, type UIModule } from \"../modules/ui\";\nimport { createCheckoutModule, type CheckoutModule } from \"../modules/checkout\";\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG: EmbeddedConfig = {\n debug: false,\n initialized: false,\n};\n\n/**\n * Default layout values.\n */\nconst DEFAULT_LAYOUT: LayoutInfo = {\n theme: \"light\",\n width: 0,\n locale: \"ar\",\n currency: \"SAR\",\n};\n\n/**\n * Default state values.\n */\nconst DEFAULT_STATE: EmbeddedState = {\n ready: false,\n initializing: false,\n layout: { ...DEFAULT_LAYOUT },\n};\n\n/**\n * Theme change callback type.\n */\ntype ThemeChangeCallback = (theme: \"light\" | \"dark\") => void;\n\n/**\n * Main Embedded SDK class.\n * Provides the primary interface for third-party apps to communicate with the Salla host.\n */\nclass EmbeddedApp {\n private config: EmbeddedConfig = { ...DEFAULT_CONFIG };\n private state: EmbeddedState = { ...DEFAULT_STATE };\n private themeCallbacks: Set<ThemeChangeCallback> = new Set();\n private initCallbacks: Set<InitCallback> = new Set();\n private appReady: boolean = false;\n\n /** Auth module for token management */\n public auth: AuthModule;\n\n /** Page module for navigation and resize */\n public page: PageModule;\n\n /** Nav module for primary actions */\n public nav: NavModule;\n\n /** UI module for loading, overlay, toast, modal */\n public ui: UIModule;\n\n /** Checkout module for checkout flow */\n public checkout: CheckoutModule;\n\n constructor() {\n // Initialize modules with reference to this instance\n this.auth = createAuthModule(() => this.getState());\n this.page = createPageModule();\n this.nav = createNavModule();\n this.ui = createUIModule();\n this.checkout = createCheckoutModule();\n\n // Set up event listeners\n this.setupThemeListener();\n this.setupResponseListeners();\n }\n\n /**\n * Get current SDK state (layout info only, no token).\n */\n getState(): Readonly<EmbeddedState> {\n return {\n ready: this.state.ready,\n initializing: this.state.initializing,\n layout: { ...this.state.layout },\n };\n }\n\n /**\n * Get current SDK configuration.\n */\n getConfig(): Readonly<EmbeddedConfig> {\n return { ...this.config };\n }\n\n /**\n * Check if SDK is initialized.\n */\n isReady(): boolean {\n return this.state.ready;\n }\n\n /**\n * Unified internal logging function that supports all console log types.\n *\n * @param type - Log type (log, warn, error, info, debug)\n * @param args - Arguments to log\n */\n private internalLog(\n type: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\",\n ...args: unknown[]\n ): void {\n switch (type) {\n case \"log\":\n logger.log(...args);\n break;\n case \"warn\":\n logger.warn(...args);\n break;\n case \"error\":\n logger.error(...args);\n break;\n case \"info\":\n logger.info(...args);\n break;\n case \"debug\":\n logger.debug(...args);\n break;\n }\n }\n\n /**\n * Set up listener for theme changes from host.\n */\n private setupThemeListener(): void {\n onMessage<ThemeChangeMessage>(CONTEXT_EVENTS.THEME_CHANGE, (data) => {\n this.state.layout.theme = data.payload.theme;\n this.internalLog(\"debug\", \"Theme changed:\", data.payload.theme);\n\n // Notify all theme callbacks\n this.themeCallbacks.forEach((callback) => {\n try {\n callback(data.payload.theme);\n } catch (error) {\n this.internalLog(\"error\", \"Error in theme callback:\", error);\n }\n });\n });\n }\n\n /**\n * Set up listeners for async response events from host.\n */\n private setupResponseListeners(): void {\n // Listen for confirm dialog responses\n onMessage<ConfirmResponseMessage>(UI_EVENTS.CONFIRM_RESPONSE, (data) => {\n this.internalLog(\"debug\", \"Received confirm response:\", data);\n if (data.requestId) {\n handleResponse(data.requestId, { confirmed: data.payload.confirmed });\n }\n });\n }\n\n /**\n * Subscribe to theme changes.\n *\n * @param callback - Function called when theme changes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = embedded.onThemeChange((theme) => {\n * document.body.classList.toggle('dark-mode', theme === 'dark');\n * });\n * ```\n */\n onThemeChange(callback: ThemeChangeCallback): () => void {\n this.themeCallbacks.add(callback);\n return () => {\n this.themeCallbacks.delete(callback);\n };\n }\n\n /**\n * Subscribe to init completion. If called after init, fires immediately.\n *\n * @param callback - Function called when init completes\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * embedded.onInit((state) => {\n * console.log('SDK initialized with layout:', state.layout);\n * });\n * ```\n */\n onInit(callback: InitCallback): () => void {\n // If already initialized, fire immediately\n if (this.config.initialized) {\n try {\n callback(this.getState());\n } catch (error) {\n this.internalLog(\"error\", \"Error in init callback:\", error);\n }\n }\n\n this.initCallbacks.add(callback);\n return () => {\n this.initCallbacks.delete(callback);\n };\n }\n\n /**\n * Signal that the app is fully loaded and ready.\n * This removes the host's loading overlay.\n *\n * @example\n * ```typescript\n * // After verifying token and loading initial data\n * embedded.ready();\n * ```\n */\n ready(): void {\n if (this.appReady) {\n this.internalLog(\"debug\", \"App already signaled as ready\");\n return;\n }\n\n if (!this.config.initialized) {\n this.internalLog(\"warn\", \"Cannot signal ready before init() is called\");\n return;\n }\n\n this.appReady = true;\n postToHost(IFRAME_EVENTS.READY, {});\n this.internalLog(\"debug\", \"Sent ready signal to host\");\n }\n\n /**\n * Initialize the SDK and establish connection with the host.\n *\n * @param options - Initialization options (optional)\n * @returns Promise that resolves with layout info\n *\n * @example\n * ```typescript\n * const { layout } = await embedded.init({ debug: true });\n * console.log('Theme:', layout.theme);\n * console.log('Locale:', layout.locale);\n * ```\n */\n async init(options: InitOptions = {}): Promise<{ layout: LayoutInfo }> {\n // Check if already initialized\n if (this.config.initialized) {\n this.internalLog(\n \"debug\",\n \"Already initialized, returning current layout\",\n );\n return { layout: { ...this.state.layout } };\n }\n\n // Check if initialization is in progress\n if (this.state.initializing) {\n this.internalLog(\"warn\", \"Initialization already in progress\");\n return this.waitForInit();\n }\n\n // Check if running in iframe\n if (!isInIframe()) {\n this.internalLog(\n \"warn\",\n \"Not running in an iframe. Some features may not work.\",\n );\n }\n\n // Set configuration\n this.config = {\n debug: options.debug ?? false,\n initialized: false,\n };\n\n // Update logger configuration\n setLoggerConfig({\n debug: this.config.debug,\n });\n\n this.state.initializing = true;\n\n this.internalLog(\"debug\", \"Initializing SDK...\");\n\n try {\n // Send ready message to host\n postToHost(IFRAME_EVENTS.INIT, {\n height: document.documentElement.scrollHeight,\n });\n\n this.internalLog(\n \"debug\",\n \"Sent iframe.ready message, waiting for context...\",\n );\n\n // Wait for host to provide context\n const response = await waitForMessage<ContextProvideResponse>(\n CONTEXT_EVENTS.PROVIDE,\n );\n\n this.internalLog(\"debug\", \"Received context from host:\", response);\n\n // Update state with layout data\n const layout = response.payload.layout;\n this.state = {\n ready: true,\n initializing: false,\n layout: {\n theme: layout?.theme ?? \"light\",\n width: layout?.width ?? 0,\n locale: layout?.locale ?? \"ar\",\n currency: layout?.currency ?? \"SAR\",\n },\n };\n\n this.config.initialized = true;\n\n this.internalLog(\n \"debug\",\n \"Initialization complete. Layout:\",\n this.state.layout,\n );\n\n // Notify all init callbacks\n const state = this.getState();\n this.initCallbacks.forEach((callback) => {\n try {\n callback(state);\n } catch (error) {\n this.internalLog(\"error\", \"Error in init callback:\", error);\n }\n });\n\n return { layout: { ...this.state.layout } };\n } catch (error) {\n this.state.initializing = false;\n this.state.ready = false;\n\n throw error;\n }\n }\n\n /**\n * Wait for initialization to complete.\n * Useful when multiple calls to init() might happen.\n */\n private waitForInit(): Promise<{ layout: LayoutInfo }> {\n return new Promise((resolve) => {\n const unsubscribe = this.onInit((state) => {\n unsubscribe();\n resolve({ layout: { ...state.layout } });\n });\n });\n }\n\n /**\n * Destroy the SDK instance and clean up resources.\n * Sends a destroy event to the host to navigate away from the embedded view.\n *\n * @example\n * ```typescript\n * // On auth failure or when app needs to exit\n * embedded.destroy();\n * ```\n */\n destroy(): void {\n this.internalLog(\"debug\", \"Destroying SDK instance\");\n\n // Send destroy event to host (navigates to app page)\n if (this.config.initialized) {\n postToHost(IFRAME_EVENTS.DESTROY, {});\n this.internalLog(\"debug\", \"Sent destroy event to host\");\n }\n\n // Clean up internal state\n cancelAllRequests(\"SDK destroyed\");\n removeAllListeners();\n this.themeCallbacks.clear();\n this.initCallbacks.clear();\n this.config = { ...DEFAULT_CONFIG };\n this.state = { ...DEFAULT_STATE };\n this.appReady = false;\n }\n}\n\n// Singleton instance\nlet instance: EmbeddedApp | null = null;\n\n/**\n * Get the singleton EmbeddedApp instance.\n */\nexport function getEmbeddedApp(): EmbeddedApp {\n if (!instance) {\n instance = new EmbeddedApp();\n }\n return instance;\n}\n\n/**\n * Reset the singleton (mainly for testing).\n */\nexport function resetEmbeddedApp(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n\nexport { EmbeddedApp };\n","/**\n * @fileoverview Main entry point for the Salla Embedded SDK.\n *\n * This SDK provides a communication bridge between embedded third-party apps\n * and the Salla Dashboard host.\n *\n * @example Using window global\n * ```typescript\n * await salla.embedded.init({ debug: true });\n * salla.embedded.ui.loading.hide();\n * ```\n *\n * @example Using ES module import\n * ```typescript\n * import { embedded } from '@salla.sa/embedded-sdk';\n * await embedded.init({ debug: true });\n * ```\n */\n\nimport { getEmbeddedApp, EmbeddedApp } from \"./core/EmbeddedApp\";\nimport { SDK_VERSION } from \"./core/constants\";\n\n// Re-export types\nexport type {\n InitOptions,\n EmbeddedState,\n ExtendedAction,\n ToastType,\n ConfirmOptions,\n ConfirmResult,\n ConfirmVariant,\n} from \"./core/types\";\n\n// Re-export validation types for advanced use cases\nexport type { ValidationResult } from \"./core/validation\";\n\nexport type { AuthModule } from \"./modules/auth\";\nexport type { PageModule, NavToOptions } from \"./modules/page\";\nexport type { NavModule, PrimaryActionConfig } from \"./modules/nav\";\nexport type { UIModule, LoadingMode, ToastOptions } from \"./modules/ui\";\nexport type { CheckoutModule, CheckoutPayload } from \"./modules/checkout\";\n\n// Export the singleton instance\nexport const embedded = getEmbeddedApp();\n\n// Export version and events\nexport const version = SDK_VERSION;\n\n// Export class for advanced use cases\nexport { EmbeddedApp };\n\n// Re-export getEmbeddedApp for advanced use cases\nexport { getEmbeddedApp, resetEmbeddedApp } from \"./core/EmbeddedApp\";\n\n// ============================================================================\n// Window Global Setup\n// ============================================================================\n\n/**\n * Salla interface extension for the embedded SDK.\n */\ninterface SallaEmbedded {\n embedded: EmbeddedApp;\n}\n\ndeclare global {\n interface Window {\n salla: SallaEmbedded & Record<string, unknown>;\n Salla: SallaEmbedded & Record<string, unknown>;\n }\n}\n\n/**\n * Set up window globals.\n * Supports both window.salla.embedded and window.Salla.embedded\n */\nif (typeof window !== \"undefined\") {\n // Initialize salla object if it doesn't exist\n window.salla = window.salla || window.Salla || {};\n window.Salla = window.salla;\n\n // Attach embedded SDK\n if (!window.salla.embedded) {\n window.salla.embedded = embedded;\n }\n if (!window.Salla.embedded) {\n window.Salla.embedded = embedded;\n }\n}\n"],"names":["EVENT_PREFIX","IFRAME_EVENTS","CONTEXT_EVENTS","UI_EVENTS","AUTH_EVENTS","PAGE_EVENTS","NAV_EVENTS","CHECKOUT_EVENTS","SDK_VERSION","pkg","DEFAULT_TIMEOUT","TRUSTED_DOMAINS","loggerConfig","setLoggerConfig","config","createBadge","text","getBadgeStyle","backgroundColor","textColor","log","type","args","badges","styles","badgeString","logger","isTrustedOrigin","origin","hostname","domain","getParentWindow","postToHost","event","data","targetOrigin","requestId","metadata","parent","message","listeners","isListening","handleMessage","eventListeners","callback","error","wildcardListeners","startListening","onMessage","waitForMessage","timeout","resolve","reject","timer","unsubscribe","removeAllListeners","isInIframe","pendingRequests","DEFAULT_REQUEST_TIMEOUT","generateRequestId","timestamp","random","sendRequest","handleResponse","result","pending","cancelAllRequests","reason","API_BASE_URL","ApiError","status","response","apiRequest","endpoint","options","method","headers","body","url","controller","timeoutId","contentType","createErrorResponse","errorMessage","introspect","params","token","appId","refreshOnError","apiResponse","isVerified","getEmbeddedApp","createAuthModule","_getState","introspectFunction","VALID_TOAST_TYPES","validateToast","errors","validateCheckout","payload","validateNavigate","validateRedirect","validateNavAction","action","index","ext","VALID_CONFIRM_VARIANTS","validateConfirm","logValidationErrors","e","createPageModule","path","validation","height","title","createNavModule","clickCallbacks","_a","createLoadingSubModule","createToastSubModule","showToast","duration","createConfirmFunction","createUIModule","createCheckoutModule","DEFAULT_CONFIG","DEFAULT_LAYOUT","DEFAULT_STATE","EmbeddedApp","layout","state","instance","resetEmbeddedApp","embedded","version"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/core/events.ts","../../src/modules/ui/events.ts","../../src/modules/auth/events.ts","../../src/modules/page/events.ts","../../src/modules/nav/events.ts","../../src/modules/checkout/events.ts","../../src/core/constants.ts","../../src/core/logger.ts","../../src/core/messenger.ts","../../src/core/requests.ts","../../src/core/subscriptions.ts","../../src/core/api.ts","../../src/modules/auth/functions/introspect.ts","../../src/modules/auth/index.ts","../../src/core/validation/toast.ts","../../src/core/validation/checkout.ts","../../src/core/validation/navigation.ts","../../src/core/validation/nav-action.ts","../../src/core/validation/confirm.ts","../../src/core/validation/utils.ts","../../src/modules/page/index.ts","../../src/modules/nav/index.ts","../../src/modules/ui/components/loading.ts","../../src/modules/ui/components/toast.ts","../../src/modules/ui/components/confirm.ts","../../src/modules/ui/index.ts","../../src/modules/checkout/index.ts","../../src/core/EmbeddedApp.ts","../../src/index.ts"],"sourcesContent":["/**\n * @fileoverview Core event constants.\n * Event naming convention: `embedded::{module}.{action}`\n */\n\n/**\n * Event prefix for all embedded events.\n */\nexport const EVENT_PREFIX = \"embedded::\" as const;\n\n/**\n * Iframe lifecycle events.\n */\nexport const IFRAME_EVENTS = {\n /** Initialize handshake - iframe signals it's ready to receive context */\n INIT: `${EVENT_PREFIX}iframe.ready`,\n /** Request iframe resize */\n RESIZE: `${EVENT_PREFIX}iframe.resize`,\n /** App signals it's fully loaded and ready */\n READY: `${EVENT_PREFIX}ready`,\n /** App requests to be destroyed and navigate away */\n DESTROY: `${EVENT_PREFIX}destroy`,\n} as const;\n\n/**\n * Context events (Host → Iframe).\n */\nexport const CONTEXT_EVENTS = {\n /** Context data provision */\n PROVIDE: `${EVENT_PREFIX}context.provide`,\n /** Theme change notification */\n THEME_CHANGE: `${EVENT_PREFIX}theme.change`,\n} as const;\n","/**\n * @fileoverview UI module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * UI state events.\n */\nexport const UI_EVENTS = {\n /** Set loading state */\n LOADING: `${EVENT_PREFIX}ui.loading`,\n /** Show toast notification */\n TOAST: `${EVENT_PREFIX}ui.toast`,\n /** Show confirm dialog (async request) */\n CONFIRM: `${EVENT_PREFIX}ui.confirm`,\n /** Confirm dialog response (from host) */\n CONFIRM_RESPONSE: `${EVENT_PREFIX}ui.confirm.response`,\n} as const;\n","/**\n * @fileoverview Authentication module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Authentication events.\n */\nexport const AUTH_EVENTS = {\n /** Request token refresh (re-renders iframe with new token) */\n REFRESH: `${EVENT_PREFIX}auth.refresh`,\n} as const;\n","/**\n * @fileoverview Page module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Page navigation events.\n */\nexport const PAGE_EVENTS = {\n /** Navigate using React Router (SPA navigation) */\n NAVIGATE: `${EVENT_PREFIX}page.navigate`,\n /** Redirect using window.location (full page reload) */\n REDIRECT: `${EVENT_PREFIX}page.redirect`,\n /** Set page title */\n SET_TITLE: `${EVENT_PREFIX}page.setTitle`,\n} as const;\n","/**\n * @fileoverview Nav module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Navigation action events.\n */\nexport const NAV_EVENTS = {\n /** Set primary action button in navbar */\n SET_ACTION: `${EVENT_PREFIX}nav.setAction`,\n /** Clear the primary action button */\n CLEAR_ACTION: `${EVENT_PREFIX}nav.clearAction`,\n /** Notification when action button is clicked (host → iframe) */\n ACTION_CLICK: `${EVENT_PREFIX}nav.actionClick`,\n} as const;\n","/**\n * @fileoverview Checkout module events.\n */\n\nimport { EVENT_PREFIX } from \"../../core/events\";\n\n/**\n * Checkout events.\n */\nexport const CHECKOUT_EVENTS = {\n /** Create checkout flow */\n CREATE: `${EVENT_PREFIX}checkout.create`,\n /** Checkout response from host */\n RESPONSE: `${EVENT_PREFIX}checkout.response`,\n /** Get available addons for the app */\n GET_ADDONS: `${EVENT_PREFIX}checkout.getAddons`,\n /** Get addons response from host */\n GET_ADDONS_RESPONSE: `${EVENT_PREFIX}checkout.getAddons.response`,\n} as const;\n","import pkg from \"../../package.json\" assert { type: \"json\" };\n\n/**\n * @fileoverview Constants for the Embedded SDK.\n * Re-exports all module events for backward compatibility.\n */\n\n// Re-export core events\nexport { EVENT_PREFIX, IFRAME_EVENTS, CONTEXT_EVENTS } from \"./events\";\n\n// Re-export module events\nexport { AUTH_EVENTS } from \"../modules/auth/events\";\nexport { PAGE_EVENTS } from \"../modules/page/events\";\nexport { NAV_EVENTS } from \"../modules/nav/events\";\nexport { UI_EVENTS } from \"../modules/ui/events\";\nexport { CHECKOUT_EVENTS } from \"../modules/checkout/events\";\n\n/**\n * SDK version for debugging and compatibility checks.\n */\nexport const SDK_VERSION: string =\n (pkg as unknown as { version: string }).version || \"\";\n\n/**\n * Default timeout for waiting for host responses (ms).\n */\nexport const DEFAULT_TIMEOUT = 10000;\n\n/**\n * Trusted domains for message validation.\n * The host will validate based on iframe URL, but SDK validates for host messages.\n */\nexport const TRUSTED_DOMAINS = [\n \"localhost\",\n \"merchants.workers.dev\",\n \"s.salla.sa\",\n \".salla.group\",\n \".salla.sa\",\n] as const;\n","/**\n * @fileoverview Unified logging utility for the Embedded SDK.\n */\n\nimport { SDK_VERSION } from \"./constants\";\n\n/**\n * Logger configuration.\n */\ninterface LoggerConfig {\n /** Whether to show the version badge */\n showVersion?: boolean;\n /** Whether debug mode is enabled */\n debug?: boolean;\n}\n\n/**\n * Log level types supported by the logger.\n */\ntype LogType = \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n\n/**\n * Global logger configuration.\n */\nlet loggerConfig: LoggerConfig = {\n showVersion: true,\n debug: false,\n};\n\n/**\n * Set the logger configuration.\n *\n * @param config - Logger configuration options\n */\nexport function setLoggerConfig(config: LoggerConfig): void {\n loggerConfig = { ...loggerConfig, ...config };\n}\n\n/**\n * Get the current logger configuration.\n */\nexport function getLoggerConfig(): Readonly<LoggerConfig> {\n return { ...loggerConfig };\n}\n\n/**\n * Create styled badge for console output.\n *\n * @param text - Badge text\n * @returns Formatted badge string\n */\nfunction createBadge(text: string): string {\n return `%c${text}`;\n}\n\n/**\n * Get CSS styles for a badge.\n *\n * @param backgroundColor - CSS color for background\n * @param textColor - CSS color for text\n * @returns CSS style string\n */\nfunction getBadgeStyle(backgroundColor: string, textColor = \"#fff\"): string {\n return `background-color: ${backgroundColor}; color: ${textColor}; padding: 2px 6px; border-radius: 3px; font-weight: 500; font-size: 11px;`;\n}\n\n/**\n * Unified logging function that supports all console log types.\n *\n * @param type - Log type (log, warn, error, info, debug)\n * @param args - Arguments to log\n */\nexport function log(type: LogType, ...args: unknown[]): void {\n // Skip debug logs if debug mode is disabled\n if (type === \"debug\" && !loggerConfig.debug) {\n return;\n }\n\n const badges: string[] = [];\n const styles: string[] = [];\n\n // Add EmbeddedSDK badge (green)\n badges.push(createBadge(\"EmbeddedSDK\"));\n styles.push(getBadgeStyle(\"#10b981\", \"#fff\"));\n\n // Add version badge (gray) if enabled\n if (loggerConfig.showVersion) {\n badges.push(createBadge(`v${SDK_VERSION}`));\n styles.push(getBadgeStyle(\"#6b7280\", \"#fff\"));\n }\n\n // Combine badges without space\n const badgeString = badges.join(\"\").trim();\n\n // Get the appropriate console method\n const consoleMethod = console[type] || console.log;\n\n // Call console method with badges and styles\n consoleMethod(badgeString, ...styles, ...args);\n}\n\n/**\n * Convenience methods for each log type.\n */\nexport const logger = {\n log: (...args: unknown[]) => {\n log(\"log\", ...args);\n },\n warn: (...args: unknown[]) => {\n log(\"warn\", ...args);\n },\n error: (...args: unknown[]) => {\n log(\"error\", ...args);\n },\n info: (...args: unknown[]) => {\n log(\"info\", ...args);\n },\n debug: (...args: unknown[]) => {\n log(\"debug\", ...args);\n },\n};\n","/**\n * @fileoverview PostMessage utilities for communicating with the host.\n */\n\nimport { DEFAULT_TIMEOUT, SDK_VERSION, TRUSTED_DOMAINS } from \"./constants\";\nimport type { BaseMessage, MessageCallback, Unsubscribe } from \"./types\";\nimport { logger } from \"./logger\";\n\n/**\n * Check if an origin is trusted.\n */\nfunction isTrustedOrigin(origin: string): boolean {\n try {\n const url = new URL(origin);\n const hostname = url.hostname;\n\n return TRUSTED_DOMAINS.some((domain) => {\n if (domain.startsWith(\".\")) {\n // Suffix match (e.g., \".salla.sa\" matches \"app.salla.sa\")\n return hostname.endsWith(domain) || hostname === domain.slice(1);\n }\n // Exact match\n return hostname === domain || hostname.startsWith(`${domain}:`);\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Get the parent window (host) reference.\n * Returns null if not in an iframe.\n */\nfunction getParentWindow(): Window | null {\n if (typeof window === \"undefined\") return null;\n if (window.parent === window) return null;\n return window.parent;\n}\n\n/**\n * Send a message to the host (parent window).\n *\n * @param event - The event name\n * @param data - Additional data to send with the message (will be wrapped in payload)\n * @param targetOrigin - Target origin for security (defaults to \"*\")\n * @param requestId - Optional request ID for request/response patterns\n * @param metadata - Optional metadata for additional context\n */\nexport function postToHost<T extends Record<string, unknown>>(\n event: string,\n data?: T,\n targetOrigin: string = \"*\",\n requestId?: string,\n metadata?: Record<string, unknown>,\n): void {\n const parent = getParentWindow();\n\n if (!parent) {\n logger.warn(\"Not running in an iframe, cannot post to host\");\n return;\n }\n\n const message: BaseMessage = {\n event,\n payload: data || {},\n timestamp: Date.now(),\n source: \"embedded-app\",\n ...(requestId && { requestId }),\n metadata: {\n version: SDK_VERSION,\n ...(metadata || {}),\n },\n };\n\n parent.postMessage(message, targetOrigin);\n}\n\n/**\n * Message listener registry.\n */\nconst listeners: Map<string, Set<MessageCallback>> = new Map();\n\n/**\n * Global message handler.\n */\nlet isListening = false;\n\nfunction handleMessage(event: MessageEvent): void {\n // Validate origin in production\n if (process.env.NODE_ENV === \"production\" && !isTrustedOrigin(event.origin)) {\n return;\n }\n\n const data = event.data as BaseMessage;\n\n // Validate message structure\n if (\n !data ||\n typeof data.event !== \"string\" ||\n !data.payload ||\n typeof data.timestamp !== \"number\" ||\n !data.source\n ) {\n logger.warn(\"Invalid message structure received:\", data);\n return;\n }\n\n const eventListeners = listeners.get(data.event);\n if (eventListeners) {\n eventListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n logger.error(\"Error in message handler:\", error);\n }\n });\n }\n\n // Also notify wildcard listeners\n const wildcardListeners = listeners.get(\"*\");\n if (wildcardListeners) {\n wildcardListeners.forEach((callback) => {\n try {\n callback(data);\n } catch (error) {\n logger.error(\"Error in wildcard handler:\", error);\n }\n });\n }\n}\n\n/**\n * Start listening for messages if not already.\n */\nfunction startListening(): void {\n if (isListening || typeof window === \"undefined\") return;\n\n window.addEventListener(\"message\", handleMessage);\n isListening = true;\n}\n\n/**\n * Subscribe to messages from the host.\n *\n * @param event - The event name to listen for, or \"*\" for all events\n * @param callback - Callback function when message is received\n * @returns Unsubscribe function\n */\nexport function onMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n callback: MessageCallback<T>,\n): Unsubscribe {\n startListening();\n\n if (!listeners.has(event)) {\n listeners.set(event, new Set());\n }\n\n const eventListeners = listeners.get(event)!;\n eventListeners.add(callback as MessageCallback);\n\n return () => {\n eventListeners.delete(callback as MessageCallback);\n if (eventListeners.size === 0) {\n listeners.delete(event);\n }\n };\n}\n\n/**\n * Wait for a specific message from the host.\n *\n * @param event - The event name to wait for\n * @param timeout - Timeout in milliseconds (defaults to DEFAULT_TIMEOUT)\n * @returns Promise that resolves with the message data\n */\nexport function waitForMessage<T extends BaseMessage = BaseMessage>(\n event: string,\n timeout: number = DEFAULT_TIMEOUT,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n unsubscribe();\n reject(new Error(`[EmbeddedSDK] Timeout waiting for \"${event}\" message`));\n }, timeout);\n\n const unsubscribe = onMessage<T>(event, (data) => {\n clearTimeout(timer);\n unsubscribe();\n resolve(data);\n });\n });\n}\n\n/**\n * Remove all message listeners.\n */\nexport function removeAllListeners(): void {\n listeners.clear();\n\n if (isListening && typeof window !== \"undefined\") {\n window.removeEventListener(\"message\", handleMessage);\n isListening = false;\n }\n}\n\n/**\n * Check if running inside an iframe.\n */\nexport function isInIframe(): boolean {\n if (typeof window === \"undefined\") return false;\n return window.parent !== window;\n}\n\n/**\n * Dispatch an event locally to registered listeners without sending via postMessage.\n * Used to trigger listeners with synthetic/internal events.\n *\n * @param event - The event name\n * @param payload - The event payload\n * @param requestId - Optional request ID\n */\nexport function dispatchLocal<T extends Record<string, unknown>>(\n event: string,\n payload: T,\n requestId?: string,\n): void {\n const message: BaseMessage = {\n event,\n payload,\n timestamp: Date.now(),\n source: \"merchant-dashboard\",\n ...(requestId && { requestId }),\n metadata: { version: SDK_VERSION, synthetic: true },\n };\n\n // Dispatch directly to listeners (origin validation not needed for internal events)\n const eventListeners = listeners.get(event);\n eventListeners?.forEach((callback) => {\n try {\n callback(message);\n } catch (error) {\n logger.error(\"Error in message handler:\", error);\n }\n });\n}\n","/**\n * @fileoverview Request-response tracking for async operations over postMessage.\n * Enables Promise-based APIs for operations that need host responses (e.g., confirm dialogs).\n */\n\nimport { postToHost } from \"./messenger\";\nimport { logger } from \"./logger\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Pending request entry with resolve/reject functions and timeout.\n */\ninterface PendingRequest<T = unknown> {\n resolve: (value: T) => void;\n reject: (reason: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n event: string;\n}\n\n// ============================================================================\n// State\n// ============================================================================\n\n/**\n * Map of pending requests by requestId.\n */\nconst pendingRequests = new Map<string, PendingRequest>();\n\n/**\n * Default timeout for requests (30 seconds).\n */\nconst DEFAULT_REQUEST_TIMEOUT = 30000;\n\n// ============================================================================\n// Request ID Generation\n// ============================================================================\n\n/**\n * Generate a unique request ID.\n * Format: req_{timestamp}_{random}\n */\nexport function generateRequestId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 9);\n return `req_${timestamp}_${random}`;\n}\n\n// ============================================================================\n// Request/Response Functions\n// ============================================================================\n\n/**\n * Send a request to the host and return a Promise that resolves when the response is received.\n *\n * @param event - The event name to send\n * @param data - Additional data to send with the request\n * @param timeout - Timeout in milliseconds (defaults to 30000)\n * @returns Promise that resolves with the response data\n *\n * @example\n * ```typescript\n * const result = await sendRequest<{ confirmed: boolean }>(\n * 'embedded::ui.confirm',\n * { title: 'Delete?', message: 'Are you sure?' }\n * );\n * if (result.confirmed) {\n * // User confirmed\n * }\n * ```\n */\nexport function sendRequest<T>(\n event: string,\n data: Record<string, unknown> = {},\n timeout: number = DEFAULT_REQUEST_TIMEOUT,\n): Promise<T> {\n const requestId = generateRequestId();\n\n return new Promise<T>((resolve, reject) => {\n // Set up timeout\n const timer = setTimeout(() => {\n const pending = pendingRequests.get(requestId);\n if (pending) {\n pendingRequests.delete(requestId);\n reject(\n new Error(\n `[EmbeddedSDK] Request \"${event}\" timed out after ${timeout}ms`,\n ),\n );\n }\n }, timeout);\n\n // Store the pending request\n pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timer,\n event,\n });\n\n // Send the request to host with requestId as base field\n postToHost(event, data, \"*\", requestId);\n });\n}\n\n/**\n * Handle a response from the host for a pending request.\n * Called by the message listener when a response event is received.\n *\n * @param requestId - The request ID from the response\n * @param result - The result data to resolve with\n * @param error - Optional error message to reject with\n *\n * @example\n * ```typescript\n * // In message listener:\n * onMessage('embedded::ui.confirm.response', (msg) => {\n * handleResponse(msg.requestId, { confirmed: msg.confirmed });\n * });\n * ```\n */\nexport function handleResponse<T = unknown>(\n requestId: string,\n result: T,\n error?: string,\n): void {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n // Request may have already timed out or been handled\n logger.warn(`Received response for unknown request: ${requestId}`);\n return;\n }\n\n // Clear the timeout\n clearTimeout(pending.timeout);\n\n // Remove from pending requests\n pendingRequests.delete(requestId);\n\n // Resolve or reject the promise\n if (error) {\n pending.reject(new Error(error));\n } else {\n pending.resolve(result);\n }\n}\n\n/**\n * Check if there are any pending requests.\n * Useful for cleanup or debugging.\n */\nexport function hasPendingRequests(): boolean {\n return pendingRequests.size > 0;\n}\n\n/**\n * Get the count of pending requests.\n * Useful for debugging.\n */\nexport function getPendingRequestCount(): number {\n return pendingRequests.size;\n}\n\n/**\n * Cancel all pending requests.\n * Useful for cleanup when the SDK is being destroyed.\n *\n * @param reason - Optional reason for cancellation\n */\nexport function cancelAllRequests(reason: string = \"SDK cleanup\"): void {\n pendingRequests.forEach((pending, requestId) => {\n clearTimeout(pending.timeout);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n });\n pendingRequests.clear();\n}\n\n/**\n * Cancel a specific pending request.\n *\n * @param requestId - The request ID to cancel\n * @param reason - Optional reason for cancellation\n * @returns true if the request was found and cancelled, false otherwise\n */\nexport function cancelRequest(\n requestId: string,\n reason: string = \"Cancelled\",\n): boolean {\n const pending = pendingRequests.get(requestId);\n\n if (!pending) {\n return false;\n }\n\n clearTimeout(pending.timeout);\n pendingRequests.delete(requestId);\n pending.reject(\n new Error(`[EmbeddedSDK] Request ${requestId} cancelled: ${reason}`),\n );\n\n return true;\n}\n","/**\n * @fileoverview Subscription utilities for managing callback sets.\n * Provides a reusable pattern for pub/sub within modules.\n */\n\nimport { logger } from \"./logger\";\n\n/**\n * A subscription manager for typed callbacks.\n */\nexport interface Subscription<T extends (...args: never[]) => void> {\n /** Add a callback and return unsubscribe function */\n subscribe: (callback: T) => () => void;\n /** Notify all subscribers with given arguments */\n notify: (...args: Parameters<T>) => void;\n /** Clear all subscribers */\n clear: () => void;\n /** Get current subscriber count */\n size: () => number;\n}\n\n/**\n * Create a subscription manager for callbacks.\n * Handles subscribe/unsubscribe and safe notification.\n *\n * @example\n * ```typescript\n * const onThemeChange = createSubscription<(theme: string) => void>();\n *\n * const unsubscribe = onThemeChange.subscribe((theme) => {\n * console.log('Theme:', theme);\n * });\n *\n * onThemeChange.notify('dark');\n * unsubscribe();\n * ```\n */\nexport function createSubscription<\n T extends (...args: never[]) => void,\n>(): Subscription<T> {\n const callbacks = new Set<T>();\n\n return {\n subscribe(callback: T): () => void {\n callbacks.add(callback);\n return () => {\n callbacks.delete(callback);\n };\n },\n\n notify(...args: Parameters<T>): void {\n callbacks.forEach((callback) => {\n try {\n callback(...args);\n } catch (error) {\n logger.error(\"Error in subscription callback:\", error);\n }\n });\n },\n\n clear(): void {\n callbacks.clear();\n },\n\n size(): number {\n return callbacks.size;\n },\n };\n}\n","/**\n * @fileoverview API client wrapper for making requests to Salla API.\n */\n\n/**\n * Base URL for Salla API.\n */\nconst API_BASE_URL = \"https://api.salla.dev\";\n\n/**\n * Options for API requests.\n */\nexport interface ApiRequestOptions {\n /** Request method */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n /** Request headers */\n headers?: Record<string, string>;\n /** Request body */\n body?: unknown;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * API error class for handling API request failures.\n */\nexport class ApiError extends Error {\n constructor(\n message: string,\n public status?: number,\n public response?: unknown,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\n/**\n * Make a request to the Salla API.\n *\n * @param endpoint - API endpoint path (e.g., \"/exchange-authority/v1/introspect\")\n * @param options - Request options\n * @returns Promise that resolves with the response data\n * @throws {ApiError} If the request fails\n *\n * @example\n * ```typescript\n * const response = await apiRequest(\"/exchange-authority/v1/introspect\", {\n * method: \"POST\",\n * headers: { \"S-Source\": \"app-id\", \"Content-Type\": \"application/json\" },\n * body: { token: \"xxx\", env: \"prod\" }\n * });\n * ```\n */\nexport async function apiRequest<T = unknown>(\n endpoint: string,\n options: ApiRequestOptions = {},\n): Promise<T> {\n const { method = \"GET\", headers = {}, body, timeout = 30000 } = options;\n\n const url = `${API_BASE_URL}${endpoint}`;\n\n // Create AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...headers,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n let data: unknown;\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n // Check if response is successful\n if (!response.ok) {\n throw new ApiError(\n `API request failed: ${response.statusText}`,\n response.status,\n data,\n );\n }\n\n return data as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ApiError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new ApiError(`Request timeout after ${timeout}ms`);\n }\n throw new ApiError(`Request failed: ${error.message}`);\n }\n\n throw new ApiError(\"Unknown error occurred\");\n }\n}\n","/**\n * @fileoverview Introspect function for token verification.\n */\n\nimport { apiRequest } from \"../../../core/api\";\nimport { logger } from \"../../../core/logger\";\nimport { getEmbeddedApp } from \"../../../core/EmbeddedApp\";\nimport { postToHost } from \"../../../core/messenger\";\nimport { AUTH_EVENTS } from \"../events\";\nimport type { IntrospectResponse, IntrospectResponseData } from \"../types\";\n\n/**\n * Raw API response from the introspect endpoint.\n */\ninterface RawIntrospectApiResponse {\n status: number;\n success: boolean;\n data: IntrospectResponseData;\n}\n\n/**\n * Options for the introspect function.\n */\nexport interface IntrospectParams {\n /** Application ID (audience) */\n appId: string;\n /** Short-lived token */\n token: string;\n /** Automatically refresh token on error (default: true) */\n refreshOnError?: boolean;\n}\n\n/**\n * Create error response for introspect.\n */\nfunction createErrorResponse(errorMessage: unknown): IntrospectResponse {\n return {\n isVerified: false,\n isError: true,\n error: errorMessage,\n data: null,\n };\n}\n\n/**\n * Introspect (verify) a short-lived token with Salla's API.\n * This function verifies the token and returns token information.\n *\n * @param params - Introspect parameters including token, appId, and refreshOnError\n * @returns Promise that resolves with the introspect response\n */\nexport async function introspect(\n params: IntrospectParams,\n): Promise<IntrospectResponse> {\n const { token, appId, refreshOnError = true } = params;\n\n if (!token) {\n const errorMessage =\n \"Token is required. Provide it as a parameter or in URL as ?token=XXX\";\n logger.error(\"Error in introspect:\", errorMessage);\n return createErrorResponse(errorMessage);\n }\n\n if (!appId) {\n const errorMessage =\n \"App ID is required. Provide it as a parameter or in URL as ?app_id=XXX\";\n logger.error(\"Error in introspect:\", errorMessage);\n return createErrorResponse(errorMessage);\n }\n\n try {\n const apiResponse = await apiRequest<RawIntrospectApiResponse>(\n \"/exchange-authority/v1/introspect\",\n {\n method: \"POST\",\n headers: {\n \"S-Source\": appId,\n \"Content-Type\": \"application/json\",\n },\n body: {\n env: \"prod\",\n token,\n iss: \"merchant-dashboard\",\n subject: \"embedded-page\",\n },\n },\n );\n\n // Transform API response to SDK response format\n const isVerified = apiResponse.success;\n return {\n isVerified,\n isError: !isVerified,\n error: !isVerified ? \"API request failed\" : undefined,\n data: isVerified ? apiResponse.data : null,\n };\n } catch (error) {\n // Default error handler: refresh token if refreshOnError is enabled\n if (refreshOnError) {\n getEmbeddedApp().ui.toast.error(error?.toString() ?? \"Introspect error\");\n postToHost(AUTH_EVENTS.REFRESH, {});\n }\n logger.error(\"Error in introspect:\", error);\n\n // Resolve with error response instead of rejecting\n const errorMessage =\n error instanceof Error\n ? error.message\n : typeof error === \"string\"\n ? error\n : error;\n\n return createErrorResponse(errorMessage);\n }\n}\n","/**\n * @fileoverview Auth module for token and authentication management.\n */\n\nimport { postToHost } from \"../../core/messenger\";\nimport { AUTH_EVENTS } from \"./events\";\nimport type {\n AuthModule,\n StateGetter,\n IntrospectOptions,\n IntrospectResponse,\n} from \"./types\";\nimport { introspect as introspectFunction } from \"./functions/introspect\";\n\nexport type {\n AuthModule,\n IntrospectOptions,\n IntrospectResponse,\n} from \"./types\";\n\n/**\n * Create the auth module.\n *\n * @param _getState - Function to get current SDK state (kept for consistency)\n * @returns Auth module instance\n */\nexport function createAuthModule(_getState: StateGetter): AuthModule {\n return {\n /**\n * Get the token from the URL query parameter.\n * The token is passed to the iframe via ?token=XXX\n *\n * @example\n * ```typescript\n * const token = embedded.auth.getToken();\n * if (token) {\n * await verifyWithBackend(token);\n * }\n * ```\n */\n getToken(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"token\");\n },\n\n /**\n * Get the app ID from the URL query parameter.\n * The app ID is passed to the iframe via ?app_id=XXX\n */\n getAppId(): string | null {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"app_id\");\n },\n\n /**\n * Request a token refresh from the host.\n * This will re-render the iframe with a new token URL.\n *\n * @example\n * ```typescript\n * // When token is about to expire\n * embedded.auth.refresh();\n * ```\n */\n refresh(): void {\n postToHost(AUTH_EVENTS.REFRESH, {});\n },\n\n /**\n * Introspect (verify) a short-lived token with Salla's API.\n * This method verifies the token and returns token information.\n *\n * @param options - Optional parameters (appId, token, and refreshOnError). If not provided, will be extracted from URL params.\n * @returns Promise that resolves with the introspect response. On API error, resolves with isVerified: false, isError: true, and empty data.\n */\n async introspect(\n options: IntrospectOptions = {},\n ): Promise<IntrospectResponse> {\n const token = options.token ?? this.getToken() ?? \"\";\n const appId = options.appId ?? this.getAppId() ?? \"\";\n return introspectFunction({\n token,\n appId,\n refreshOnError: options.refreshOnError,\n });\n },\n };\n}\n","/**\n * @fileoverview Toast notification validation.\n */\n\nimport type { ToastType } from \"../types\";\nimport type { ValidationResult, ToastValidationInput } from \"./types\";\n\nconst VALID_TOAST_TYPES: ToastType[] = [\"success\", \"error\", \"warning\", \"info\"];\n\n/**\n * Validate toast notification options.\n */\nexport function validateToast(options: ToastValidationInput): ValidationResult {\n const errors: string[] = [];\n\n // Type validation\n if (options.type === undefined || options.type === null) {\n errors.push(\"Toast type is required\");\n } else if (\n typeof options.type !== \"string\" ||\n !VALID_TOAST_TYPES.includes(options.type as ToastType)\n ) {\n errors.push(\n `Invalid toast type \"${options.type}\". Expected: ${VALID_TOAST_TYPES.join(\" | \")}`,\n );\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Toast message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Toast message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Toast message cannot be empty\");\n }\n\n // Duration validation (optional)\n if (options.duration !== undefined && options.duration !== null) {\n if (typeof options.duration !== \"number\") {\n errors.push(\"Toast duration must be a number\");\n } else if (options.duration < 0) {\n errors.push(\"Toast duration cannot be negative\");\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Checkout payload validation.\n * Supports both single item (current API) and items array (future API).\n */\n\nimport type {\n ValidationResult,\n CheckoutValidationInput,\n CheckoutItemValidationInput,\n} from \"./types\";\n\n/**\n * Validate a single checkout item.\n *\n * @param item - The item to validate\n * @param label - Label for error messages (e.g., \"Item\" or \"Item at index 0\")\n */\nfunction validateItem(\n item: CheckoutItemValidationInput,\n label: string,\n): string[] {\n const errors: string[] = [];\n\n if (typeof item !== \"object\" || item === null) {\n errors.push(`${label} must be an object`);\n return errors;\n }\n\n if (typeof item.type !== \"string\" || item.type.trim() === \"\") {\n errors.push(`${label} must have a valid type`);\n }\n\n if (typeof item.slug !== \"string\" || item.slug.trim() === \"\") {\n errors.push(`${label} must have a valid slug`);\n }\n\n if (\n item.quantity !== undefined &&\n (typeof item.quantity !== \"number\" || item.quantity < 1)\n ) {\n errors.push(`${label} must have a quantity >= 1`);\n }\n\n return errors;\n}\n\n/**\n * Validate checkout options.\n * Supports both single item format (current) and items array (future).\n *\n * Single item format: { item: { type, slug, quantity? }, context? }\n * Array format: { items: [{ type, slug, quantity? }], context? }\n */\nexport function validateCheckout(\n payload: CheckoutValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n if (typeof payload !== \"object\" || payload === null) {\n errors.push(\"Checkout options must be an object\");\n return { valid: false, errors };\n }\n\n // Support both single item (item) and array (items) formats\n const hasSingleItem = \"item\" in payload;\n const hasItemsArray = \"items\" in payload;\n\n if (!hasSingleItem && !hasItemsArray) {\n errors.push(\"Checkout requires either 'item' or 'items'\");\n return { valid: false, errors };\n }\n\n // Single item format (current API)\n if (hasSingleItem) {\n const itemErrors = validateItem(\n payload.item as CheckoutItemValidationInput,\n \"Item\",\n );\n errors.push(...itemErrors);\n return { valid: errors.length === 0, errors };\n }\n\n // Array format (future API)\n if (!Array.isArray(payload.items)) {\n errors.push(\"Checkout items must be an array\");\n return { valid: false, errors };\n }\n\n if (payload.items.length === 0) {\n errors.push(\"At least one item is required\");\n return { valid: false, errors };\n }\n\n // Validate each item\n payload.items.forEach((item, index) => {\n const itemErrors = validateItem(\n item as CheckoutItemValidationInput,\n `Item at index ${index}`,\n );\n errors.push(...itemErrors);\n });\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Page navigation and redirect validation.\n */\n\nimport type {\n ValidationResult,\n NavigateValidationInput,\n RedirectValidationInput,\n} from \"./types\";\n\n/**\n * Validate page navigation options.\n */\nexport function validateNavigate(\n options: NavigateValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Path validation\n if (options.path === undefined || options.path === null) {\n errors.push(\"Navigation path is required\");\n } else if (typeof options.path !== \"string\") {\n errors.push(\"Navigation path must be a string\");\n } else if (options.path.trim() === \"\") {\n errors.push(\"Navigation path cannot be empty\");\n }\n\n // Replace validation (optional)\n if (options.replace !== undefined && typeof options.replace !== \"boolean\") {\n errors.push(\"Navigation replace option must be a boolean\");\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Validate page redirect options.\n */\nexport function validateRedirect(\n options: RedirectValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // URL validation\n if (options.url === undefined || options.url === null) {\n errors.push(\"Redirect URL is required\");\n } else if (typeof options.url !== \"string\") {\n errors.push(\"Redirect URL must be a string\");\n } else if (options.url.trim() === \"\") {\n errors.push(\"Redirect URL cannot be empty\");\n } else {\n // Validate URL format\n try {\n new URL(options.url);\n } catch {\n errors.push(`Invalid redirect URL: \"${options.url}\"`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Nav action validation.\n */\n\nimport type { ValidationResult, NavActionValidationInput } from \"./types\";\n\n/**\n * Validate nav action options.\n */\nexport function validateNavAction(\n options: NavActionValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation (required, non-empty)\n if (!options.title) {\n errors.push(\"Nav action title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Nav action title must be a string\");\n }\n\n // Value validation (required, non-empty)\n if (!options.value) {\n errors.push(\"Nav action value is required\");\n } else if (typeof options.value !== \"string\") {\n errors.push(\"Nav action value must be a string\");\n }\n\n // subTitle validation (optional)\n if (options.subTitle !== undefined && options.subTitle !== null) {\n if (typeof options.subTitle !== \"string\") {\n errors.push(\"Nav action subTitle must be a string\");\n }\n }\n\n // icon validation (optional)\n if (options.icon !== undefined && options.icon !== null) {\n if (typeof options.icon !== \"string\") {\n errors.push(\"Nav action icon must be a string\");\n }\n }\n\n // disabled validation (optional)\n if (options.disabled !== undefined && options.disabled !== null) {\n if (typeof options.disabled !== \"boolean\") {\n errors.push(\"Nav action disabled must be a boolean\");\n }\n }\n\n // Extended actions validation (optional)\n if (\n options.extendedActions !== undefined &&\n options.extendedActions !== null\n ) {\n if (!Array.isArray(options.extendedActions)) {\n errors.push(\"Nav action extendedActions must be an array\");\n } else {\n options.extendedActions.forEach((action: unknown, index: number) => {\n if (typeof action !== \"object\" || action === null) {\n errors.push(`Extended action at index ${index} must be an object`);\n return;\n }\n const ext = action as {\n title?: unknown;\n subTitle?: unknown;\n value?: unknown;\n icon?: unknown;\n disabled?: unknown;\n };\n if (!ext.title || typeof ext.title !== \"string\") {\n errors.push(\n `Extended action at index ${index} is missing required \"title\" property`,\n );\n }\n if (!ext.value || typeof ext.value !== \"string\") {\n errors.push(\n `Extended action at index ${index} is missing required \"value\" property`,\n );\n }\n if (ext.subTitle !== undefined && typeof ext.subTitle !== \"string\") {\n errors.push(\n `Extended action at index ${index} subTitle must be a string`,\n );\n }\n if (ext.icon !== undefined && typeof ext.icon !== \"string\") {\n errors.push(\n `Extended action at index ${index} icon must be a string`,\n );\n }\n if (ext.disabled !== undefined && typeof ext.disabled !== \"boolean\") {\n errors.push(\n `Extended action at index ${index} disabled must be a boolean`,\n );\n }\n });\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Confirm dialog validation.\n */\n\nimport type { ValidationResult, ConfirmValidationInput } from \"./types\";\n\nconst VALID_CONFIRM_VARIANTS = [\"danger\", \"warning\", \"info\"];\n\n/**\n * Validate confirm dialog options.\n */\nexport function validateConfirm(\n options: ConfirmValidationInput,\n): ValidationResult {\n const errors: string[] = [];\n\n // Title validation\n if (options.title === undefined || options.title === null) {\n errors.push(\"Confirm dialog title is required\");\n } else if (typeof options.title !== \"string\") {\n errors.push(\"Confirm dialog title must be a string\");\n } else if (options.title.trim() === \"\") {\n errors.push(\"Confirm dialog title cannot be empty\");\n }\n\n // Message validation\n if (options.message === undefined || options.message === null) {\n errors.push(\"Confirm dialog message is required\");\n } else if (typeof options.message !== \"string\") {\n errors.push(\"Confirm dialog message must be a string\");\n } else if (options.message.trim() === \"\") {\n errors.push(\"Confirm dialog message cannot be empty\");\n }\n\n // Confirm text validation (optional)\n if (options.confirmText !== undefined && options.confirmText !== null) {\n if (typeof options.confirmText !== \"string\") {\n errors.push(\"Confirm dialog confirmText must be a string\");\n }\n }\n\n // Cancel text validation (optional)\n if (options.cancelText !== undefined && options.cancelText !== null) {\n if (typeof options.cancelText !== \"string\") {\n errors.push(\"Confirm dialog cancelText must be a string\");\n }\n }\n\n // Variant validation (optional)\n if (options.variant !== undefined && options.variant !== null) {\n if (\n typeof options.variant !== \"string\" ||\n !VALID_CONFIRM_VARIANTS.includes(options.variant)\n ) {\n errors.push(\n `Invalid confirm variant \"${options.variant}\". Expected: ${VALID_CONFIRM_VARIANTS.join(\" | \")}`,\n );\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n","/**\n * @fileoverview Validation utility functions.\n */\n\nimport { logger } from \"../logger\";\n\n/**\n * Log validation errors to console with helpful formatting.\n *\n * @param method - The SDK method that failed validation\n * @param errors - Array of error messages\n */\nexport function logValidationErrors(method: string, errors: string[]): void {\n logger.error(\n `Validation failed for ${method}:\\n` +\n errors.map((e) => ` • ${e}`).join(\"\\n\"),\n );\n}\n","/**\n * @fileoverview Page module for navigation and resize.\n */\n\nimport { IFRAME_EVENTS } from \"../../core/events\";\nimport { postToHost } from \"../../core/messenger\";\nimport {\n validateNavigate,\n validateRedirect,\n logValidationErrors,\n} from \"../../core/validation\";\nimport { PAGE_EVENTS } from \"./events\";\nimport type { PageModule, NavToOptions } from \"./types\";\n\nexport type { PageModule, NavToOptions } from \"./types\";\n\n/**\n * Create the page module.\n *\n * @returns Page module instance\n */\nexport function createPageModule(): PageModule {\n return {\n /**\n * Navigate to a path using React Router (SPA navigation).\n */\n navigate(path: string, options?: NavToOptions): void {\n const validation = validateNavigate({ path, ...options });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.NAVIGATE, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.NAVIGATE, {\n path,\n state: options?.state,\n replace: options?.replace,\n });\n },\n\n /**\n * Redirect to a URL (full page reload).\n */\n redirect(url: string): void {\n const validation = validateRedirect({ url });\n if (!validation.valid) {\n logValidationErrors(PAGE_EVENTS.REDIRECT, validation.errors);\n return;\n }\n postToHost(PAGE_EVENTS.REDIRECT, { url });\n },\n\n /**\n * Navigate to a path - auto-detects internal vs external.\n */\n navTo(path: string, options?: NavToOptions): void {\n // External URLs use redirect\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n this.redirect(path);\n return;\n }\n\n // Internal navigation\n this.navigate(path, options);\n },\n\n /**\n * Update the iframe height.\n */\n resize(height: number): void {\n if (typeof height !== \"number\" || height < 0) {\n logValidationErrors(IFRAME_EVENTS.RESIZE, [\n \"Height must be a non-negative number\",\n ]);\n return;\n }\n postToHost(IFRAME_EVENTS.RESIZE, { height });\n },\n\n /**\n * Auto-resize iframe to content height.\n */\n autoResize(): void {\n const height = document.documentElement.scrollHeight;\n this.resize(height);\n },\n\n /**\n * Set the page title in the host document.\n */\n setTitle(title: string): void {\n if (typeof title !== \"string\" || !title.trim()) {\n logValidationErrors(PAGE_EVENTS.SET_TITLE, [\n \"Title must be a non-empty string\",\n ]);\n return;\n }\n postToHost(PAGE_EVENTS.SET_TITLE, { title });\n },\n };\n}\n","/**\n * @fileoverview Nav module for navigation actions.\n */\n\nimport { postToHost, onMessage } from \"../../core/messenger\";\nimport { validateNavAction, logValidationErrors } from \"../../core/validation\";\nimport { createSubscription } from \"../../core/subscriptions\";\nimport type { NavActionClickMessage, Unsubscribe } from \"../../core/types\";\nimport { NAV_EVENTS } from \"./events\";\nimport type {\n NavModule,\n PrimaryActionConfig,\n ActionClickCallback,\n} from \"./types\";\n\nexport type { NavModule, PrimaryActionConfig } from \"./types\";\n\n/**\n * Create the nav module.\n */\nexport function createNavModule(): NavModule {\n const clickSubscription = createSubscription<ActionClickCallback>();\n\n // Listen for action click events from host\n onMessage<NavActionClickMessage>(NAV_EVENTS.ACTION_CLICK, (data) => {\n clickSubscription.notify(data.payload.value);\n });\n\n return {\n setAction(config: PrimaryActionConfig): void {\n const validation = validateNavAction(config);\n if (!validation.valid) {\n logValidationErrors(NAV_EVENTS.SET_ACTION, validation.errors);\n return;\n }\n\n postToHost(NAV_EVENTS.SET_ACTION, {\n title: config.title,\n value: config.value,\n subTitle: config.subTitle,\n icon: config.icon,\n disabled: config.disabled,\n extendedActions: config.extendedActions?.map((ext) => ({\n title: ext.title,\n value: ext.value,\n subTitle: ext.subTitle,\n icon: ext.icon,\n disabled: ext.disabled,\n })),\n });\n },\n\n clearAction(): void {\n postToHost(NAV_EVENTS.CLEAR_ACTION, {});\n },\n\n onActionClick(callback: ActionClickCallback): Unsubscribe {\n return clickSubscription.subscribe(callback);\n },\n };\n}\n","/**\n * @fileoverview Loading component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { UI_EVENTS } from \"../events\";\nimport type { LoadingSubModule } from \"../types\";\n\n/**\n * Create the loading sub-module.\n */\nexport function createLoadingSubModule(): LoadingSubModule {\n return {\n /**\n * Show loading indicator.\n */\n show(): void {\n postToHost(UI_EVENTS.LOADING, { action: \"show\" });\n },\n\n /**\n * Hide loading indicator.\n */\n hide(): void {\n postToHost(UI_EVENTS.LOADING, { action: \"hide\" });\n },\n };\n}\n","/**\n * @fileoverview Toast notification component.\n */\n\nimport { postToHost } from \"../../../core/messenger\";\nimport { validateToast, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ToastSubModule, ToastOptions } from \"../types\";\n\n/**\n * Create the toast sub-module.\n */\nexport function createToastSubModule(): ToastSubModule {\n const showToast = (options: ToastOptions): void => {\n const validation = validateToast(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.TOAST, validation.errors);\n return;\n }\n postToHost(UI_EVENTS.TOAST, {\n type: options.type,\n message: options.message,\n duration: options.duration,\n });\n };\n\n return {\n /**\n * Show a toast notification.\n */\n show: showToast,\n\n /**\n * Show success toast.\n */\n success(message: string, duration?: number): void {\n showToast({ type: \"success\", message, duration });\n },\n\n /**\n * Show error toast.\n */\n error(message: string, duration?: number): void {\n showToast({ type: \"error\", message, duration });\n },\n\n /**\n * Show warning toast.\n */\n warning(message: string, duration?: number): void {\n showToast({ type: \"warning\", message, duration });\n },\n\n /**\n * Show info toast.\n */\n info(message: string, duration?: number): void {\n showToast({ type: \"info\", message, duration });\n },\n };\n}\n","/**\n * @fileoverview Confirm dialog component.\n */\n\nimport { sendRequest } from \"../../../core/requests\";\nimport { validateConfirm, logValidationErrors } from \"../../../core/validation\";\nimport { UI_EVENTS } from \"../events\";\nimport type { ConfirmOptions, ConfirmResult } from \"../../../core/types\";\n\n/**\n * Create the confirm function.\n */\nexport function createConfirmFunction(): (\n options: ConfirmOptions,\n) => Promise<ConfirmResult> {\n return async (options: ConfirmOptions): Promise<ConfirmResult> => {\n const validation = validateConfirm(options);\n if (!validation.valid) {\n logValidationErrors(UI_EVENTS.CONFIRM, validation.errors);\n return Promise.reject(new Error(validation.errors.join(\", \")));\n }\n\n return sendRequest<ConfirmResult>(UI_EVENTS.CONFIRM, {\n title: options.title,\n message: options.message,\n confirmText: options.confirmText ?? \"Confirm\",\n cancelText: options.cancelText ?? \"Cancel\",\n variant: options.variant ?? \"info\",\n });\n };\n}\n","/**\n * @fileoverview UI module with nested sub-modules for loading, toast, and confirm.\n */\n\nimport {\n createLoadingSubModule,\n createToastSubModule,\n createConfirmFunction,\n} from \"./components\";\nimport type { UIModule } from \"./types\";\n\nexport type {\n UIModule,\n LoadingSubModule,\n ToastSubModule,\n LoadingMode,\n ToastOptions,\n ToastType,\n} from \"./types\";\n\n/**\n * Create the UI module with nested sub-modules.\n *\n * @returns UI module instance\n */\nexport function createUIModule(): UIModule {\n return {\n loading: createLoadingSubModule(),\n toast: createToastSubModule(),\n confirm: createConfirmFunction(),\n };\n}\n","/**\n * @fileoverview Checkout module for checkout flow integration.\n */\n\nimport { postToHost, onMessage } from \"../../core/messenger\";\nimport {\n sendRequest,\n handleResponse,\n generateRequestId,\n} from \"../../core/requests\";\nimport { createSubscription } from \"../../core/subscriptions\";\nimport type { BaseMessage, CheckoutResponseMessage } from \"../../core/types\";\nimport { validateCheckout, logValidationErrors } from \"../../core/validation\";\nimport { CHECKOUT_EVENTS } from \"./events\";\nimport type {\n AddonInfo,\n CheckoutModule,\n CheckoutCreateConfig,\n CheckoutResultCallback,\n CheckoutItem,\n GetAddonsResult,\n} from \"./types\";\n\nexport type {\n AddonInfo,\n CheckoutModule,\n CheckoutCreateConfig,\n CheckoutResult,\n CheckoutResultCallback,\n CheckoutItem,\n GetAddonsResult,\n} from \"./types\";\n\n/** Response message for getAddons */\ninterface GetAddonsResponseMessage extends BaseMessage {\n payload: {\n success: boolean;\n addons?: AddonInfo[];\n error?: { code: string; message: string };\n };\n}\n\n/**\n * Create the checkout module.\n */\nexport function createCheckoutModule(): CheckoutModule {\n const resultSubscription = createSubscription<CheckoutResultCallback>();\n\n // Track listener unsubscribe functions for cleanup\n const unsubscribers: Array<() => void> = [];\n\n // Listen for checkout responses\n unsubscribers.push(\n onMessage<CheckoutResponseMessage>(CHECKOUT_EVENTS.RESPONSE, (message) => {\n resultSubscription.notify({\n success: message.payload.success,\n order_id: message.payload.order_id,\n status: message.payload.status,\n error: message.payload.error,\n context: message.payload.context,\n });\n }),\n );\n\n // Listen for getAddons responses\n unsubscribers.push(\n onMessage<GetAddonsResponseMessage>(\n CHECKOUT_EVENTS.GET_ADDONS_RESPONSE,\n (message) => {\n if (message.requestId) {\n handleResponse<GetAddonsResult>(message.requestId, {\n success: message.payload.success,\n addons: message.payload.addons,\n error: message.payload.error,\n });\n }\n },\n ),\n );\n\n return {\n create(\n input: CheckoutItem | CheckoutItem[],\n config?: CheckoutCreateConfig,\n ): void {\n const items = Array.isArray(input) ? input : [input];\n\n // Validate input before sending\n const validation = validateCheckout({ items });\n if (!validation.valid) {\n logValidationErrors(CHECKOUT_EVENTS.CREATE, validation.errors);\n throw new Error(validation.errors[0]);\n }\n\n // Note: Using \"*\" as targetOrigin because the SDK runs in third-party iframes\n // and doesn't know the host's origin at build time. Origin validation is\n // performed by the host when receiving messages via its trusted origin list.\n postToHost(\n CHECKOUT_EVENTS.CREATE,\n {\n items: items.map((i) => ({\n type: i.type,\n slug: i.slug,\n quantity: i.quantity ?? 1,\n })),\n ...(config?.context !== undefined && { context: config.context }),\n },\n \"*\",\n generateRequestId(),\n );\n },\n\n onResult(callback: CheckoutResultCallback): () => void {\n return resultSubscription.subscribe(callback);\n },\n\n async getAddons(): Promise<GetAddonsResult> {\n try {\n return await sendRequest<GetAddonsResult>(\n CHECKOUT_EVENTS.GET_ADDONS,\n {},\n 30000,\n );\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"REQUEST_FAILED\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n },\n };\n }\n },\n\n destroy(): void {\n unsubscribers.forEach((unsubscribe) => unsubscribe());\n unsubscribers.length = 0;\n resultSubscription.clear();\n },\n };\n}\n","/**\n * @fileoverview Main EmbeddedApp singleton class.\n * Core of the SDK that manages initialization, state, and module coordination.\n */\n\nimport { IFRAME_EVENTS, CONTEXT_EVENTS } from \"./events\";\nimport { UI_EVENTS } from \"../modules/ui/events\";\nimport {\n postToHost,\n waitForMessage,\n removeAllListeners,\n isInIframe,\n onMessage,\n dispatchLocal,\n} from \"./messenger\";\nimport { CHECKOUT_EVENTS } from \"../modules/checkout/events\";\nimport type {\n InitOptions,\n EmbeddedState,\n LayoutInfo,\n ContextProvideResponse,\n ThemeChangeMessage,\n ConfirmResponseMessage,\n InitCallback,\n} from \"./types\";\nimport { handleResponse, cancelAllRequests } from \"./requests\";\nimport { logger, setLoggerConfig } from \"./logger\";\nimport { createSubscription, type Subscription } from \"./subscriptions\";\n\n// Import modules\nimport { createAuthModule, type AuthModule } from \"../modules/auth\";\nimport { createPageModule, type PageModule } from \"../modules/page\";\nimport { createNavModule, type NavModule } from \"../modules/nav\";\nimport { createUIModule, type UIModule } from \"../modules/ui\";\nimport { createCheckoutModule, type CheckoutModule } from \"../modules/checkout\";\n\n/**\n * Default layout values.\n */\nconst DEFAULT_LAYOUT: LayoutInfo = {\n theme: \"light\",\n width: 0,\n locale: \"ar\",\n currency: \"SAR\",\n};\n\n/**\n * Post-init hook type. Called after handshake with context response.\n */\ntype PostInitHook = (response: ContextProvideResponse) => void;\n\n/**\n * Main Embedded SDK class.\n * Provides the primary interface for third-party apps to communicate with the Salla host.\n */\nclass EmbeddedApp {\n private initialized = false;\n private initializing = false;\n private debugMode = false;\n private appReady = false;\n private layout: LayoutInfo = { ...DEFAULT_LAYOUT };\n\n // Subscriptions\n private themeSubscription: Subscription<(theme: \"light\" | \"dark\") => void>;\n private initSubscription: Subscription<InitCallback>;\n\n // Post-init hooks for modules to register\n private postInitHooks: PostInitHook[] = [];\n\n /** Auth module for token management */\n public auth: AuthModule;\n /** Page module for navigation and resize */\n public page: PageModule;\n /** Nav module for primary actions */\n public nav: NavModule;\n /** UI module for loading, overlay, toast, modal */\n public ui: UIModule;\n /** Checkout module for checkout flow */\n public checkout: CheckoutModule;\n\n constructor() {\n // Create subscriptions\n this.themeSubscription = createSubscription();\n this.initSubscription = createSubscription();\n\n // Initialize modules\n this.auth = createAuthModule(() => this.getState());\n this.page = createPageModule();\n this.nav = createNavModule();\n this.ui = createUIModule();\n this.checkout = createCheckoutModule();\n\n // Register checkout's post-init hook for pending checkout results\n this.registerPostInitHook((response) => {\n const result = response.payload.pendingCheckoutResult;\n if (result) {\n logger.debug(\"Dispatching pending checkout result:\", result);\n // Dispatch on next microtask to allow callbacks to register after init\n queueMicrotask(() => {\n dispatchLocal(CHECKOUT_EVENTS.RESPONSE, {\n success: result.success,\n status: result.status,\n error: result.error,\n context: result.context,\n });\n });\n }\n });\n\n // Set up core listeners\n this.setupListeners();\n }\n\n /**\n * Register a hook to run after successful init handshake.\n * Used by modules to process context data.\n */\n private registerPostInitHook(hook: PostInitHook): void {\n this.postInitHooks.push(hook);\n }\n\n /**\n * Set up core event listeners.\n */\n private setupListeners(): void {\n // Theme changes\n onMessage<ThemeChangeMessage>(CONTEXT_EVENTS.THEME_CHANGE, (data) => {\n this.layout.theme = data.payload.theme;\n logger.debug(\"Theme changed:\", data.payload.theme);\n this.themeSubscription.notify(data.payload.theme);\n });\n\n // Confirm dialog responses\n onMessage<ConfirmResponseMessage>(UI_EVENTS.CONFIRM_RESPONSE, (data) => {\n logger.debug(\"Received confirm response:\", data);\n if (data.requestId) {\n handleResponse(data.requestId, { confirmed: data.payload.confirmed });\n }\n });\n }\n\n /**\n * Get current SDK state.\n */\n getState(): Readonly<EmbeddedState> {\n return {\n ready: this.initialized,\n initializing: this.initializing,\n layout: { ...this.layout },\n };\n }\n\n /**\n * Check if SDK is initialized and ready.\n */\n isReady(): boolean {\n return this.initialized;\n }\n\n /**\n * Subscribe to theme changes.\n */\n onThemeChange(callback: (theme: \"light\" | \"dark\") => void): () => void {\n return this.themeSubscription.subscribe(callback);\n }\n\n /**\n * Subscribe to init completion. Fires immediately if already initialized.\n */\n onInit(callback: InitCallback): () => void {\n if (this.initialized) {\n try {\n callback(this.getState());\n } catch (error) {\n logger.error(\"Error in init callback:\", error);\n }\n }\n return this.initSubscription.subscribe(callback);\n }\n\n /**\n * Signal that the app is fully loaded and ready.\n */\n ready(): void {\n if (this.appReady) {\n logger.debug(\"App already signaled as ready\");\n return;\n }\n if (!this.initialized) {\n logger.warn(\"Cannot signal ready before init() is called\");\n return;\n }\n this.appReady = true;\n postToHost(IFRAME_EVENTS.READY, {});\n logger.debug(\"Sent ready signal to host\");\n }\n\n /**\n * Initialize the SDK and establish connection with the host.\n */\n async init(options: InitOptions = {}): Promise<{ layout: LayoutInfo }> {\n // Already initialized\n if (this.initialized) {\n logger.debug(\"Already initialized, returning current layout\");\n return { layout: { ...this.layout } };\n }\n\n // Initialization in progress - wait for it\n if (this.initializing) {\n logger.warn(\"Initialization already in progress\");\n return new Promise((resolve) => {\n const unsubscribe = this.onInit((state) => {\n unsubscribe();\n resolve({ layout: { ...state.layout } });\n });\n });\n }\n\n // Start initialization\n this.initializing = true;\n this.debugMode = options.debug ?? false;\n setLoggerConfig({ debug: this.debugMode });\n\n if (!isInIframe()) {\n logger.warn(\"Not running in an iframe. Some features may not work.\");\n }\n\n logger.debug(\"Initializing SDK...\");\n\n try {\n // Handshake: send init, wait for context\n postToHost(IFRAME_EVENTS.INIT, {\n height: document.documentElement.scrollHeight,\n });\n logger.debug(\"Sent iframe.ready message, waiting for context...\");\n\n const response = await waitForMessage<ContextProvideResponse>(\n CONTEXT_EVENTS.PROVIDE,\n );\n logger.debug(\"Received context from host:\", response);\n\n // Update layout\n const { layout } = response.payload;\n this.layout = {\n theme: layout?.theme ?? \"light\",\n width: layout?.width ?? 0,\n locale: layout?.locale ?? \"ar\",\n currency: layout?.currency ?? \"SAR\",\n };\n\n // Run post-init hooks (e.g., pending checkout handling)\n this.postInitHooks.forEach((hook) => {\n try {\n hook(response);\n } catch (error) {\n logger.error(\"Error in post-init hook:\", error);\n }\n });\n\n this.initialized = true;\n this.initializing = false;\n\n logger.debug(\"Initialization complete. Layout:\", this.layout);\n\n // Notify subscribers\n this.initSubscription.notify(this.getState());\n\n return { layout: { ...this.layout } };\n } catch (error) {\n this.initializing = false;\n throw error;\n }\n }\n\n /**\n * Destroy the SDK instance and clean up resources.\n */\n destroy(): void {\n logger.debug(\"Destroying SDK instance\");\n\n if (this.initialized) {\n postToHost(IFRAME_EVENTS.DESTROY, {});\n logger.debug(\"Sent destroy event to host\");\n }\n\n // Cleanup modules\n this.checkout.destroy();\n\n // Cleanup core resources\n cancelAllRequests(\"SDK destroyed\");\n removeAllListeners();\n this.themeSubscription.clear();\n this.initSubscription.clear();\n this.postInitHooks = [];\n\n // Reset state\n this.initialized = false;\n this.initializing = false;\n this.appReady = false;\n this.layout = { ...DEFAULT_LAYOUT };\n }\n}\n\n// Singleton\nlet instance: EmbeddedApp | null = null;\n\n/**\n * Get the singleton EmbeddedApp instance.\n */\nexport function getEmbeddedApp(): EmbeddedApp {\n if (!instance) {\n instance = new EmbeddedApp();\n }\n return instance;\n}\n\n/**\n * Reset the singleton (for testing).\n */\nexport function resetEmbeddedApp(): void {\n if (instance) {\n instance.destroy();\n instance = null;\n }\n}\n\nexport { EmbeddedApp };\n","/**\n * @fileoverview Main entry point for the Salla Embedded SDK.\n *\n * This SDK provides a communication bridge between embedded third-party apps\n * and the Salla Dashboard host.\n *\n * @example Using window global\n * ```typescript\n * await salla.embedded.init({ debug: true });\n * salla.embedded.ui.loading.hide();\n * ```\n *\n * @example Using ES module import\n * ```typescript\n * import { embedded } from '@salla.sa/embedded-sdk';\n * await embedded.init({ debug: true });\n * ```\n */\n\nimport { getEmbeddedApp, EmbeddedApp } from \"./core/EmbeddedApp\";\nimport { SDK_VERSION } from \"./core/constants\";\n\n// Re-export types\nexport type {\n InitOptions,\n EmbeddedState,\n ExtendedAction,\n ToastType,\n ConfirmOptions,\n ConfirmResult,\n ConfirmVariant,\n} from \"./core/types\";\n\n// Re-export validation types for advanced use cases\nexport type { ValidationResult } from \"./core/validation\";\n\nexport type { AuthModule } from \"./modules/auth\";\nexport type { PageModule, NavToOptions } from \"./modules/page\";\nexport type { NavModule, PrimaryActionConfig } from \"./modules/nav\";\nexport type { UIModule, LoadingMode, ToastOptions } from \"./modules/ui\";\nexport type {\n CheckoutModule,\n CheckoutCreateConfig,\n CheckoutResult,\n CheckoutResultCallback,\n CheckoutItem,\n} from \"./modules/checkout\";\n\n// Export the singleton instance\nexport const embedded = getEmbeddedApp();\n\n// Export version and events\nexport const version = SDK_VERSION;\n\n// Export class for advanced use cases\nexport { EmbeddedApp };\n\n// Re-export getEmbeddedApp for advanced use cases\nexport { getEmbeddedApp, resetEmbeddedApp } from \"./core/EmbeddedApp\";\n\n// ============================================================================\n// Window Global Setup\n// ============================================================================\n\n/**\n * Salla interface extension for the embedded SDK.\n */\ninterface SallaEmbedded {\n embedded: EmbeddedApp;\n}\n\ndeclare global {\n interface Window {\n salla: SallaEmbedded & Record<string, unknown>;\n Salla: SallaEmbedded & Record<string, unknown>;\n }\n}\n\n/**\n * Set up window globals.\n * Supports both window.salla.embedded and window.Salla.embedded\n */\nif (typeof window !== \"undefined\") {\n // Initialize salla object if it doesn't exist\n window.salla = window.salla || window.Salla || {};\n window.Salla = window.salla;\n\n // Attach embedded SDK\n if (!window.salla.embedded) {\n window.salla.embedded = embedded;\n }\n if (!window.Salla.embedded) {\n window.Salla.embedded = embedded;\n }\n}\n"],"names":["EVENT_PREFIX","IFRAME_EVENTS","CONTEXT_EVENTS","UI_EVENTS","AUTH_EVENTS","PAGE_EVENTS","NAV_EVENTS","CHECKOUT_EVENTS","SDK_VERSION","pkg","DEFAULT_TIMEOUT","TRUSTED_DOMAINS","loggerConfig","setLoggerConfig","config","createBadge","text","getBadgeStyle","backgroundColor","textColor","log","type","args","badges","styles","badgeString","logger","isTrustedOrigin","origin","hostname","domain","getParentWindow","postToHost","event","data","targetOrigin","requestId","metadata","parent","message","listeners","isListening","handleMessage","eventListeners","callback","error","wildcardListeners","startListening","onMessage","waitForMessage","timeout","resolve","reject","timer","unsubscribe","removeAllListeners","isInIframe","dispatchLocal","payload","pendingRequests","DEFAULT_REQUEST_TIMEOUT","generateRequestId","timestamp","random","sendRequest","handleResponse","result","pending","cancelAllRequests","reason","createSubscription","callbacks","API_BASE_URL","ApiError","status","response","apiRequest","endpoint","options","method","headers","body","url","controller","timeoutId","contentType","createErrorResponse","errorMessage","introspect","params","token","appId","refreshOnError","apiResponse","isVerified","getEmbeddedApp","createAuthModule","_getState","introspectFunction","VALID_TOAST_TYPES","validateToast","errors","validateItem","item","label","validateCheckout","hasSingleItem","hasItemsArray","itemErrors","index","validateNavigate","validateRedirect","validateNavAction","action","ext","VALID_CONFIRM_VARIANTS","validateConfirm","logValidationErrors","e","createPageModule","path","validation","height","title","createNavModule","clickSubscription","_a","createLoadingSubModule","createToastSubModule","showToast","duration","createConfirmFunction","createUIModule","createCheckoutModule","resultSubscription","unsubscribers","input","items","i","DEFAULT_LAYOUT","EmbeddedApp","hook","state","layout","instance","resetEmbeddedApp","embedded","version"],"mappings":"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"}
|