@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.
package/dist/index.d.ts CHANGED
@@ -163,6 +163,129 @@ interface OfferQuery {
163
163
  categories?: string[];
164
164
  }
165
165
 
166
+ /**
167
+ * Version of the loader <-> widget postMessage protocol.
168
+ * Contract of record: docs/PRD.md section 5.6.
169
+ */
170
+ declare const PROTOCOL_VERSION: "1.0";
171
+ /** Fields carried by every message on the wire. */
172
+ interface FrugaMessageEnvelope {
173
+ /** Protocol version of the sender, e.g. '1.0'. */
174
+ version: string;
175
+ }
176
+ /** Why the widget is asking the host for a token. */
177
+ type NeedTokenReason = 'ttl' | 'unauthorized';
178
+ /** Widget -> loader: the widget has no usable token and asks the host for one. */
179
+ interface NeedTokenMessage extends FrugaMessageEnvelope {
180
+ type: 'NEED_TOKEN';
181
+ /**
182
+ * `ttl` when the current token is about to expire, `unauthorized` when the
183
+ * API rejected it. The native shell mirrors this into `tokenRequired.reason`.
184
+ */
185
+ reason: NeedTokenReason;
186
+ }
187
+ /** Loader -> widget: a fresh authentication token. */
188
+ interface FrugaTokenUpdateMessage extends FrugaMessageEnvelope {
189
+ type: 'FRUGA_TOKEN_UPDATE';
190
+ token: string;
191
+ }
192
+ /** Loader -> widget: request the current balances. */
193
+ interface FrugaGetBalanceMessage extends FrugaMessageEnvelope {
194
+ type: 'FRUGA_GET_BALANCE';
195
+ /** Correlation id; always set by the loader and echoed back by the widget. */
196
+ requestId: string;
197
+ }
198
+ /** Widget -> loader: answer to {@link FrugaGetBalanceMessage}. */
199
+ interface FrugaBalanceResponseMessage extends FrugaMessageEnvelope {
200
+ type: 'FRUGA_BALANCE_RESPONSE';
201
+ /** Echo of the {@link FrugaGetBalanceMessage} `requestId`. */
202
+ requestId: string;
203
+ available: number;
204
+ pending: number;
205
+ }
206
+ /** Widget -> loader: the iframe should be resized to these dimensions. */
207
+ interface FrugaResizeMessage extends FrugaMessageEnvelope {
208
+ type: 'FRUGA_RESIZE';
209
+ width: number;
210
+ height: number;
211
+ isFullscreen: boolean;
212
+ }
213
+ /** Loader -> widget: the host page viewport changed. */
214
+ interface FrugaHostResizeMessage extends FrugaMessageEnvelope {
215
+ type: 'FRUGA_HOST_RESIZE';
216
+ isHostMobile: boolean;
217
+ hostHeight: number;
218
+ hostWidth: number;
219
+ }
220
+ /** Widget -> loader: the widget is mounted and able to receive messages. */
221
+ interface FrugaReadyMessage extends FrugaMessageEnvelope {
222
+ type: 'FRUGA_READY';
223
+ protocolVersion: string;
224
+ widgetVersion: string;
225
+ }
226
+ /** Host page description handed to the widget in {@link FrugaInitMessage}. */
227
+ interface FrugaInitHost {
228
+ origin: string;
229
+ width: number;
230
+ height: number;
231
+ isMobile: boolean;
232
+ }
233
+ /**
234
+ * Host-supplied overrides carried in {@link FrugaInitMessage}. Each field, when
235
+ * present, takes precedence over the matching value in `bootstrap.config.ui`.
236
+ * Sourced from the loader's public `LoaderOptions`.
237
+ */
238
+ interface FrugaInitOverrides {
239
+ /** Overrides `bootstrap.config.ui.defaultTheme`. */
240
+ theme?: 'light' | 'dark';
241
+ /** Overrides `bootstrap.config.ui.accent`. */
242
+ primaryColor?: string;
243
+ /** Host-app identifier for the current end user. */
244
+ userId?: string;
245
+ /** Render the widget with its panel already open (native shell mounts this way). */
246
+ panelOpen?: boolean;
247
+ }
248
+ /** Loader -> widget: single initialisation payload sent after FRUGA_READY. */
249
+ interface FrugaInitMessage extends FrugaMessageEnvelope {
250
+ type: 'FRUGA_INIT';
251
+ protocolVersion: string;
252
+ token?: string;
253
+ bootstrap: WidgetBootstrap;
254
+ apiBaseUrl?: string;
255
+ host: FrugaInitHost;
256
+ /** Host-supplied overrides of `bootstrap.config.ui`; absent when the host set none. */
257
+ overrides?: FrugaInitOverrides;
258
+ }
259
+ /** Every message that may cross the loader <-> widget boundary. */
260
+ type FrugaMessage = NeedTokenMessage | FrugaTokenUpdateMessage | FrugaGetBalanceMessage | FrugaBalanceResponseMessage | FrugaResizeMessage | FrugaHostResizeMessage | FrugaReadyMessage | FrugaInitMessage;
261
+ type FrugaMessageType = FrugaMessage['type'];
262
+ /** Narrow the union to the single member with the given `type`. */
263
+ type FrugaMessageOf<T extends FrugaMessageType> = Extract<FrugaMessage, {
264
+ type: T;
265
+ }>;
266
+ declare const isFrugaMessageType: (value: unknown) => value is FrugaMessageType;
267
+ /**
268
+ * Structural guard for anything arriving from an untrusted `MessageEvent`.
269
+ * `version` is not required: pre-1.0 senders omit it and transports stamp
270
+ * {@link PROTOCOL_VERSION} on arrival.
271
+ */
272
+ declare const isFrugaMessage: (data: unknown) => data is FrugaMessage;
273
+ /**
274
+ * Major component of a protocol version string. Returns `NaN` for
275
+ * unparseable input so callers can treat it as incompatible.
276
+ */
277
+ declare const protocolMajor: (v: string) => number;
278
+
279
+ /**
280
+ * Host viewport width, in px, below which the host page counts as mobile and
281
+ * the widget switches to its fullscreen layout. Matches the PRD's `<768px`
282
+ * host mobile rule.
283
+ *
284
+ * Single source of truth for the loader, the widgets and any future native
285
+ * wrapper: none of them may redefine the number locally.
286
+ */
287
+ declare const HOST_MOBILE_BREAKPOINT = 768;
288
+
166
289
  type PartnerType = 'RELAY' | 'CONNECT' | 'EXTERNAL_TENANT';
167
290
  interface PartnerConfig {
168
291
  partnerId: string;
@@ -192,11 +315,26 @@ interface BootstrapAuth {
192
315
  issuer: string;
193
316
  tokenTtlSeconds: number;
194
317
  }
318
+ /**
319
+ * Who receives the cashback. The wire type is deliberately wider than the two
320
+ * modes the UI knows about: the API may introduce further values, so every
321
+ * consumer narrows through {@link resolvePayoutMode} instead of comparing
322
+ * against a literal.
323
+ */
324
+ type PayoutMode = 'PARTNER' | 'USER';
325
+ /** `partnerPayout` as it arrives on the wire, including values this build does not know. */
326
+ type PartnerPayout = PayoutMode | 'UNKNOWN';
327
+ /**
328
+ * Narrows an unvalidated `partnerPayout` to a mode the UI can act on.
329
+ * Returns `null` for missing, malformed or unrecognised values so an
330
+ * unexpected API response never renders as a known payout mode.
331
+ */
332
+ declare const resolvePayoutMode: (value: unknown) => PayoutMode | null;
195
333
  interface WidgetBootstrap {
196
334
  partnerEnvId: string;
197
335
  partnerId: string;
198
336
  partnerType: PartnerType;
199
- partnerPayout: 'PARTNER' | 'USER';
337
+ partnerPayout: PartnerPayout;
200
338
  auth: BootstrapAuth;
201
339
  config: {
202
340
  ui: WidgetUiConfig;
@@ -205,6 +343,20 @@ interface WidgetBootstrap {
205
343
  launcherIcon: string[];
206
344
  };
207
345
  };
346
+ /**
347
+ * Absolute URL of the widget document to load. When present the loader uses
348
+ * it instead of its default, which gives ops a kill switch and native
349
+ * wrappers the URL from the same call.
350
+ */
351
+ widgetUrl?: string;
352
+ }
353
+ /**
354
+ * localStorage envelope around a cached {@link WidgetBootstrap}.
355
+ * `fetchedAt` is epoch milliseconds and lets a reader apply a TTL.
356
+ */
357
+ interface CachedBootstrap {
358
+ fetchedAt: number;
359
+ bootstrap: WidgetBootstrap;
208
360
  }
209
361
  interface RelayConfig {
210
362
  containerId: string;
@@ -230,6 +382,14 @@ declare global {
230
382
  }
231
383
  }
232
384
 
385
+ declare class HttpError extends Error {
386
+ readonly status: number;
387
+ constructor(status: number, message: string);
388
+ }
389
+ declare class UnauthorizedError extends HttpError {
390
+ constructor(message?: string);
391
+ }
392
+
233
393
  interface IWalletService {
234
394
  getWallet(): Promise<Wallet>;
235
395
  }
@@ -249,12 +409,26 @@ interface IPayoutService {
249
409
  deleteMethod(id: string | number): Promise<void>;
250
410
  }
251
411
 
412
+ /**
413
+ * Platform-neutral seam for loader <-> widget messaging.
414
+ * Web implementation: `PostMessageTransport`. Native wrappers provide their own.
415
+ * `M` defaults to `FrugaMessage`; a bridge with its own message union
416
+ * instantiates it with that union instead.
417
+ */
418
+ interface IMessageTransport<M = FrugaMessage> {
419
+ /** Send a message to the peer. Implementations stamp `version` when absent. */
420
+ send(message: M): void;
421
+ /** Register a handler for validated inbound messages. Returns an unsubscribe function. */
422
+ subscribe(handler: (message: M) => void): () => void;
423
+ /** Release the underlying listener. Subscribing afterwards throws. */
424
+ dispose(): void;
425
+ }
426
+
252
427
  declare class HttpWalletService implements IWalletService {
253
428
  private readonly baseUrl;
254
429
  private readonly token;
255
430
  constructor(baseUrl: string, token: string);
256
431
  getWallet(): Promise<Wallet>;
257
- private getEmptyWallet;
258
432
  }
259
433
 
260
434
  type QueryParamValue = string | number | boolean | string[] | undefined | null;
@@ -268,14 +442,12 @@ declare abstract class BaseHttpService {
268
442
  declare class HttpActivityService extends BaseHttpService implements IActivityService {
269
443
  constructor(baseUrl: string, token: string);
270
444
  getActivity(pageNumber?: number, pageSize?: number): Promise<PaginatedActivity>;
271
- private getEmptyActivity;
272
445
  }
273
446
 
274
447
  declare class HttpOffersService extends BaseHttpService implements IOffersService {
275
448
  constructor(baseUrl: string, token: string);
276
449
  getCategories(): Promise<OfferCategoryResponse>;
277
450
  getOffers(query: OfferQuery): Promise<PaginatedResponse<Offer>>;
278
- private getEmptyPaginatedResponse;
279
451
  }
280
452
 
281
453
  declare class HttpPayoutService implements IPayoutService {
@@ -287,13 +459,82 @@ declare class HttpPayoutService implements IPayoutService {
287
459
  deleteMethod(id: string | number): Promise<void>;
288
460
  }
289
461
 
290
- interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
291
- variant?: 'primary' | 'secondary';
462
+ interface PostMessageTransportOptions {
463
+ /** Window messages are sent to (the iframe's `window.parent`, or the iframe's `contentWindow`). */
464
+ target: Window;
465
+ /** `targetOrigin` passed to `postMessage`. Use '*' only until the peer origin is known. */
466
+ targetOrigin: string;
467
+ /** When set, inbound events from any other `event.source` are dropped. */
468
+ acceptSource?: Window;
469
+ /** When set, inbound events from any other `event.origin` are dropped. */
470
+ acceptOrigin?: string;
471
+ /** Window the 'message' listener is attached to. Defaults to the global `window`. */
472
+ listenOn?: Window;
473
+ /**
474
+ * Message type that establishes the peer origin (widget side passes
475
+ * `'FRUGA_INIT'`). While unpinned, only messages of this type are delivered,
476
+ * from any origin that also satisfies `acceptSource`; the first one accepted
477
+ * pins the transport to `event.origin` via {@link PostMessageTransport.pinOrigin},
478
+ * or to the wildcard `'*'` when that origin is opaque.
479
+ */
480
+ pinOriginFrom?: FrugaMessageType;
481
+ }
482
+ type MessageHandler = (message: FrugaMessage) => void;
483
+ /**
484
+ * `IMessageTransport` over `Window.postMessage`.
485
+ * Owns all `MessageEvent` validation: subscribers only ever see typed,
486
+ * origin- and source-checked `FrugaMessage` values.
487
+ */
488
+ declare class PostMessageTransport implements IMessageTransport {
489
+ private readonly target;
490
+ private readonly acceptSource?;
491
+ private readonly listenOn;
492
+ private readonly handlers;
493
+ private readonly pinOriginFrom?;
494
+ private targetOrigin;
495
+ private acceptOrigin?;
496
+ private pinned;
497
+ private disposed;
498
+ constructor(options: PostMessageTransportOptions);
499
+ /**
500
+ * Origin the transport has locked onto, `'*'` when it pinned to the wildcard
501
+ * after an opaque-origin handshake, or `null` while still unpinned.
502
+ */
503
+ get pinnedOrigin(): string | null;
504
+ /** Lock both the outbound and inbound origin once the peer origin is known. */
505
+ pinOrigin(origin: string): void;
506
+ send(message: FrugaMessage): void;
507
+ subscribe(handler: MessageHandler): () => void;
508
+ dispose(): void;
509
+ private readonly onMessage;
510
+ /**
511
+ * Gate applied only while `pinOriginFrom` is set and the transport is still
512
+ * unpinned: nothing but the pinning message type gets through, and the first
513
+ * one that does completes the handshake for everything after it.
514
+ */
515
+ private admitWhileUnpinned;
292
516
  }
293
- declare const WidgetButton: React.FC<ButtonProps>;
294
- declare const WidgetHeader: React.FC<{
295
- title: string;
296
- }>;
517
+
518
+ interface CreateHostTransportOptions {
519
+ /** Window the widget document runs in. Defaults to the global `window`. */
520
+ listenOn?: Window;
521
+ }
522
+ /**
523
+ * Builds the single `PostMessageTransport` a widget document uses to talk to
524
+ * its host. Centralised here so every widget entry point (relay, connect, and
525
+ * future wrappers) shares one framing check instead of duplicating it inline.
526
+ *
527
+ * `window.parent !== window` is true only when this document is loaded
528
+ * inside an iframe (the normal embed path); an unframed page (e.g. the
529
+ * widget opened directly, or under a test harness that renders it at the
530
+ * top level) has no host to accept messages from, so `acceptSource` is
531
+ * omitted rather than pinned to `window` itself.
532
+ *
533
+ * Note for tests: happy-dom sets `MessageEvent.source` to `null` for
534
+ * same-window `dispatchEvent` calls, so a same-window `acceptSource` check
535
+ * would always fail there too - another reason not to fall back to `window`.
536
+ */
537
+ declare const createHostTransport: (options?: CreateHostTransportOptions) => PostMessageTransport;
297
538
 
298
539
  interface WidgetContainerProps {
299
540
  children: ReactNode;
@@ -317,13 +558,34 @@ declare const WidgetProvider: React.FC<{
317
558
  }>;
318
559
  declare const useWidget: () => WidgetContextType;
319
560
 
561
+ declare const MessageTransportContext: React.Context<IMessageTransport<FrugaMessage> | null>;
562
+ interface MessageTransportProviderProps {
563
+ transport: IMessageTransport;
564
+ children: ReactNode;
565
+ }
566
+ /**
567
+ * Provides the single `IMessageTransport` instance used by the widget tree.
568
+ * The owner of the transport (widget entry point) is responsible for `dispose()`.
569
+ */
570
+ declare const MessageTransportProvider: React.FC<MessageTransportProviderProps>;
571
+
572
+ /** Whether the widget currently holds a usable token. */
573
+ type WidgetAuthStatus = 'pending' | 'authenticated';
320
574
  interface WidgetState {
321
575
  isOpen: boolean;
322
576
  isFocused: boolean;
323
577
  isIdle: boolean;
324
578
  mode: 'light' | 'dark';
325
579
  token: string | null;
326
- partnerPayout: 'PARTNER' | 'USER' | null;
580
+ /**
581
+ * Bumped every time the token *value* changes. Data layers key their caches
582
+ * on it so a token refresh invalidates anything fetched with the old token.
583
+ */
584
+ tokenEpoch: number;
585
+ /** Derived from `token` on every `setToken`; never set directly. */
586
+ authStatus: WidgetAuthStatus;
587
+ /** Narrowed payout mode; `null` while unknown or when the API sent a value this build does not recognise. */
588
+ partnerPayout: PayoutMode | null;
327
589
  toggle: () => void;
328
590
  setOpen: (open: boolean) => void;
329
591
  setFocused: (focused: boolean) => void;
@@ -333,7 +595,8 @@ interface WidgetState {
333
595
  setBalances: (available: number, pending: number) => void;
334
596
  setMode: (mode: 'light' | 'dark') => void;
335
597
  setToken: (token: string | null) => void;
336
- setPartnerPayout: (payout: 'PARTNER' | 'USER') => void;
598
+ /** Accepts the raw wire value; anything but `'PARTNER'` or `'USER'` resets the mode to `null`. */
599
+ setPartnerPayout: (payout: unknown) => void;
337
600
  isAddingPayoutFromAlert: boolean;
338
601
  setIsAddingPayoutFromAlert: (val: boolean) => void;
339
602
  showPayoutSuccess: boolean;
@@ -349,23 +612,63 @@ declare const useWidgetStore: zustand.UseBoundStore<zustand.StoreApi<WidgetState
349
612
  */
350
613
  declare const useDebounce: <T>(value: T, delay: number) => T;
351
614
 
352
- declare const STORAGE_KEYS: {
353
- readonly BOOTSTRAP_DATA: "fruga_bootstrap";
354
- readonly BOOTSTRAP_CONFIG: "fruga_active_config";
355
- };
615
+ declare const useMessageTransport: () => IMessageTransport;
616
+ /**
617
+ * Subscribe to a single message type. The latest `handler` is kept in a ref so
618
+ * the subscription is created once per transport and type.
619
+ */
620
+ declare const useFrugaMessage: <T extends FrugaMessageType>(type: T, handler: (message: FrugaMessageOf<T>) => void) => void;
621
+
622
+ /** Names of the entries the SDK is allowed to persist. */
623
+ type StorageEntryName = 'bootstrap';
624
+ /**
625
+ * Legacy, partner-unscoped bootstrap key written by SDK <= 1.0.4. Kept only so
626
+ * callers can delete stale data during migration; never write it again.
627
+ *
628
+ * @deprecated Use {@link storageKey} instead.
629
+ */
630
+ declare const LEGACY_BOOTSTRAP_STORAGE_KEY = "fruga_bootstrap";
631
+ /**
632
+ * Builds a partner-scoped localStorage key, e.g. `fruga:pk_live_123:bootstrap`.
633
+ * Scoping keeps two partners embedded on the same origin from reading each
634
+ * other's cached data.
635
+ */
636
+ declare const storageKey: (partnerKey: string, name: StorageEntryName) => string;
637
+ /**
638
+ * Namespaced localStorage access. Every method is a no-op outside a browser
639
+ * (SSR) and swallows quota / privacy-mode failures — persistence is a cache,
640
+ * never a correctness requirement.
641
+ */
356
642
  declare class StorageService {
357
643
  static set<T>(key: string, value: T): void;
358
644
  static get<T>(key: string): T | null;
359
645
  static remove(key: string): void;
360
- static clear(): void;
361
646
  }
362
647
 
363
648
  /**
364
- * Default API Base URL for the Fruga SDK.
365
- * This can be overridden at build-time using the VITE_FRUGA_API_URL environment variable.
649
+ * Production API base URL. Used whenever the build did not inject
650
+ * `__FRUGA_API_URL__` (see `src/globals.d.ts`).
651
+ *
652
+ * Resolution is build-time only: `process.env` is never read, because
653
+ * `process` does not exist in a browser (which used to pin every bundle to the
654
+ * dev API) and under SSR a host application's identically named variable would
655
+ * leak into the widget.
366
656
  */
367
- declare const DEFAULT_API_URL: string;
657
+ declare const DEFAULT_API_URL = "https://api.fruga.co.uk";
658
+ /** Resolves the API base URL: explicit override, then build-time flag, then production. */
368
659
  declare const getBaseUrl: (override?: string) => string;
660
+ /**
661
+ * Whether this bundle runs in test mode (mock repositories, mock bootstrap).
662
+ * Decided solely by the build-time `__FRUGA_MODE__` define — never by the
663
+ * presence or absence of a token.
664
+ */
665
+ declare const isTestMode: () => boolean;
666
+ /**
667
+ * Version of this SDK build, injected from the root `package.json` by the
668
+ * bundler's `define`. Falls back to `0.0.0-dev` in vitest and in an
669
+ * unconfigured build.
670
+ */
671
+ declare const SDK_VERSION: string;
369
672
 
370
673
  /**
371
674
  * Formats a date string to "DD-MM-YYYY"
@@ -395,4 +698,4 @@ declare const getDaysRemaining: (dateStr?: string) => number | null;
395
698
  */
396
699
  declare const truncateText: (str: string | undefined | null, maxLength?: number) => string;
397
700
 
398
- export { type Activity, type AddBankPayload, type BankInfo, type BootstrapAuth, type Category, DEFAULT_API_URL, DEFAULT_THEME, DEFAULT_THEME as DefaultTheme, HttpActivityService, HttpOffersService, HttpPayoutService, HttpWalletService, type IActivityService, type IOffersService, type IPayoutService, type IWalletService, type Offer, type OfferCategory, type OfferCategoryResponse, type OfferQuery, type PaginatedActivity, type PaginatedResponse, type PartnerConfig, type PartnerType, type PayoutMethod, type PayoutMethodListResponse, type PayoutMethodStatus, type PayoutMethodType, type RelayConfig, type RelayState, type RequiredAction, type RequiredActionType, type ResolvedTheme, STORAGE_KEYS, StorageService, type Theme, type Transaction, type Wallet, type WidgetBootstrap, WidgetButton, WidgetContainer, type WidgetContainerProps, type WidgetContextType, WidgetHeader, WidgetProvider, type WidgetState, type WidgetUiConfig, formatDate, getBaseUrl, getDaysRemaining, getResolvedTheme, isWithinDays, truncateText, useDebounce, useWidget, useWidgetStore };
701
+ export { type Activity, type AddBankPayload, type BankInfo, type BootstrapAuth, type CachedBootstrap, type Category, type CreateHostTransportOptions, DEFAULT_API_URL, DEFAULT_THEME, DEFAULT_THEME as DefaultTheme, type FrugaBalanceResponseMessage, type FrugaGetBalanceMessage, type FrugaHostResizeMessage, type FrugaInitHost, type FrugaInitMessage, type FrugaInitOverrides, type FrugaMessage, type FrugaMessageEnvelope, type FrugaMessageOf, type FrugaMessageType, type FrugaReadyMessage, type FrugaResizeMessage, type FrugaTokenUpdateMessage, HOST_MOBILE_BREAKPOINT, HttpActivityService, HttpError, HttpOffersService, HttpPayoutService, HttpWalletService, type IActivityService, type IMessageTransport, type IOffersService, type IPayoutService, type IWalletService, LEGACY_BOOTSTRAP_STORAGE_KEY, MessageTransportContext, MessageTransportProvider, type MessageTransportProviderProps, type NeedTokenMessage, type NeedTokenReason, type Offer, type OfferCategory, type OfferCategoryResponse, type OfferQuery, PROTOCOL_VERSION, type PaginatedActivity, type PaginatedResponse, type PartnerConfig, type PartnerPayout, type PartnerType, type PayoutMethod, type PayoutMethodListResponse, type PayoutMethodStatus, type PayoutMethodType, type PayoutMode, PostMessageTransport, type PostMessageTransportOptions, type RelayConfig, type RelayState, type RequiredAction, type RequiredActionType, type ResolvedTheme, SDK_VERSION, type StorageEntryName, StorageService, type Theme, type Transaction, UnauthorizedError, type Wallet, type WidgetAuthStatus, type WidgetBootstrap, WidgetContainer, type WidgetContainerProps, type WidgetContextType, WidgetProvider, type WidgetState, type WidgetUiConfig, createHostTransport, formatDate, getBaseUrl, getDaysRemaining, getResolvedTheme, isFrugaMessage, isFrugaMessageType, isTestMode, isWithinDays, protocolMajor, resolvePayoutMode, storageKey, truncateText, useDebounce, useFrugaMessage, useMessageTransport, useWidget, useWidgetStore };