@fruga/sdk 1.0.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,5 @@
1
1
  import React, { ReactNode } from 'react';
2
2
 
3
- interface LoaderOptions {
4
- partnerKey: string;
5
- containerId?: string;
6
- token?: string;
7
- onTokenRequired?: () => Promise<string>;
8
- theme?: 'light' | 'dark';
9
- primaryColor?: string;
10
- appUrl?: string;
11
- autoMount?: boolean;
12
- userId?: string;
13
- baseUrl?: string;
14
- }
15
-
16
- declare const requestBalance: () => void;
17
- declare const getBalance: () => Promise<{
18
- available: number;
19
- pending: number;
20
- }>;
21
-
22
3
  declare const DEFAULT_THEME: {
23
4
  widgetTitle: string;
24
5
  launcherLabel: string;
@@ -72,11 +53,20 @@ interface BootstrapAuth {
72
53
  issuer: string;
73
54
  tokenTtlSeconds: number;
74
55
  }
56
+ /**
57
+ * Who receives the cashback. The wire type is deliberately wider than the two
58
+ * modes the UI knows about: the API may introduce further values, so every
59
+ * consumer narrows through {@link resolvePayoutMode} instead of comparing
60
+ * against a literal.
61
+ */
62
+ type PayoutMode = 'PARTNER' | 'USER';
63
+ /** `partnerPayout` as it arrives on the wire, including values this build does not know. */
64
+ type PartnerPayout = PayoutMode | 'UNKNOWN';
75
65
  interface WidgetBootstrap {
76
66
  partnerEnvId: string;
77
67
  partnerId: string;
78
68
  partnerType: PartnerType;
79
- partnerPayout: 'PARTNER' | 'USER';
69
+ partnerPayout: PartnerPayout;
80
70
  auth: BootstrapAuth;
81
71
  config: {
82
72
  ui: WidgetUiConfig;
@@ -85,6 +75,12 @@ interface WidgetBootstrap {
85
75
  launcherIcon: string[];
86
76
  };
87
77
  };
78
+ /**
79
+ * Absolute URL of the widget document to load. When present the loader uses
80
+ * it instead of its default, which gives ops a kill switch and native
81
+ * wrappers the URL from the same call.
82
+ */
83
+ widgetUrl?: string;
88
84
  }
89
85
  interface RelayConfig {
90
86
  containerId: string;
@@ -113,15 +109,134 @@ interface WidgetContainerProps {
113
109
  theme: Theme;
114
110
  }
115
111
 
116
- declare const useFrugaWidget: (config: LoaderOptions) => {
112
+ /**
113
+ * Why the widget never became usable.
114
+ *
115
+ * - `TIMEOUT`: no FRUGA_READY arrived within `LoaderOptions.loadTimeoutMs`.
116
+ * - `VERSION_MISMATCH`: FRUGA_READY carried an incompatible protocol major.
117
+ * - `BOOTSTRAP_FAILED`: bootstrap could not be resolved and nothing was cached.
118
+ * - `NOT_READY`: a balance request was made before FRUGA_READY and the widget
119
+ * did not become ready in time. Rejects the call only; the mount survives.
120
+ */
121
+ type FrugaLoadErrorCode = 'TIMEOUT' | 'VERSION_MISMATCH' | 'BOOTSTRAP_FAILED' | 'NOT_READY';
122
+ /** Version context attached to a {@link FrugaLoadError}, when known. */
123
+ interface FrugaLoadErrorDetails {
124
+ /** Defaults to the running loader's package version. */
125
+ loaderVersion?: string;
126
+ /** Widget bundle version, as reported in FRUGA_READY. */
127
+ widgetVersion?: string;
128
+ /** Widget protocol version, as reported in FRUGA_READY. */
129
+ protocolVersion?: string;
130
+ }
131
+ /**
132
+ * Host-facing load failure handed to `LoaderOptions.onError`. Carries enough
133
+ * version context for a partner to file a useful bug report.
134
+ */
135
+ declare class FrugaLoadError extends Error {
136
+ readonly code: FrugaLoadErrorCode;
137
+ readonly loaderVersion: string;
138
+ readonly widgetVersion?: string;
139
+ readonly protocolVersion?: string;
140
+ constructor(code: FrugaLoadErrorCode, message: string, details?: FrugaLoadErrorDetails);
141
+ }
142
+
143
+ interface Balance {
144
+ available: number;
145
+ pending: number;
146
+ }
147
+ /**
148
+ * Channel a {@link FrugaLoaderEvent} belongs to: `lifecycle` for mount/ready/
149
+ * token milestones, `protocol` for every postMessage in or out, `log` for
150
+ * anything the loader would otherwise only write to the console, and `error`
151
+ * for a {@link FrugaLoadError} - and only that. The split mirrors the native
152
+ * bridge, where `log` and `error` are separate messages.
153
+ */
154
+ type FrugaLoaderEventType = 'lifecycle' | 'protocol' | 'log' | 'error';
155
+ /**
156
+ * Severity of a {@link FrugaLoaderEvent}. `lifecycle` and `protocol` are always
157
+ * `info`, `error` is always `error`, `log` carries the level of the console call
158
+ * it replaces.
159
+ */
160
+ type FrugaLoaderEventLevel = 'info' | 'warn' | 'error';
161
+ /**
162
+ * Diagnostic event handed to `LoaderOptions.onEvent`. Deliberately flat and
163
+ * JSON-serialisable: the native SDKs forward exactly this shape to their
164
+ * partner log sink, so `name` values are stable API. Never carries a token.
165
+ */
166
+ interface FrugaLoaderEvent {
167
+ type: FrugaLoaderEventType;
168
+ level: FrugaLoaderEventLevel;
169
+ /** Lifecycle milestone, protocol message type, log name, or error code. */
170
+ name: string;
171
+ data?: unknown;
172
+ /** `Date.now()` when the event was emitted. */
173
+ ts: number;
174
+ }
175
+ interface LoaderOptions {
176
+ partnerKey: string;
177
+ containerId?: string;
178
+ token?: string;
179
+ onTokenRequired?: () => Promise<string>;
180
+ theme?: 'light' | 'dark';
181
+ primaryColor?: string;
182
+ appUrl?: string;
183
+ autoMount?: boolean;
184
+ userId?: string;
185
+ baseUrl?: string;
186
+ /** Mount with the widget's panel already open. Used by the native shell. */
187
+ panelOpen?: boolean;
188
+ /**
189
+ * Delivers the reply to a fire-and-forget `requestBalance()` call. Without it
190
+ * `requestBalance()` has no consumer and does nothing; use `getBalance()` for
191
+ * the promise-based form.
192
+ */
193
+ onBalance?: (balance: Balance) => void;
194
+ /**
195
+ * How long to wait for the widget's FRUGA_READY before the mount is treated
196
+ * as failed. Defaults to {@link DEFAULT_LOAD_TIMEOUT_MS}; `0` disables the
197
+ * timeout entirely.
198
+ */
199
+ loadTimeoutMs?: number;
200
+ /**
201
+ * Called once per failed mount. The loader has already removed the iframe and
202
+ * rendered its own minimal error element inside the container; call
203
+ * `FrugaHandle.retry()` to try again.
204
+ */
205
+ onError?: (error: FrugaLoadError) => void;
206
+ /**
207
+ * Diagnostic sink: lifecycle milestones, every postMessage in or out, every
208
+ * diagnostic the loader would otherwise log, and every load error. When set it
209
+ * *replaces* the loader's console output; without it the console stays the
210
+ * default sink.
211
+ */
212
+ onEvent?: (event: FrugaLoaderEvent) => void;
213
+ }
214
+
215
+ declare const requestBalance: () => void;
216
+ declare const getBalance: () => Promise<Balance>;
217
+
218
+ interface UseFrugaWidgetResult {
117
219
  mount: () => Promise<void>;
118
220
  unmount: () => void;
119
- };
221
+ /** Clears the error and mounts once more. The loader never retries by itself. */
222
+ retry: () => Promise<void>;
223
+ /** Last load failure, or `null` while the widget is healthy. */
224
+ error: FrugaLoadError | null;
225
+ }
226
+ declare const useFrugaWidget: (config: LoaderOptions) => UseFrugaWidgetResult;
227
+ /** `LoaderOptions` (including `onError` and `loadTimeoutMs`) are the props. */
120
228
  declare const FrugaWidget: React.FC<LoaderOptions>;
121
229
  /**
122
- * A wrapper component that provides the WidgetProvider context around the WidgetContainer.
123
- * This ensures that any child components or the container itself can access the WidgetContext.
230
+ * Widget-side shell: owns the `PostMessageTransport` to the host window and
231
+ * provides it to `WidgetHandshake`, which announces FRUGA_READY once the
232
+ * subscribers below are mounted.
233
+ *
234
+ * The transport is built in an effect rather than in render (or a lazily
235
+ * initialised ref) so React StrictMode's double-invoked effects leave exactly
236
+ * one live, undisposed transport behind - same trade-off as `RelayEntry`. The
237
+ * cost is one `null` first paint, which is invisible: nothing below has data
238
+ * before FRUGA_INIT arrives anyway.
124
239
  */
125
240
  declare const WidgetUI: React.FC<WidgetContainerProps>;
126
241
 
127
- export { FrugaWidget, WidgetUI, getBalance, requestBalance, useFrugaWidget };
242
+ export { type FrugaLoaderEvent, type FrugaLoaderEventLevel, type FrugaLoaderEventType, FrugaWidget, type UseFrugaWidgetResult, WidgetUI, getBalance, requestBalance, useFrugaWidget };
@@ -1,24 +1,5 @@
1
1
  import React, { ReactNode } from 'react';
2
2
 
3
- interface LoaderOptions {
4
- partnerKey: string;
5
- containerId?: string;
6
- token?: string;
7
- onTokenRequired?: () => Promise<string>;
8
- theme?: 'light' | 'dark';
9
- primaryColor?: string;
10
- appUrl?: string;
11
- autoMount?: boolean;
12
- userId?: string;
13
- baseUrl?: string;
14
- }
15
-
16
- declare const requestBalance: () => void;
17
- declare const getBalance: () => Promise<{
18
- available: number;
19
- pending: number;
20
- }>;
21
-
22
3
  declare const DEFAULT_THEME: {
23
4
  widgetTitle: string;
24
5
  launcherLabel: string;
@@ -72,11 +53,20 @@ interface BootstrapAuth {
72
53
  issuer: string;
73
54
  tokenTtlSeconds: number;
74
55
  }
56
+ /**
57
+ * Who receives the cashback. The wire type is deliberately wider than the two
58
+ * modes the UI knows about: the API may introduce further values, so every
59
+ * consumer narrows through {@link resolvePayoutMode} instead of comparing
60
+ * against a literal.
61
+ */
62
+ type PayoutMode = 'PARTNER' | 'USER';
63
+ /** `partnerPayout` as it arrives on the wire, including values this build does not know. */
64
+ type PartnerPayout = PayoutMode | 'UNKNOWN';
75
65
  interface WidgetBootstrap {
76
66
  partnerEnvId: string;
77
67
  partnerId: string;
78
68
  partnerType: PartnerType;
79
- partnerPayout: 'PARTNER' | 'USER';
69
+ partnerPayout: PartnerPayout;
80
70
  auth: BootstrapAuth;
81
71
  config: {
82
72
  ui: WidgetUiConfig;
@@ -85,6 +75,12 @@ interface WidgetBootstrap {
85
75
  launcherIcon: string[];
86
76
  };
87
77
  };
78
+ /**
79
+ * Absolute URL of the widget document to load. When present the loader uses
80
+ * it instead of its default, which gives ops a kill switch and native
81
+ * wrappers the URL from the same call.
82
+ */
83
+ widgetUrl?: string;
88
84
  }
89
85
  interface RelayConfig {
90
86
  containerId: string;
@@ -113,15 +109,134 @@ interface WidgetContainerProps {
113
109
  theme: Theme;
114
110
  }
115
111
 
116
- declare const useFrugaWidget: (config: LoaderOptions) => {
112
+ /**
113
+ * Why the widget never became usable.
114
+ *
115
+ * - `TIMEOUT`: no FRUGA_READY arrived within `LoaderOptions.loadTimeoutMs`.
116
+ * - `VERSION_MISMATCH`: FRUGA_READY carried an incompatible protocol major.
117
+ * - `BOOTSTRAP_FAILED`: bootstrap could not be resolved and nothing was cached.
118
+ * - `NOT_READY`: a balance request was made before FRUGA_READY and the widget
119
+ * did not become ready in time. Rejects the call only; the mount survives.
120
+ */
121
+ type FrugaLoadErrorCode = 'TIMEOUT' | 'VERSION_MISMATCH' | 'BOOTSTRAP_FAILED' | 'NOT_READY';
122
+ /** Version context attached to a {@link FrugaLoadError}, when known. */
123
+ interface FrugaLoadErrorDetails {
124
+ /** Defaults to the running loader's package version. */
125
+ loaderVersion?: string;
126
+ /** Widget bundle version, as reported in FRUGA_READY. */
127
+ widgetVersion?: string;
128
+ /** Widget protocol version, as reported in FRUGA_READY. */
129
+ protocolVersion?: string;
130
+ }
131
+ /**
132
+ * Host-facing load failure handed to `LoaderOptions.onError`. Carries enough
133
+ * version context for a partner to file a useful bug report.
134
+ */
135
+ declare class FrugaLoadError extends Error {
136
+ readonly code: FrugaLoadErrorCode;
137
+ readonly loaderVersion: string;
138
+ readonly widgetVersion?: string;
139
+ readonly protocolVersion?: string;
140
+ constructor(code: FrugaLoadErrorCode, message: string, details?: FrugaLoadErrorDetails);
141
+ }
142
+
143
+ interface Balance {
144
+ available: number;
145
+ pending: number;
146
+ }
147
+ /**
148
+ * Channel a {@link FrugaLoaderEvent} belongs to: `lifecycle` for mount/ready/
149
+ * token milestones, `protocol` for every postMessage in or out, `log` for
150
+ * anything the loader would otherwise only write to the console, and `error`
151
+ * for a {@link FrugaLoadError} - and only that. The split mirrors the native
152
+ * bridge, where `log` and `error` are separate messages.
153
+ */
154
+ type FrugaLoaderEventType = 'lifecycle' | 'protocol' | 'log' | 'error';
155
+ /**
156
+ * Severity of a {@link FrugaLoaderEvent}. `lifecycle` and `protocol` are always
157
+ * `info`, `error` is always `error`, `log` carries the level of the console call
158
+ * it replaces.
159
+ */
160
+ type FrugaLoaderEventLevel = 'info' | 'warn' | 'error';
161
+ /**
162
+ * Diagnostic event handed to `LoaderOptions.onEvent`. Deliberately flat and
163
+ * JSON-serialisable: the native SDKs forward exactly this shape to their
164
+ * partner log sink, so `name` values are stable API. Never carries a token.
165
+ */
166
+ interface FrugaLoaderEvent {
167
+ type: FrugaLoaderEventType;
168
+ level: FrugaLoaderEventLevel;
169
+ /** Lifecycle milestone, protocol message type, log name, or error code. */
170
+ name: string;
171
+ data?: unknown;
172
+ /** `Date.now()` when the event was emitted. */
173
+ ts: number;
174
+ }
175
+ interface LoaderOptions {
176
+ partnerKey: string;
177
+ containerId?: string;
178
+ token?: string;
179
+ onTokenRequired?: () => Promise<string>;
180
+ theme?: 'light' | 'dark';
181
+ primaryColor?: string;
182
+ appUrl?: string;
183
+ autoMount?: boolean;
184
+ userId?: string;
185
+ baseUrl?: string;
186
+ /** Mount with the widget's panel already open. Used by the native shell. */
187
+ panelOpen?: boolean;
188
+ /**
189
+ * Delivers the reply to a fire-and-forget `requestBalance()` call. Without it
190
+ * `requestBalance()` has no consumer and does nothing; use `getBalance()` for
191
+ * the promise-based form.
192
+ */
193
+ onBalance?: (balance: Balance) => void;
194
+ /**
195
+ * How long to wait for the widget's FRUGA_READY before the mount is treated
196
+ * as failed. Defaults to {@link DEFAULT_LOAD_TIMEOUT_MS}; `0` disables the
197
+ * timeout entirely.
198
+ */
199
+ loadTimeoutMs?: number;
200
+ /**
201
+ * Called once per failed mount. The loader has already removed the iframe and
202
+ * rendered its own minimal error element inside the container; call
203
+ * `FrugaHandle.retry()` to try again.
204
+ */
205
+ onError?: (error: FrugaLoadError) => void;
206
+ /**
207
+ * Diagnostic sink: lifecycle milestones, every postMessage in or out, every
208
+ * diagnostic the loader would otherwise log, and every load error. When set it
209
+ * *replaces* the loader's console output; without it the console stays the
210
+ * default sink.
211
+ */
212
+ onEvent?: (event: FrugaLoaderEvent) => void;
213
+ }
214
+
215
+ declare const requestBalance: () => void;
216
+ declare const getBalance: () => Promise<Balance>;
217
+
218
+ interface UseFrugaWidgetResult {
117
219
  mount: () => Promise<void>;
118
220
  unmount: () => void;
119
- };
221
+ /** Clears the error and mounts once more. The loader never retries by itself. */
222
+ retry: () => Promise<void>;
223
+ /** Last load failure, or `null` while the widget is healthy. */
224
+ error: FrugaLoadError | null;
225
+ }
226
+ declare const useFrugaWidget: (config: LoaderOptions) => UseFrugaWidgetResult;
227
+ /** `LoaderOptions` (including `onError` and `loadTimeoutMs`) are the props. */
120
228
  declare const FrugaWidget: React.FC<LoaderOptions>;
121
229
  /**
122
- * A wrapper component that provides the WidgetProvider context around the WidgetContainer.
123
- * This ensures that any child components or the container itself can access the WidgetContext.
230
+ * Widget-side shell: owns the `PostMessageTransport` to the host window and
231
+ * provides it to `WidgetHandshake`, which announces FRUGA_READY once the
232
+ * subscribers below are mounted.
233
+ *
234
+ * The transport is built in an effect rather than in render (or a lazily
235
+ * initialised ref) so React StrictMode's double-invoked effects leave exactly
236
+ * one live, undisposed transport behind - same trade-off as `RelayEntry`. The
237
+ * cost is one `null` first paint, which is invisible: nothing below has data
238
+ * before FRUGA_INIT arrives anyway.
124
239
  */
125
240
  declare const WidgetUI: React.FC<WidgetContainerProps>;
126
241
 
127
- export { FrugaWidget, WidgetUI, getBalance, requestBalance, useFrugaWidget };
242
+ export { type FrugaLoaderEvent, type FrugaLoaderEventLevel, type FrugaLoaderEventType, FrugaWidget, type UseFrugaWidgetResult, WidgetUI, getBalance, requestBalance, useFrugaWidget };
@@ -1,4 +1,4 @@
1
- "use strict";var we=Object.create;var y=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var Pe=Object.getOwnPropertyNames;var Ae=Object.getPrototypeOf,Be=Object.prototype.hasOwnProperty;var Fe=(a,e,t)=>e in a?y(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var ye=(a,e)=>{for(var t in e)y(a,t,{get:e[t],enumerable:!0})},ae=(a,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let u of Pe(e))!Be.call(a,u)&&u!==t&&y(a,u,{get:()=>e[u],enumerable:!(o=ke(e,u))||o.enumerable});return a};var Me=(a,e,t)=>(t=a!=null?we(Ae(a)):{},ae(e||!a||!a.__esModule?y(t,"default",{value:a,enumerable:!0}):t,a)),Te=a=>ae(y({},"__esModule",{value:!0}),a);var H=(a,e,t)=>Fe(a,typeof e!="symbol"?e+"":e,t);var Ze={};ye(Ze,{FrugaWidget:()=>Xe,WidgetUI:()=>Ke,getBalance:()=>Y,requestBalance:()=>j,useFrugaWidget:()=>ge});module.exports=Te(Ze);var O=require("react");var te={widgetTitle:"Savings Box",launcherLabel:"Insurance Savings",launcherIcon:"arrow",showLauncher:!0,mode:"light",allowUserThemeControl:!1,defaultTheme:"light",uiVersion:"current",primary:"#1E40AF",accent:"#2648C9",accentTextLight:"#FFFFFF",accentTextDark:"#FFFFFF",bg:"#0B1220",panel:"#0F1A2E",panel2:"#111F38",itemBg:"rgba(255,255,255,0.03)",text:"#E6EDF7",muted:"#A7B3C6",border:"rgba(255,255,255,0.08)",success:"#34D399",danger:"#EF4444",warning:"#FBBF24",lightBg:"#F8FAFC",lightPanel:"#FFFFFF",lightPanel2:"#F1F5F9",lightItemBg:"rgba(0,0,0,0.04)",lightText:"#0F172A",lightMuted:"#64748B",lightBorder:"rgba(0,0,0,0.1)"};function oe(a){let e=a.mode==="light",t=e?a.textColorLight?.trim()||a.lightText:a.textColorDark?.trim()||a.text;return{...a,bg:e?a.lightBg:a.bg,panel:e?a.lightPanel:a.panel,panel2:e?a.lightPanel2:a.panel2,itemBg:e?a.lightItemBg:a.itemBg,text:t,muted:e?a.lightMuted:a.muted,border:e?a.lightBorder:a.border,subtleBg:e?"rgba(0,0,0,0.02)":"rgba(255,255,255,0.03)",tooltipBg:e?"#FFFFFF":"#0B1220",tooltipBorder:e?"rgba(0,0,0,0.12)":"rgba(255,255,255,0.12)",accentText:e?a.accentTextLight?.trim()||"#0F172A":a.accentTextDark?.trim()||"#FFFFFF",isLight:e,mode:a.mode}}var Re=require("react/jsx-runtime");var g=require("react");var G=require("react");var E=(...a)=>a.filter((e,t,o)=>!!e&&e.trim()!==""&&o.indexOf(e)===t).join(" ").trim();var ue=a=>a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();var de=a=>a.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,o)=>o?o.toUpperCase():t.toLowerCase());var _=a=>{let e=de(a);return e.charAt(0).toUpperCase()+e.slice(1)};var M=require("react");var W={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var le=a=>{for(let e in a)if(e.startsWith("aria-")||e==="role"||e==="title")return!0;return!1};var B=require("react");var be=(0,B.createContext)({});var re=()=>(0,B.useContext)(be);var se=(0,M.forwardRef)(({color:a,size:e,strokeWidth:t,absoluteStrokeWidth:o,className:u="",children:d,iconNode:c,...s},i)=>{let{size:l=24,strokeWidth:r=2,absoluteStrokeWidth:I=!1,color:h="currentColor",className:p=""}=re()??{},f=o??I?Number(t??r)*24/Number(e??l):t??r;return(0,M.createElement)("svg",{ref:i,...W,width:e??l??W.width,height:e??l??W.height,stroke:a??h,strokeWidth:f,className:E("lucide",p,u),...!d&&!le(s)&&{"aria-hidden":"true"},...s},[...c.map(([w,x])=>(0,M.createElement)(w,x)),...Array.isArray(d)?d:[d]])});var C=(a,e)=>{let t=(0,G.forwardRef)(({className:o,...u},d)=>(0,G.createElement)(se,{ref:d,iconNode:e,className:E(`lucide-${ue(_(a))}`,`lucide-${a}`,o),...u}));return t.displayName=_(a),t};var qe=[["rect",{width:"20",height:"14",x:"2",y:"5",rx:"2",key:"ynyp8z"}],["line",{x1:"2",x2:"22",y1:"10",y2:"10",key:"1b3vmo"}]],T=C("credit-card",qe);var ve=[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8",key:"1sqzm4"}],["path",{d:"M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5",key:"kc0143"}],["rect",{x:"3",y:"7",width:"18",height:"4",rx:"1",key:"1hberx"}]],D=C("gift",ve);var Ue=[["path",{d:"M13 5H19V11",key:"1n1gyv"}],["path",{d:"M19 5L5 19",key:"72u4yj"}]],R=C("move-up-right",Ue);var Oe=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],S=C("sparkles",Oe);var He=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],b=C("x",He);var q=require("react/jsx-runtime");function fe({theme:a}){return a.launcherIcon==="none"?null:a.launcherIcon==="sparkles"?(0,q.jsx)(S,{size:20}):a.launcherIcon==="credit"?(0,q.jsx)(T,{size:20}):a.launcherIcon==="arrow"?(0,q.jsx)(R,{size:20}):(0,q.jsx)(D,{size:20})}var V=require("react");var ie=a=>{let e,t=new Set,o=(l,r)=>{let I=typeof l=="function"?l(e):l;if(!Object.is(I,e)){let h=e;e=r??(typeof I!="object"||I===null)?I:Object.assign({},e,I),t.forEach(p=>p(e,h))}},u=()=>e,s={setState:o,getState:u,getInitialState:()=>i,subscribe:l=>(t.add(l),()=>t.delete(l))},i=e=a(o,u,s);return s},ne=(a=>a?ie(a):ie);var v=Me(require("react"),1);var Ee=a=>a;function We(a,e=Ee){let t=v.default.useSyncExternalStore(a.subscribe,v.default.useCallback(()=>e(a.getState()),[a,e]),v.default.useCallback(()=>e(a.getInitialState()),[a,e]));return v.default.useDebugValue(t),t}var ce=a=>{let e=ne(a),t=o=>We(e,o);return Object.assign(t,e),t},pe=(a=>a?ce(a):ce);var P=pe(a=>({isOpen:!1,isFocused:!0,isIdle:!1,available:0,pending:0,mode:"light",token:null,partnerPayout:null,isAddingPayoutFromAlert:!1,showPayoutSuccess:!1,toggle:()=>a(e=>({isOpen:!e.isOpen})),setOpen:e=>a({isOpen:e}),setFocused:e=>a({isFocused:e}),setIdle:e=>a({isIdle:e}),setBalances:(e,t)=>a({available:e,pending:t}),setMode:e=>a({mode:e}),setToken:e=>a({token:e}),setPartnerPayout:e=>a({partnerPayout:e}),setIsAddingPayoutFromAlert:e=>a({isAddingPayoutFromAlert:e}),setShowPayoutSuccess:e=>a({showPayoutSuccess:e})}));function me(){let{setFocused:a,setIdle:e}=P(),t=(0,V.useRef)(null);(0,V.useEffect)(()=>{let o=()=>a(!0),u=()=>a(!1),d=()=>{e(!1),t.current&&clearTimeout(t.current),t.current=setTimeout(()=>{e(!0)},6e4)},c=()=>{d()};d(),a(document.hasFocus()),window.addEventListener("focus",o),window.addEventListener("blur",u);let s=["mousemove","keydown","scroll","touchstart","mousedown"];return s.forEach(i=>{window.addEventListener(i,c,i==="scroll"?!0:void 0)}),()=>{window.removeEventListener("focus",o),window.removeEventListener("blur",u),s.forEach(i=>{window.removeEventListener(i,c,i==="scroll"?!0:void 0)}),t.current&&clearTimeout(t.current)}},[a,e])}var L=require("react/jsx-runtime"),Le=({children:a,theme:e,hostHeight:t=800,isMobile:o=!1})=>{me();let{isOpen:u,toggle:d,mode:c}=P(),s=e||te,[i,l]=(0,g.useState)(t),[r,I]=(0,g.useState)(o),h=s.allowUserThemeControl?{...s,mode:c}:{...s,mode:s.mode||"light"},p=oe(h),f=(0,g.useRef)(null),w=(0,g.useRef)(null);return(0,g.useEffect)(()=>{let x=m=>{if(m.data?.type==="FRUGA_HOST_RESIZE"&&(l(m.data.hostHeight),I(m.data.isHostMobile)),m.data?.type==="FRUGA_TOKEN_UPDATE"){let{setToken:n}=P.getState();n(m.data.token)}if(m.data?.type==="FRUGA_GET_BALANCE"){let{available:n,pending:k}=P.getState();console.log("FRUGA_GET_BALANCE",n,k),window.parent.postMessage({type:"FRUGA_BALANCE_RESPONSE",requestId:m.data.requestId,available:n,pending:k},"*")}};return window.addEventListener("message",x),()=>window.removeEventListener("message",x)},[]),(0,g.useEffect)(()=>{if(!f.current)return;let x=()=>{if(!f.current)return;let n=u?450:100;!u&&w.current&&(n=w.current.offsetWidth+40);let k=u?Math.max(200,i-100):100;r&&u&&(n=window.innerWidth,k=i),window.parent.postMessage({type:"FRUGA_RESIZE",height:k,width:n,isFullscreen:r&&u},"*")},m=new ResizeObserver(()=>x());return m.observe(f.current),x(),()=>m.disconnect()},[u,i,r]),(0,L.jsxs)("div",{ref:f,className:p.mode==="dark"?"dark":"",style:{fontFamily:'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',color:p.text,display:"flex",flexDirection:"column",alignItems:"flex-end",justifyContent:"flex-end",padding:r&&u?"0":"20px",boxSizing:"border-box",height:"100%",margin:0,overscrollBehavior:"contain"},children:[u&&(0,L.jsx)("div",{style:{width:r?"100vw":"410px",minWidth:r?"100vw":"410px",flexShrink:0,maxHeight:r?"100vh":`${Math.max(100,i-100)}px`,height:"100%",marginBottom:r?"0":"20px",backgroundColor:p.accent,borderRadius:r?"0":"16px",boxShadow:r?"none":"0 20px 40px -10px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0,0,0,0.1)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9998},children:(0,L.jsx)("div",{className:"fruga-scrollbar",style:{flex:1,minHeight:0,backgroundColor:p.isLight?"#f9f9f9":"#111",display:"flex",flexDirection:"column",boxShadow:r?"none":"0 20px 40px -10px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0,0,0,0.1)"},children:a})}),(0,L.jsxs)("button",{ref:w,onClick:d,style:{backgroundColor:p.accent,color:p.accentText,border:"none",cursor:"pointer",boxShadow:"0 12px 30px -5px rgba(0, 0, 0, 0.1), 0 0 1px rgba(0,0,0, 0.1)",display:u?"none":"flex",alignItems:"center",justifyContent:"center",zIndex:9999,flexShrink:0,borderRadius:"20px",padding:"10px 16px",transition:"transform 0.3s ease-in-out"},className:"flex h-15 items-center gap-2 rounded-xl px-4 active:scale-[0.99]","aria-label":u?"Close widget":"Open widget",children:[s.launcherLabel&&!u?(0,L.jsxs)(L.Fragment,{children:[s.launcherLabel!=="none"&&(0,L.jsx)("div",{className:"text-sm font-semibold",children:s.launcherLabel}),(0,L.jsx)("div",{className:"flex h-6 w-5 shrink-0 items-center justify-center",children:(0,L.jsx)(fe,{theme:p})})]}):null,u?(0,L.jsx)(b,{}):null]})]})};var Ie=require("react/jsx-runtime");var xe=require("react");var U={BOOTSTRAP_DATA:"fruga_bootstrap",BOOTSTRAP_CONFIG:"fruga_active_config"},A=class{static set(e,t){if(!(typeof window>"u"))try{window.localStorage.setItem(e,JSON.stringify(t))}catch(o){console.warn(`[FrugaStorage] Failed to save key "${e}":`,o)}}static get(e){if(typeof window>"u")return null;try{let t=window.localStorage.getItem(e);return t?JSON.parse(t):null}catch(t){return console.warn(`[FrugaStorage] Failed to load key "${e}":`,t),null}}static remove(e){typeof window>"u"||window.localStorage.removeItem(e)}static clear(){typeof window>"u"||window.localStorage.clear()}};var Ve=typeof process<"u"&&process.env.VITE_FRUGA_API_URL||"https://api-dev.fruga.co.uk",Ce=a=>a||Ve;var Q={partnerEnvId:"env_dev_123",partnerId:"partner_abc_456",partnerType:"EXTERNAL_TENANT",partnerPayout:"USER",auth:{mode:"JWT",audience:"https://api.fruga.io",issuer:"https://auth.fruga.io",tokenTtlSeconds:70},config:{ui:{accent:"#F97316",defaultTheme:"light",launcherIcon:"arrow",showLauncher:!0,launcherLabel:"Help",accentTextDark:"#832424",accentTextLight:"#d81414",allowUserThemeControl:!0},validValues:{defaultTheme:["light","dark"],launcherIcon:["none","gift","sparkles","credit","arrow"]}}};var z=class{async bootstrap(e,t){let o=Ce(t);if(typeof process<"u"&&process.env.VITE_FRUGA_MODE==="test")return console.log("Fruga SDK: Using bootstrap mocks (VITE_FRUGA_MODE=test)"),Q;try{let d=await fetch(`${o}/widget/bootstrap?partnerKey=${e}`,{method:"GET",headers:{Accept:"application/json","Content-Type":"application/json"}});if(!d.ok)throw new Error(`Bootstrap failed with status: ${d.status}`);return await d.json()}catch(d){return console.error("Fruga SDK: Bootstrap failed, falling back to mocks",d),Q}}};var N=class{mount(e,t,o){let{partnerKey:u,theme:d,primaryColor:c,appUrl:s,userId:i}=o,l=document.createElement("iframe"),r=t.partnerType==="EXTERNAL_TENANT"?"relay":"connect",I=typeof document<"u"?document.currentScript:null,h=I?.src||(typeof window<"u"?window.location.href:""),p=`./${r}/index.html`;if(!I)p=`https://frugainsurance.github.io/sdk/${r}/index.html`;else try{new URL(h).pathname.includes("/dist/")&&(p=`./${r}/index.html`)}catch{}let f=new URL(s||t.appUrl||p,h);f.searchParams.set("partnerKey",u),f.searchParams.set("partnerId",t.partnerId);let w=typeof window<"u"?window.innerWidth<768:!1;if(f.searchParams.set("isHostMobile",String(w)),typeof window<"u"&&(f.searchParams.set("hostHeight",String(window.innerHeight)),f.searchParams.set("hostWidth",String(window.innerWidth))),d&&f.searchParams.set("theme",d),c&&f.searchParams.set("primaryColor",c),i&&f.searchParams.set("userId",i),t.token&&f.searchParams.set("token",t.token),o.baseUrl&&f.searchParams.set("baseUrl",o.baseUrl),t.bootstrapConfig)try{let n=btoa(JSON.stringify(t.bootstrapConfig));f.searchParams.set("bootstrapConfig",n)}catch(n){console.warn("FrugaLoader: Failed to encode bootstrapConfig for iframe URL",n)}l.src=f.toString(),l.style.border="none",l.style.width="410px",l.style.height="600px",l.style.backgroundColor="transparent";let x=n=>{if(n.source===l.contentWindow&&n.data?.type==="FRUGA_RESIZE"){let{width:k,height:he,isFullscreen:Se}=n.data;Se?(l.style.position="fixed",l.style.inset="0",l.style.width="100vw",l.style.height="100vh",l.style.zIndex="99999"):(l.style.position="static",l.style.width=`${k}px`,l.style.height=`${he}px`,l.style.zIndex="auto")}},m=()=>{l.contentWindow?.postMessage({type:"FRUGA_HOST_RESIZE",isHostMobile:window.innerWidth<768,hostHeight:window.innerHeight,hostWidth:window.innerWidth},"*")};return window.addEventListener("message",x),window.addEventListener("resize",m),e.appendChild(l),{iframe:l,cleanup:()=>{window.removeEventListener("message",x),window.removeEventListener("resize",m)}}}unmount(e){e.remove()}};var X=class{constructor(e,t){this.bootstrapService=e;this.widgetMounter=t;H(this,"state",{container:null,iframe:null,options:null,currentToken:null});H(this,"pendingRequests",new Map);H(this,"handleIframeMessage",async e=>{if(!(this.state.iframe&&e.source!==this.state.iframe.contentWindow)){if(e.data?.type==="NEED_TOKEN"&&this.state.options?.onTokenRequired)try{let t=await this.state.options.onTokenRequired();this.state.currentToken=t,this.state.iframe?.contentWindow?.postMessage({type:"FRUGA_TOKEN_UPDATE",token:t},"*")}catch(t){console.error("FrugaLoader: Failed to refresh token:",t)}if(e.data?.type==="FRUGA_BALANCE_RESPONSE"){let{requestId:t,available:o,pending:u}=e.data;if(t&&this.pendingRequests.has(t)){let{resolve:d,timeout:c}=this.pendingRequests.get(t);clearTimeout(c),this.pendingRequests.delete(t),d({available:o,pending:u})}}}})}async init(e){if(this.state.options=e,e.autoMount!==!1){if(e.token&&(this.state.currentToken=e.token),e.onTokenRequired)try{this.state.currentToken=await e.onTokenRequired()}catch(o){console.error("FrugaLoader: Failed to fetch initial token:",o)}await this.mount()}}setOptions(e){this.state.options=e}async mount(){if(!this.state.options||this.state.container&&this.state.iframe&&document.body.contains(this.state.container))return;let e=A.get(U.BOOTSTRAP_DATA);if(e)this.doMount(e);else{let t=A.get(U.BOOTSTRAP_CONFIG);if(t){let o={partnerEnvId:"cached",partnerId:"cached",partnerType:"EXTERNAL_TENANT",partnerPayout:"USER",auth:{mode:"none",audience:"",issuer:"",tokenTtlSeconds:0},config:t};this.doMount(o)}}try{let t=await this.bootstrapService.bootstrap(this.state.options.partnerKey,this.state.options.baseUrl);A.set(U.BOOTSTRAP_DATA,t),A.set(U.BOOTSTRAP_CONFIG,t.config),this.doMount(t)}catch{}}doMount(e){if(!this.state.options)return;let{containerId:t="fruga-widget-root"}=this.state.options,o=document.getElementById(t);o?o.innerHTML="":(o=document.createElement("div"),o.id=t,document.body.appendChild(o)),o.style.position="fixed",o.style.bottom="0px",o.style.right="0px",o.style.zIndex="9999";let d={...{...this.state.options,containerId:this.state.options.containerId||"fruga-widget-root",bootstrapConfig:e,token:this.state.currentToken||void 0},partnerId:e.partnerId,partnerType:e.partnerType},{iframe:c,cleanup:s}=this.widgetMounter.mount(o,d,this.state.options);this.state.container=o,this.state.iframe=c,o._frugaCleanup=s,window.addEventListener("message",this.handleIframeMessage)}unmount(){if(this.state.container&&document.body.contains(this.state.container)){let e=this.state.container._frugaCleanup;e?.(),this.widgetMounter.unmount(this.state.container)}this.state.container=null,this.state.iframe=null,window.removeEventListener("message",this.handleIframeMessage)}requestBalance(){this.state.iframe&&this.state.iframe.contentWindow?.postMessage({type:"FRUGA_GET_BALANCE"},"*")}async getBalance(){if(!this.state.iframe)throw new Error("FrugaLoader: Cannot get balance - widget not mounted");let e=Math.random().toString(36).substring(2,15);return new Promise((t,o)=>{let u=setTimeout(()=>{this.pendingRequests.has(e)&&(this.pendingRequests.delete(e),o(new Error("FrugaLoader: Get balance request timed out")))},5e3);this.pendingRequests.set(e,{resolve:t,reject:o,timeout:u}),this.state.iframe?.contentWindow?.postMessage({type:"FRUGA_GET_BALANCE",requestId:e},"*")})}};var ze=new z,Ne=new N,F=new X(ze,Ne),J=async()=>{await F.mount()},Z=()=>{F.unmount()},K=async a=>{await F.init(a)},$=a=>{F.setOptions(a)},j=()=>{F.requestBalance()},Y=async()=>F.getBalance();if(typeof window<"u"){let a=document.currentScript;if(a){let e=a.getAttribute("data-partner-key"),t=a.getAttribute("data-container-id")||void 0,o=a.getAttribute("data-app-url")||void 0,u=a.getAttribute("data-base-url")||void 0,d=window.frugaConfig||{};(e||d.partnerKey)&&K({partnerKey:e||d.partnerKey||"demo-key",containerId:t||d.containerId,appUrl:o||d.appUrl,baseUrl:u||d.baseUrl,theme:d.theme,primaryColor:d.primaryColor})}window.FrugaLoader={init:K,setOptions:$,mount:J,unmount:Z,requestBalance:j,getBalance:Y}}var ee=require("react/jsx-runtime");var ge=a=>{let e=(0,O.useRef)(!1);return(0,O.useEffect)(()=>{e.current&&$(a)},[a]),(0,O.useEffect)(()=>(e.current||K(a).then(()=>{e.current=!0}),()=>{Z(),e.current=!1}),[a.partnerKey,a.appUrl]),{mount:J,unmount:Z}},Xe=a=>{let e=a.containerId||"fruga-widget-container";return ge({...a,containerId:e,autoMount:!0}),(0,ee.jsx)("div",{id:e,style:{width:"100%",height:"100%"}})},Ke=({children:a,...e})=>(0,ee.jsx)(Le,{...e,children:a});0&&(module.exports={FrugaWidget,WidgetUI,getBalance,requestBalance,useFrugaWidget});
1
+ "use strict";var je=Object.create;var v=Object.defineProperty;var Je=Object.getOwnPropertyDescriptor;var Ye=Object.getOwnPropertyNames;var ea=Object.getPrototypeOf,aa=Object.prototype.hasOwnProperty;var ta=(t,e,a)=>e in t?v(t,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[e]=a;var oa=(t,e)=>{for(var a in e)v(t,a,{get:e[a],enumerable:!0})},xe=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Ye(e))!aa.call(t,r)&&r!==a&&v(t,r,{get:()=>e[r],enumerable:!(o=Je(e,r))||o.enumerable});return t};var ra=(t,e,a)=>(a=t!=null?je(ea(t)):{},xe(e||!t||!t.__esModule?v(a,"default",{value:t,enumerable:!0}):a,t)),ua=t=>xe(v({},"__esModule",{value:!0}),t);var l=(t,e,a)=>ta(t,typeof e!="symbol"?e+"":e,a);var va={};oa(va,{FrugaWidget:()=>Ba,WidgetUI:()=>Da,getBalance:()=>oe,requestBalance:()=>te,useFrugaWidget:()=>$e});module.exports=ua(va);var p=require("react");var da=["loader.global.js","native.global.js"],sa=()=>{if(typeof document>"u")return null;let e=document.currentScript?.src;if(!e)return null;try{let a=new URL(e,document.baseURI),o=a.pathname.split("/").pop()??"";return da.includes(o)?a.toString():null}catch{return null}},se=sa();var ge={widgetTitle:"Savings Box",launcherLabel:"Insurance Savings",launcherIcon:"arrow",showLauncher:!0,mode:"light",allowUserThemeControl:!1,defaultTheme:"light",uiVersion:"current",primary:"#1E40AF",accent:"#2648C9",accentTextLight:"#FFFFFF",accentTextDark:"#FFFFFF",bg:"#0B1220",panel:"#0F1A2E",panel2:"#111F38",itemBg:"rgba(255,255,255,0.03)",text:"#E6EDF7",muted:"#A7B3C6",border:"rgba(255,255,255,0.08)",success:"#34D399",danger:"#EF4444",warning:"#FBBF24",lightBg:"#F8FAFC",lightPanel:"#FFFFFF",lightPanel2:"#F1F5F9",lightItemBg:"rgba(0,0,0,0.04)",lightText:"#0F172A",lightMuted:"#64748B",lightBorder:"rgba(0,0,0,0.1)"};function he(t){let e=t.mode==="light",a=e?t.textColorLight?.trim()||t.lightText:t.textColorDark?.trim()||t.text;return{...t,bg:e?t.lightBg:t.bg,panel:e?t.lightPanel:t.panel,panel2:e?t.lightPanel2:t.panel2,itemBg:e?t.lightItemBg:t.itemBg,text:a,muted:e?t.lightMuted:t.muted,border:e?t.lightBorder:t.border,subtleBg:e?"rgba(0,0,0,0.02)":"rgba(255,255,255,0.03)",tooltipBg:e?"#FFFFFF":"#0B1220",tooltipBorder:e?"rgba(0,0,0,0.12)":"rgba(255,255,255,0.12)",accentText:e?t.accentTextLight?.trim()||"#0F172A":t.accentTextDark?.trim()||"#FFFFFF",isLight:e,mode:t.mode}}var la=["NEED_TOKEN","FRUGA_TOKEN_UPDATE","FRUGA_GET_BALANCE","FRUGA_BALANCE_RESPONSE","FRUGA_RESIZE","FRUGA_HOST_RESIZE","FRUGA_READY","FRUGA_INIT"],fa=t=>typeof t=="string"&&la.includes(t),ia=["ttl","unauthorized"],Ce=t=>{if(typeof t!="object"||t===null)return!1;let e=t;if(!fa(e.type)||e.version!==void 0&&typeof e.version!="string")return!1;if(e.type==="NEED_TOKEN"){let{reason:a}=t;return typeof a=="string"&&ia.includes(a)}return!0},le=t=>Number.parseInt(t.split(".")[0]??"",10);var Se=t=>t==="PARTNER"||t==="USER"?t:null;var ca="*",A=class{constructor(e){l(this,"target");l(this,"acceptSource");l(this,"listenOn");l(this,"handlers",new Set);l(this,"pinOriginFrom");l(this,"targetOrigin");l(this,"acceptOrigin");l(this,"pinned",null);l(this,"disposed",!1);l(this,"onMessage",e=>{if(this.disposed||this.acceptSource&&e.source!==this.acceptSource||this.acceptOrigin&&e.origin!==this.acceptOrigin||!Ce(e.data)||!this.admitWhileUnpinned(e.data.type,e.origin))return;let a=typeof e.data.version=="string"&&e.data.version.length>0?e.data:{...e.data,version:"1.0"};for(let o of[...this.handlers])o(a)});let a=e.listenOn??(typeof window<"u"?window:void 0);if(!a)throw new Error("PostMessageTransport: no window to listen on; pass options.listenOn");this.target=e.target,this.targetOrigin=e.targetOrigin,this.acceptSource=e.acceptSource,this.acceptOrigin=e.acceptOrigin,this.pinOriginFrom=e.pinOriginFrom,this.listenOn=a,this.listenOn.addEventListener("message",this.onMessage)}get pinnedOrigin(){return this.pinned}pinOrigin(e){this.targetOrigin=e,this.acceptOrigin=e,this.pinned=e}send(e){if(this.disposed)return;let a=typeof e.version=="string"&&e.version.length>0?e:{...e,version:"1.0"};this.target.postMessage(a,this.targetOrigin)}subscribe(e){if(this.disposed)throw new Error("PostMessageTransport: cannot subscribe after dispose()");return this.handlers.add(e),()=>{this.handlers.delete(e)}}dispose(){this.disposed||(this.disposed=!0,this.handlers.clear(),this.listenOn.removeEventListener("message",this.onMessage))}admitWhileUnpinned(e,a){return!this.pinOriginFrom||this.pinned!==null?!0:e!==this.pinOriginFrom?!1:a&&a!=="null"?(this.pinOrigin(a),!0):(this.pinned=ca,!0)}};var we=t=>{let e=t?.listenOn??(typeof window<"u"?window:void 0);if(!e)throw new Error("createHostTransport: no window available; pass options.listenOn");let a=e.parent!==e;return new A({target:e.parent,targetOrigin:"*",pinOriginFrom:"FRUGA_INIT",listenOn:e,...a?{acceptSource:e.parent}:{}})};var w=require("react");var K=require("react");var z=(...t)=>t.filter((e,a,o)=>!!e&&e.trim()!==""&&o.indexOf(e)===a).join(" ").trim();var ke=t=>t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();var Pe=t=>t.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,a,o)=>o?o.toUpperCase():a.toLowerCase());var ie=t=>{let e=Pe(t);return e.charAt(0).toUpperCase()+e.slice(1)};var b=require("react");var X={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var Fe=t=>{for(let e in t)if(e.startsWith("aria-")||e==="role"||e==="title")return!0;return!1};var y=require("react");var pa=(0,y.createContext)({});var Me=()=>(0,y.useContext)(pa);var Te=(0,b.forwardRef)(({color:t,size:e,strokeWidth:a,absoluteStrokeWidth:o,className:r="",children:u,iconNode:d,...s},f)=>{let{size:n=24,strokeWidth:i=2,absoluteStrokeWidth:m=!1,color:g="currentColor",className:x=""}=Me()??{},re=o??m?Number(a??i)*24/Number(e??n):a??i;return(0,b.createElement)("svg",{ref:f,...X,width:e??n??X.width,height:e??n??X.height,stroke:t??g,strokeWidth:re,className:z("lucide",x,r),...!u&&!Fe(s)&&{"aria-hidden":"true"},...s},[...d.map(([S,T])=>(0,b.createElement)(S,T)),...Array.isArray(u)?u:[u]])});var h=(t,e)=>{let a=(0,K.forwardRef)(({className:o,...r},u)=>(0,K.createElement)(Te,{ref:u,iconNode:e,className:z(`lucide-${ke(ie(t))}`,`lucide-${t}`,o),...r}));return a.displayName=ie(t),a};var ma=[["rect",{width:"20",height:"14",x:"2",y:"5",rx:"2",key:"ynyp8z"}],["line",{x1:"2",x2:"22",y1:"10",y2:"10",key:"1b3vmo"}]],O=h("credit-card",ma);var La=[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8",key:"1sqzm4"}],["path",{d:"M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5",key:"kc0143"}],["rect",{x:"3",y:"7",width:"18",height:"4",rx:"1",key:"1hberx"}]],q=h("gift",La);var Ia=[["path",{d:"M13 5H19V11",key:"1n1gyv"}],["path",{d:"M19 5L5 19",key:"72u4yj"}]],U=h("move-up-right",Ia);var xa=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],F=h("sparkles",xa);var ga=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],E=h("x",ga);var H=require("react/jsx-runtime");function Ae({theme:t}){return t.launcherIcon==="none"?null:t.launcherIcon==="sparkles"?(0,H.jsx)(F,{size:20}):t.launcherIcon==="credit"?(0,H.jsx)(O,{size:20}):t.launcherIcon==="arrow"?(0,H.jsx)(U,{size:20}):(0,H.jsx)(q,{size:20})}var Z=require("react");var ye=t=>{let e,a=new Set,o=(n,i)=>{let m=typeof n=="function"?n(e):n;if(!Object.is(m,e)){let g=e;e=i??(typeof m!="object"||m===null)?m:Object.assign({},e,m),a.forEach(x=>x(e,g))}},r=()=>e,s={setState:o,getState:r,getInitialState:()=>f,subscribe:n=>(a.add(n),()=>a.delete(n))},f=e=t(o,r,s);return s},Be=(t=>t?ye(t):ye);var G=ra(require("react"),1);var ha=t=>t;function Ca(t,e=ha){let a=G.default.useSyncExternalStore(t.subscribe,G.default.useCallback(()=>e(t.getState()),[t,e]),G.default.useCallback(()=>e(t.getInitialState()),[t,e]));return G.default.useDebugValue(a),a}var Re=t=>{let e=Be(t),a=o=>Ca(e,o);return Object.assign(a,e),a},De=(t=>t?Re(t):Re);var C=De(t=>({isOpen:!1,isFocused:!0,isIdle:!1,available:0,pending:0,mode:"light",token:null,tokenEpoch:0,authStatus:"pending",partnerPayout:null,isAddingPayoutFromAlert:!1,showPayoutSuccess:!1,toggle:()=>t(e=>({isOpen:!e.isOpen})),setOpen:e=>t({isOpen:e}),setFocused:e=>t({isFocused:e}),setIdle:e=>t({isIdle:e}),setBalances:(e,a)=>t({available:e,pending:a}),setMode:e=>t({mode:e}),setToken:e=>t(a=>({token:e,tokenEpoch:a.token===e?a.tokenEpoch:a.tokenEpoch+1,authStatus:e?"authenticated":"pending"})),setPartnerPayout:e=>t({partnerPayout:Se(e)}),setIsAddingPayoutFromAlert:e=>t({isAddingPayoutFromAlert:e}),setShowPayoutSuccess:e=>t({showPayoutSuccess:e})}));function ve(){let{setFocused:t,setIdle:e}=C(),a=(0,Z.useRef)(null);(0,Z.useEffect)(()=>{let o=()=>t(!0),r=()=>t(!1),u=()=>{e(!1),a.current&&clearTimeout(a.current),a.current=setTimeout(()=>{e(!0)},6e4)},d=()=>{u()};u(),t(document.hasFocus()),window.addEventListener("focus",o),window.addEventListener("blur",r);let s=["mousemove","keydown","scroll","touchstart","mousedown"];return s.forEach(f=>{window.addEventListener(f,d,f==="scroll"?!0:void 0)}),()=>{window.removeEventListener("focus",o),window.removeEventListener("blur",r),s.forEach(f=>{window.removeEventListener(f,d,f==="scroll"?!0:void 0)}),a.current&&clearTimeout(a.current)}},[t,e])}var B=require("react");var be=require("react"),qe=require("react/jsx-runtime"),ne=(0,be.createContext)(null),Oe=({transport:t,children:e})=>(0,qe.jsx)(ne.Provider,{value:t,children:e});var W=()=>{let t=(0,B.useContext)(ne);if(!t)throw new Error("useMessageTransport: no transport in context. Wrap the widget tree in <MessageTransportProvider transport={...}>.");return t},V=(t,e)=>{let a=W(),o=(0,B.useRef)(e);o.current=e,(0,B.useEffect)(()=>a.subscribe(r=>{r.type===t&&o.current(r)}),[a,t])};var I=require("react/jsx-runtime"),Ue=({children:t,theme:e,hostHeight:a=800,isMobile:o=!1})=>{ve();let{isOpen:r,toggle:u,mode:d}=C(),s=e||ge,[f,n]=(0,w.useState)(a),[i,m]=(0,w.useState)(o),[g,x]=(0,w.useState)(void 0),re=s.allowUserThemeControl?{...s,mode:d}:{...s,mode:g??s.mode??"light"},S=he(re),T=(0,w.useRef)(null),ue=(0,w.useRef)(null),de=W();return V("FRUGA_HOST_RESIZE",L=>{n(L.hostHeight),m(L.isHostMobile)}),V("FRUGA_TOKEN_UPDATE",L=>{C.getState().setToken(L.token)}),V("FRUGA_GET_BALANCE",L=>{let{available:P,pending:D}=C.getState();de.send({type:"FRUGA_BALANCE_RESPONSE",version:"1.0",requestId:L.requestId,available:P,pending:D})}),V("FRUGA_INIT",L=>{n(L.host.height),m(L.host.isMobile),L.token&&C.getState().setToken(L.token),L.overrides?.panelOpen&&C.getState().setOpen(!0);let P=L.overrides?.theme;P&&(x(P),C.getState().setMode(P))}),(0,w.useEffect)(()=>{if(!T.current)return;let L=()=>{if(!T.current)return;let D=r?450:100;!r&&ue.current&&(D=ue.current.offsetWidth+40);let Ie=r?Math.max(200,f-100):100;i&&r&&(D=window.innerWidth,Ie=f),de.send({type:"FRUGA_RESIZE",version:"1.0",height:Ie,width:D,isFullscreen:i&&r})},P=new ResizeObserver(()=>L());return P.observe(T.current),L(),()=>P.disconnect()},[r,f,i,de]),(0,I.jsxs)("div",{ref:T,className:S.mode==="dark"?"dark":"",style:{fontFamily:'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',color:S.text,display:"flex",flexDirection:"column",alignItems:"flex-end",justifyContent:"flex-end",padding:i&&r?"0":"20px",boxSizing:"border-box",height:"100%",margin:0,overscrollBehavior:"contain"},children:[r&&(0,I.jsx)("div",{style:{width:i?"100vw":"410px",minWidth:i?"100vw":"410px",flexShrink:0,maxHeight:i?"100vh":`${Math.max(100,f-100)}px`,height:"100%",marginBottom:i?"0":"20px",backgroundColor:S.accent,borderRadius:i?"0":"16px",boxShadow:i?"none":"0 20px 40px -10px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0,0,0,0.1)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9998},children:(0,I.jsx)("div",{className:"fruga-scrollbar",style:{flex:1,minHeight:0,backgroundColor:S.isLight?"#f9f9f9":"#111",display:"flex",flexDirection:"column",boxShadow:i?"none":"0 20px 40px -10px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0,0,0,0.1)"},children:t})}),(0,I.jsxs)("button",{ref:ue,onClick:u,style:{backgroundColor:S.accent,color:S.accentText,border:"none",cursor:"pointer",boxShadow:"0 12px 30px -5px rgba(0, 0, 0, 0.1), 0 0 1px rgba(0,0,0, 0.1)",display:r?"none":"flex",alignItems:"center",justifyContent:"center",zIndex:9999,flexShrink:0,borderRadius:"20px",padding:"10px 16px",transition:"transform 0.3s ease-in-out"},className:"flex h-15 items-center gap-2 rounded-xl px-4 active:scale-[0.99]","aria-label":r?"Close widget":"Open widget",children:[s.launcherLabel&&!r?(0,I.jsxs)(I.Fragment,{children:[s.launcherLabel!=="none"&&(0,I.jsx)("div",{className:"text-sm font-semibold",children:s.launcherLabel}),(0,I.jsx)("div",{className:"flex h-6 w-5 shrink-0 items-center justify-center",children:(0,I.jsx)(Ae,{theme:S})})]}):null,r?(0,I.jsx)(E,{}):null]})]})};var Ee=require("react/jsx-runtime");var He=require("react");var Ge="fruga_bootstrap",We=(t,e)=>`fruga:${t}:${e}`,R=class{static set(e,a){if(!(typeof window>"u"))try{window.localStorage.setItem(e,JSON.stringify(a))}catch(o){console.warn(`[FrugaStorage] Failed to save key "${e}":`,o)}}static get(e){if(typeof window>"u")return null;try{let a=window.localStorage.getItem(e);return a?JSON.parse(a):null}catch(a){return console.warn(`[FrugaStorage] Failed to load key "${e}":`,a),null}}static remove(e){if(!(typeof window>"u"))try{window.localStorage.removeItem(e)}catch(a){console.warn(`[FrugaStorage] Failed to remove key "${e}":`,a)}}};var wa="https://api.fruga.co.uk",Ve=t=>t||wa;var _e="1.3.0";var Q=class{async bootstrap(e,a){let o=Ve(a),r=`${o}/widget/bootstrap?partnerKey=${encodeURIComponent(e)}`,u;try{u=await fetch(r,{method:"GET",headers:{Accept:"application/json"}})}catch(d){throw new Error(`FrugaLoader: bootstrap request to ${o} failed`,{cause:d})}if(!u.ok)throw new Error(`FrugaLoader: bootstrap request to ${o} failed with status ${u.status}`);try{return await u.json()}catch(d){throw new Error(`FrugaLoader: bootstrap response from ${o} was not valid JSON`,{cause:d})}}};var Ne="*",ze=`https://cdn.fruga.co.uk/v/${_e}/`,$=class{mount(e,a,o,r){let u=document.createElement("iframe"),d=this.resolveWidgetUrl(a,o,r),s=this.originOf(d);u.src=d,u.style.border="none",u.style.width="410px",u.style.height="600px",u.style.backgroundColor="transparent",e.appendChild(u);let f=u.contentWindow;if(!f)throw new Error("FrugaLoader: iframe has no contentWindow after being appended");let n=new A({target:f,targetOrigin:s,acceptSource:f,...s===Ne?{}:{acceptOrigin:s}}),i=!1,m=n.subscribe(x=>{if(x.type==="FRUGA_READY"){i=!0;return}x.type==="FRUGA_RESIZE"&&this.applySize(u,x.width,x.height,x.isFullscreen)}),g=()=>{i&&n.send({type:"FRUGA_HOST_RESIZE",version:"1.0",isHostMobile:window.innerWidth<768,hostHeight:window.innerHeight,hostWidth:window.innerWidth})};return window.addEventListener("resize",g),{iframe:u,transport:n,widgetOrigin:s,cleanup:()=>{window.removeEventListener("resize",g),m(),n.dispose()}}}unmount(e){e.remove()}originOf(e){let a;try{a=new URL(e).origin}catch{a="null"}return a&&a!=="null"?a:(console.warn(`FrugaLoader: widget URL has an opaque origin (${e}); falling back to postMessage targetOrigin '*'`),Ne)}applySize(e,a,o,r){if(r){e.style.position="fixed",e.style.inset="0",e.style.width="100vw",e.style.height="100vh",e.style.zIndex="99999";return}e.style.position="static",e.style.inset="",e.style.width=`${a}px`,e.style.height=`${o}px`,e.style.zIndex="auto"}resolveWidgetUrl(e,a,o){let r=se??(typeof window<"u"?window.location.href:ze),u=e.appUrl||o||(se?`./${a}/index.html`:`${ze}${a}/index.html`),d=new URL(u,r);return d.searchParams.set("partnerKey",e.partnerKey),d.toString()}};var Xe=1e4,ce=t=>t==="EXTERNAL_TENANT"?"relay":"connect";var Ke="1.3.0";var J=Ke;var k=class extends Error{constructor(a,o,r={}){super(o);l(this,"code");l(this,"loaderVersion");l(this,"widgetVersion");l(this,"protocolVersion");this.name="FrugaLoadError",this.code=a,this.loaderVersion=r.loaderVersion??J,this.widgetVersion=r.widgetVersion,this.protocolVersion=r.protocolVersion}};var Ze="fruga-widget-root",pe=5e3,Pa="Fruga widget failed to load.",Qe="data-fruga-owned",Fa=1440*60*1e3,Ma={get:t=>R.get(t),set:(t,e)=>R.set(t,e),remove:t=>R.remove(t)},Y=class{constructor(e,a,o={}){this.bootstrapService=e;this.widgetMounter=a;this.env=o;l(this,"options",null);l(this,"currentToken",null);l(this,"session",null);l(this,"mountGeneration",0);l(this,"inFlightBootstrap",null);l(this,"pendingRequests",new Map);l(this,"loadFailed",!1);l(this,"errorElement",null);l(this,"initialTokenRequested",!1)}async init(e){this.options&&this.options.partnerKey!==e.partnerKey&&(this.currentToken=null,this.initialTokenRequested=!1),this.options=e,e.token&&(this.currentToken=e.token),this.emit("lifecycle","init",{partnerKey:e.partnerKey,autoMount:e.autoMount!==!1}),e.autoMount!==!1&&await this.mount()}setOptions(e){this.options=e,e.token&&e.token!==this.currentToken&&this.setToken(e.token)}async mount(){let e=this.options;if(!e){this.report("error","not_initialised","FrugaLoader: Cannot mount - init() must be called first");return}if(!this.initialTokenRequested&&e.onTokenRequired&&(this.initialTokenRequested=!0,await this.requestToken(e.onTokenRequired,"initial")),this.session&&this.session.container.isConnected)return;let a=++this.mountGeneration;this.loadFailed=!1,this.storage.remove(Ge);let o=We(e.partnerKey,"bootstrap"),r=this.readFreshCache(o);r&&this.startSession(r);try{let u=await this.fetchBootstrap(e.partnerKey,e.baseUrl);if(a!==this.mountGeneration)return;this.storage.set(o,{fetchedAt:Date.now(),bootstrap:u}),this.applyBootstrap(u)}catch(u){if(a!==this.mountGeneration)return;if(r&&this.session){this.report("warn","bootstrap_refresh_failed","FrugaLoader: bootstrap refresh failed, keeping cached config:",u);return}this.failMount(new k("BOOTSTRAP_FAILED",`FrugaLoader: failed to load partner configuration: ${u instanceof Error?u.message:String(u)}`))}}readFreshCache(e){let a=this.storage.get(e);return!a||typeof a.fetchedAt!="number"||!a.bootstrap?null:Date.now()-a.fetchedAt>=Fa?(this.storage.remove(e),null):a.bootstrap}fetchBootstrap(e,a){let o=`${e}::${a??""}`,r=this.inFlightBootstrap;if(r&&r.key===o)return r.promise;let u=this.bootstrapService.bootstrap(e,a),d=()=>{this.inFlightBootstrap?.promise===u&&(this.inFlightBootstrap=null)};return u.then(d,d),this.inFlightBootstrap={key:o,promise:u},u}unmount(){this.mountGeneration+=1;let e=this.session;this.session=null,e&&(this.disposeSession(e),e.ownsContainer&&this.widgetMounter.unmount(e.container),this.emit("lifecycle","unmount",{widgetType:e.widgetType})),this.clearErrorElement(),this.rejectPendingRequests(new Error("FrugaLoader: widget unmounted")),this.initialTokenRequested=!1,this.currentToken=this.options?.token??null}async retry(){this.clearErrorElement(),await this.mount()}requestBalance(){let e=this.session;if(!e){this.report("warn","balance_not_mounted","FrugaLoader: Cannot request balance - widget not mounted");return}let a=this.options?.onBalance;if(!a){this.report("warn","balance_no_callback","FrugaLoader: requestBalance() needs an onBalance option; use getBalance() instead");return}let o=this.nextRequestId(),r=setTimeout(()=>{this.pendingRequests.delete(o)&&this.report("warn","balance_timeout",this.balanceTimeoutMessage(e))},pe);this.pendingRequests.set(o,{resolve:u=>a(u),reject:()=>{},timeout:r}),this.sendBalanceRequest(e,o)}async getBalance(){let e=this.session;if(!e)throw new k("NOT_READY","FrugaLoader: Cannot get balance - widget not mounted");let a=this.nextRequestId();return new Promise((o,r)=>{let u=setTimeout(()=>{this.pendingRequests.delete(a)&&r(e.ready?new Error(this.balanceTimeoutMessage(e)):new k("NOT_READY",this.balanceTimeoutMessage(e)))},pe);this.pendingRequests.set(a,{resolve:o,reject:r,timeout:u}),this.sendBalanceRequest(e,a)})}sendBalanceRequest(e,a){if(!e.ready){e.queuedBalanceRequests.push(a);return}this.send(e,{type:"FRUGA_GET_BALANCE",version:"1.0",requestId:a})}flushBalanceRequests(e){for(let a of e.queuedBalanceRequests.splice(0))this.pendingRequests.has(a)&&this.sendBalanceRequest(e,a)}balanceTimeoutMessage(e){return e.ready?"FrugaLoader: Get balance request timed out":`FrugaLoader: widget did not report FRUGA_READY within ${pe}ms; balance request was never sent`}applyBootstrap(e){let a=this.session,o=ce(e.partnerType);if(!a||a.widgetType!==o){this.startSession(e);return}a.bootstrap=e,a.ready&&this.sendInit(a)}startSession(e){let a=this.options,o=this.documentRef;if(!a||!o||this.loadFailed)return;this.clearErrorElement();let r=this.session;this.session=null,r&&this.disposeSession(r);let{container:u,owned:d}=this.ensureContainer(o,a.containerId||Ze),s=ce(e.partnerType),{iframe:f,transport:n,cleanup:i}=this.widgetMounter.mount(u,a,s,e.widgetUrl),m={container:u,iframe:f,transport:n,cleanup:i,bootstrap:e,widgetType:s,ready:!1,ownsContainer:d,queuedBalanceRequests:[],loadTimer:null,unsubscribe:()=>{}};m.unsubscribe=n.subscribe(g=>{this.handleMessage(m,g)}),this.session=m,this.startLoadTimer(m,a),this.emit("lifecycle","mount",{widgetType:s})}disposeSession(e){this.clearLoadTimer(e),e.unsubscribe(),e.cleanup(),e.iframe.remove()}ensureContainer(e,a){let o=e.getElementById(a);if(o)return o.innerHTML="",{container:o,owned:o.hasAttribute(Qe)};let r=e.createElement("div");return r.id=a,r.setAttribute(Qe,""),r.style.position="fixed",r.style.bottom="0px",r.style.right="0px",r.style.zIndex="9999",e.body.appendChild(r),{container:r,owned:!0}}async handleMessage(e,a){if(this.session===e)switch(this.emit("protocol",a.type,{direction:"in"}),a.type){case"FRUGA_READY":{if(le(a.protocolVersion)!==le("1.0")){this.report("error","protocol_mismatch","FrugaLoader: protocol mismatch",{loader:"1.0",widget:a.protocolVersion}),this.failSession(e,new k("VERSION_MISMATCH",`FrugaLoader: widget protocol ${a.protocolVersion} is incompatible with loader protocol ${"1.0"}`,{widgetVersion:a.widgetVersion,protocolVersion:a.protocolVersion}));return}this.clearLoadTimer(e),this.clearErrorElement(),e.ready=!0,this.emit("lifecycle","ready",{widgetVersion:a.widgetVersion,protocolVersion:a.protocolVersion}),this.sendInit(e),this.flushBalanceRequests(e);return}case"NEED_TOKEN":{await this.refreshToken();return}case"FRUGA_BALANCE_RESPONSE":{this.resolveBalance(a.requestId,a.available,a.pending);return}default:return}}sendInit(e){let a=this.windowRef,o=a?.innerWidth??0,r=a?.innerHeight??0,u=this.buildOverrides();this.send(e,{type:"FRUGA_INIT",version:"1.0",protocolVersion:"1.0",token:this.currentToken??void 0,bootstrap:e.bootstrap,apiBaseUrl:this.options?.baseUrl,host:{origin:a?.location.origin??"",width:o,height:r,isMobile:o<768},...u?{overrides:u}:{}})}buildOverrides(){let e=this.options;if(!e)return;let a={...e.theme?{theme:e.theme}:{},...e.primaryColor?{primaryColor:e.primaryColor}:{},...e.userId?{userId:e.userId}:{},...e.panelOpen?{panelOpen:!0}:{}};return Object.keys(a).length>0?a:void 0}async refreshToken(){let e=this.options?.onTokenRequired;e&&await this.requestToken(e,"ttl")}async requestToken(e,a){this.emit("lifecycle","token_requested",{reason:a});try{this.setToken(await e())}catch(o){this.report("error","token_failed",`FrugaLoader: Failed to fetch ${a} token:`,o)}}setToken(e){this.currentToken=e,this.emit("lifecycle","token_updated",{});let a=this.session;a&&a.ready&&this.send(a,{type:"FRUGA_TOKEN_UPDATE",version:"1.0",token:e})}resolveBalance(e,a,o){if(!e){this.report("warn","balance_response_without_id","FrugaLoader: FRUGA_BALANCE_RESPONSE without requestId ignored");return}let r=this.pendingRequests.get(e);r&&(clearTimeout(r.timeout),this.pendingRequests.delete(e),r.resolve({available:a,pending:o}))}rejectPendingRequests(e){for(let[a,o]of this.pendingRequests)clearTimeout(o.timeout),this.pendingRequests.delete(a),o.reject(e)}nextRequestId(){return Math.random().toString(36).substring(2,15)}startLoadTimer(e,a){let o=a.loadTimeoutMs??Xe;o<=0||(e.loadTimer=this.setTimer(()=>{e.loadTimer=null,this.failSession(e,new k("TIMEOUT",`FrugaLoader: widget did not report FRUGA_READY within ${o}ms`))},o))}clearLoadTimer(e){e.loadTimer!==null&&(this.clearTimer(e.loadTimer),e.loadTimer=null)}failSession(e,a){this.session===e&&(this.session=null,this.loadFailed=!0,this.disposeSession(e),this.renderErrorElement(e.container),this.rejectPendingRequests(a),this.notifyError(a))}failMount(e){this.loadFailed=!0;let a=this.session;a&&(this.session=null,this.disposeSession(a));let o=this.documentRef,r=this.options?.containerId||Ze;o&&this.renderErrorElement(this.ensureContainer(o,r).container),this.rejectPendingRequests(e),this.notifyError(e)}notifyError(e){this.emit("error",e.code,{message:e.message});let a=this.options?.onError;if(a)try{a(e)}catch(o){console.error("FrugaLoader: onError callback threw:",o)}}renderErrorElement(e){let a=this.documentRef;if(!a)return;this.clearErrorElement();let o=a.createElement("div");o.setAttribute("role","alert"),o.setAttribute("data-fruga-error",""),o.style.padding="12px",o.textContent=Pa,e.appendChild(o),this.errorElement=o}clearErrorElement(){this.errorElement?.remove(),this.errorElement=null}send(e,a){this.emit("protocol",a.type,{direction:"out"}),e.transport.send(a)}emit(e,a,o,r=e==="error"?"error":"info"){let u=this.options?.onEvent;if(u)try{u({type:e,level:r,name:a,data:o,ts:Date.now()})}catch(d){console.error("FrugaLoader: onEvent callback threw:",d)}}report(e,a,o,r){if(this.options?.onEvent){this.emit("log",a,r===void 0?{message:o}:{message:o,data:r},e);return}let u=e==="error"?console.error:console.warn;if(r===void 0){u(o);return}u(o,r)}setTimer(e,a){let o=this.windowRef;return o?o.setTimeout(e,a):setTimeout(e,a)}clearTimer(e){let a=this.windowRef;if(a){a.clearTimeout(e);return}clearTimeout(e)}get windowRef(){return this.env.windowRef??(typeof window<"u"?window:void 0)}get documentRef(){return this.env.documentRef??(typeof document<"u"?document:void 0)}get storage(){return this.env.storage??Ma}};var Ta=new Q,Aa=new $,M=new Y(Ta,Aa);var me=async()=>{await M.mount()},_=()=>{M.unmount()},ae=async()=>{await M.retry()},ee=async t=>(await M.init(t),ya),Le=t=>{M.setOptions(t)},te=()=>{M.requestBalance()},oe=async()=>M.getBalance(),ya={unmount:_,retry:ae,getBalance:oe,requestBalance:te};if(typeof window<"u"){let t=document.currentScript;if(t){let e=t.getAttribute("data-partner-key"),a=t.getAttribute("data-container-id")||void 0,o=t.getAttribute("data-app-url")||void 0,r=t.getAttribute("data-base-url")||void 0,u=window.frugaConfig||{};(e||u.partnerKey)&&ee({partnerKey:e||u.partnerKey||"demo-key",containerId:a||u.containerId,appUrl:o||u.appUrl,baseUrl:r||u.baseUrl,theme:u.theme,primaryColor:u.primaryColor})}window.FrugaLoader={init:ee,setOptions:Le,mount:me,unmount:_,retry:ae,requestBalance:te,getBalance:oe}}var N=require("react/jsx-runtime");var $e=t=>{let e=(0,p.useRef)(!1),[a,o]=(0,p.useState)(null),r=(0,p.useRef)(t.onError);(0,p.useEffect)(()=>{r.current=t.onError},[t.onError]);let u=(0,p.useMemo)(()=>({...t,onError:f=>{o(f),r.current?.(f)}}),[t]),d=(0,p.useRef)(u);(0,p.useEffect)(()=>{d.current=u},[u]),(0,p.useEffect)(()=>{e.current&&Le(u)},[u]),(0,p.useEffect)(()=>(e.current||ee(d.current).then(()=>{e.current=!0}),()=>{_(),e.current=!1}),[t.partnerKey,t.appUrl]);let s=(0,p.useCallback)(async()=>{o(null),await ae()},[]);return{mount:me,unmount:_,retry:s,error:a}},Ba=t=>{let e=t.containerId||"fruga-widget-container";return $e({...t,containerId:e,autoMount:!0}),(0,N.jsx)("div",{id:e,style:{width:"100%",height:"100%"}})},Ra=({children:t,...e})=>{let a=W();return(0,p.useEffect)(()=>{a.send({type:"FRUGA_READY",version:"1.0",protocolVersion:"1.0",widgetVersion:J})},[a]),(0,N.jsx)(Ue,{...e,children:t})},Da=({children:t,...e})=>{let[a,o]=(0,p.useState)(null);return(0,p.useEffect)(()=>{let r=we();return o(r),()=>{r.dispose()}},[]),a?(0,N.jsx)(Oe,{transport:a,children:(0,N.jsx)(Ra,{...e,children:t})}):null};0&&(module.exports={FrugaWidget,WidgetUI,getBalance,requestBalance,useFrugaWidget});
2
2
  /*! Bundled license information:
3
3
 
4
4
  lucide-react/dist/esm/shared/src/utils/mergeClasses.js: