@frak-labs/core-sdk 0.0.8 → 0.0.10

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
@@ -4,6 +4,20 @@ import type { Prettify } from 'viem/chains';
4
4
  import type { RpcSchema } from 'viem';
5
5
  import type { SiweMessage } from 'viem/siwe';
6
6
 
7
+ /**
8
+ * Decode a base64url encoded string
9
+ * @param value The value to decode
10
+ * @returns The decoded value
11
+ */
12
+ export declare function base64urlDecode(value: string): Uint8Array;
13
+
14
+ /**
15
+ * Encode a buffer to a base64url encoded string
16
+ * @param buffer The buffer to encode
17
+ * @returns The encoded string
18
+ */
19
+ export declare function base64urlEncode(buffer: Uint8Array): string;
20
+
7
21
  /**
8
22
  * Base props for the iframe
9
23
  * @ignore
@@ -27,7 +41,7 @@ export declare const baseIframeProps: {
27
41
  * Event related to the iframe lifecycle
28
42
  * @ignore
29
43
  */
30
- export declare type ClientLifecycleEvent = CustomCssEvent | RestoreBackupEvent | HearbeatEvent | HandshakeResponse;
44
+ export declare type ClientLifecycleEvent = CustomCssEvent | CustomI18nEvent | RestoreBackupEvent | HearbeatEvent | HandshakeResponse;
31
45
 
32
46
  /** @ignore */
33
47
  export declare class ClientNotFound extends FrakRpcError {
@@ -46,17 +60,21 @@ declare function compress(context?: Partial<FrakContext>): string | undefined;
46
60
  * -> The encoded should contain a HashProtectedData once decoded
47
61
  * @ignore
48
62
  */
49
- export declare type CompressedData = Readonly<{
50
- compressed: string;
51
- compressedHash: string;
52
- }>;
63
+ export declare type CompressedData = Uint8Array;
64
+
65
+ /**
66
+ * Compress json data
67
+ * @param data
68
+ * @ignore
69
+ */
70
+ export declare function compressJson(data: unknown): Uint8Array;
53
71
 
54
72
  /**
55
73
  * Compress json data
56
74
  * @param data
57
75
  * @ignore
58
76
  */
59
- export declare function compressJson(data: unknown): Promise<string>;
77
+ export declare function compressJsonToB64(data: unknown): string;
60
78
 
61
79
  /**
62
80
  * Create the Frak iframe
@@ -90,6 +108,12 @@ export declare function createIFrameFrakClient({ config, iframe, }: {
90
108
  iframe: HTMLIFrameElement;
91
109
  }): FrakClient;
92
110
 
111
+ /**
112
+ * All the currencies available
113
+ * @category Config
114
+ */
115
+ export declare type Currency = "eur" | "usd" | "gbp";
116
+
93
117
  declare type CustomCssEvent = {
94
118
  clientLifecycle: "modal-css";
95
119
  data: {
@@ -97,6 +121,13 @@ declare type CustomCssEvent = {
97
121
  };
98
122
  };
99
123
 
124
+ declare type CustomI18nEvent = {
125
+ clientLifecycle: "modal-i18n";
126
+ data: {
127
+ i18n: I18nConfig;
128
+ };
129
+ };
130
+
100
131
  /** @ignore */
101
132
  export declare class DebugInfoGatherer {
102
133
  private config?;
@@ -134,14 +165,21 @@ declare function decompress(context?: string): FrakContext | undefined;
134
165
  * @param compressedData The params to encode
135
166
  * @ignore
136
167
  */
137
- export declare function decompressDataAndCheckHash<T>(compressedData: CompressedData): Promise<HashProtectedData<T>>;
168
+ export declare function decompressDataAndCheckHash<T>(compressedData: CompressedData): HashProtectedData<T>;
169
+
170
+ /**
171
+ * Decompress json data
172
+ * @param data
173
+ * @ignore
174
+ */
175
+ export declare function decompressJson<T>(data: Uint8Array): T | null;
138
176
 
139
177
  /**
140
178
  * Decompress json data
141
179
  * @param data
142
180
  * @ignore
143
181
  */
144
- export declare function decompressJson<T>(data: string): Promise<T | null>;
182
+ export declare function decompressJsonFromB64<T>(data: string): T | null;
145
183
 
146
184
  /**
147
185
  * Simple deferred promise wrapper
@@ -158,36 +196,31 @@ export declare class Deferred<T> {
158
196
  }
159
197
 
160
198
  /**
161
- * The params used to display the embeded wallet
199
+ * The params used to display the embedded wallet
162
200
  *
163
- * @group Embeded wallet
201
+ * @group Embedded wallet
164
202
  */
165
203
  export declare type DisplayEmbededWalletParamsType = {
166
204
  /**
167
- * The embeded view to display once the user is logged in
205
+ * The embedded view to display once the user is logged in
168
206
  */
169
207
  loggedIn?: LoggedInEmbededView;
170
208
  /**
171
- * The embeded view to display once the user is logged out
209
+ * The embedded view to display once the user is logged out
172
210
  */
173
211
  loggedOut?: LoggedOutEmbededView;
174
212
  /**
175
- * Some metadata to customise the embeded view
213
+ * Some metadata to customize the embedded view
176
214
  */
177
215
  metadata?: {
178
216
  /**
179
- * Language of the embeded wallet
180
- * If undefined, will default to the browser language
181
- */
182
- lang?: "fr" | "en";
183
- /**
184
- * The logo to display on the embeded wallet
217
+ * The logo to display on the embedded wallet
185
218
  * If undefined, will default to no logo displayed
186
219
  */
187
220
  logo?: string;
188
221
  /**
189
222
  * Link to the homepage of the calling website
190
- * If unedfined, will default to the domain of the calling website
223
+ * If undefined, will default to the domain of the calling website
191
224
  */
192
225
  homepageLink?: string;
193
226
  /**
@@ -198,6 +231,10 @@ export declare type DisplayEmbededWalletParamsType = {
198
231
  * The position of the component
199
232
  */
200
233
  position?: "left" | "right";
234
+ /**
235
+ * Some i18n override for the displayed modal (i.e. update the displayed text only for this modal)
236
+ */
237
+ i18n?: I18nConfig;
201
238
  };
202
239
  };
203
240
 
@@ -219,9 +256,9 @@ declare type DoBackupEvent = {
219
256
  };
220
257
 
221
258
  /**
222
- * The different type of action we can have on the embeded view (once the user is logged in)
259
+ * The different type of action we can have on the embedded view (once the user is logged in)
223
260
  *
224
- * @group Embeded wallet
261
+ * @group Embedded wallet
225
262
  */
226
263
  export declare type EmbededViewAction = {
227
264
  key: "sharing";
@@ -231,11 +268,13 @@ export declare type EmbededViewAction = {
231
268
  options?: {
232
269
  /**
233
270
  * The title that will be displayed on the system popup once the system sharing window is open
271
+ * @deprecated Use the top level `config.metadata.i18n` instead
234
272
  */
235
273
  popupTitle?: string;
236
274
  /**
237
275
  * The text that will be shared alongside the link.
238
276
  * Can contain the variable {LINK} to specify where the link is placed, otherwise it will be added at the end
277
+ * @deprecated Use the top level `config.metadata.i18n` instead
239
278
  */
240
279
  text?: string;
241
280
  /**
@@ -280,7 +319,13 @@ export declare type ExtractedReturnTypeFromRpc<TRpcSchema extends RpcSchema, TPa
280
319
  export declare type FinalActionType = {
281
320
  key: "sharing";
282
321
  options?: {
322
+ /**
323
+ * @deprecated Use the top level `config.metadata.i18n` instead
324
+ */
283
325
  popupTitle?: string;
326
+ /**
327
+ * @deprecated Use the top level `config.metadata.i18n` instead
328
+ */
284
329
  text?: string;
285
330
  link?: string;
286
331
  };
@@ -303,6 +348,8 @@ export declare type FinalModalStepType = GenericModalStepType<"final", {
303
348
  autoSkip?: boolean;
304
349
  }, object>;
305
350
 
351
+ export declare function formatAmount(amount: number, currency?: Currency): string;
352
+
306
353
  /**
307
354
  * Representing a Frak client, used to interact with the Frak Wallet
308
355
  */
@@ -317,6 +364,8 @@ export declare type FrakClient = {
317
364
  * The current Frak Context
318
365
  *
319
366
  * For now, only contain a referrer address.
367
+ *
368
+ * @ignore
320
369
  */
321
370
  export declare type FrakContext = {
322
371
  r: Address;
@@ -345,7 +394,8 @@ export declare class FrakRpcError<T = undefined> extends Error {
345
394
  }
346
395
 
347
396
  /**
348
- * Configuration for the Nexus Wallet SDK
397
+ * Configuration for the Frak Wallet SDK
398
+ * @category Config
349
399
  */
350
400
  export declare type FrakWalletSdkConfig = {
351
401
  /**
@@ -361,10 +411,37 @@ export declare type FrakWalletSdkConfig = {
361
411
  * Your application name (will be displayed in a few modals and in SSO)
362
412
  */
363
413
  name: string;
414
+ /**
415
+ * Language to display in the modal
416
+ * If undefined, will default to the browser language
417
+ */
418
+ lang?: Language;
419
+ /**
420
+ * The currency to display in the modal
421
+ * @defaultValue `"eur"`
422
+ */
423
+ currency?: Currency;
424
+ /**
425
+ * The logo URL that will be displayed in a few components
426
+ */
427
+ logoUrl?: string;
428
+ /**
429
+ * The homepage link that could be displayed in a few components
430
+ */
431
+ homepageLink?: string;
432
+ };
433
+ /**
434
+ * Some customization for the modal
435
+ */
436
+ customizations?: {
364
437
  /**
365
438
  * Custom CSS styles to apply to the modals and components
366
439
  */
367
- css?: string;
440
+ css?: `${string}.css`;
441
+ /**
442
+ * Custom i18n configuration for the modal
443
+ */
444
+ i18n?: I18nConfig;
368
445
  };
369
446
  /**
370
447
  * The domain name of your application
@@ -392,6 +469,13 @@ declare type GenericModalStepType<TKey, TParams, TReturns> = {
392
469
  returns: TReturns;
393
470
  };
394
471
 
472
+ /**
473
+ * Get the currency amount key for a given currency
474
+ * @param currency - The currency to use
475
+ * @returns The currency amount key
476
+ */
477
+ export declare function getCurrencyAmountKey(currency?: Currency): keyof TokenAmountType;
478
+
395
479
  /**
396
480
  * Response of the `frak_getProductInformation` RPC method
397
481
  * @group RPC Schema
@@ -419,9 +503,13 @@ export declare type GetProductInformationReturnType = {
419
503
  productTypes: ProductTypesKey[];
420
504
  };
421
505
  /**
422
- * The max potential reward in EUR for the given product
506
+ * The max potential reward for the referrer
423
507
  */
424
- estimatedEurReward?: string;
508
+ maxReferrer?: TokenAmountType;
509
+ /**
510
+ * The max potential reward for the referee
511
+ */
512
+ maxReferee?: TokenAmountType;
425
513
  /**
426
514
  * List of all the potentials reward arround this product
427
515
  */
@@ -429,19 +517,25 @@ export declare type GetProductInformationReturnType = {
429
517
  token: Address;
430
518
  campaign: Address;
431
519
  interactionTypeKey: FullInteractionTypesKey;
432
- referrer: {
433
- amount: number;
434
- eurAmount: number;
435
- usdAmount: number;
436
- };
437
- referee: {
438
- amount: number;
439
- eurAmount: number;
440
- usdAmount: number;
441
- };
520
+ referrer: TokenAmountType;
521
+ referee: TokenAmountType;
442
522
  }[];
443
523
  };
444
524
 
525
+ /**
526
+ * Get the supported currency for a given currency
527
+ * @param currency - The currency to use
528
+ * @returns The supported currency
529
+ */
530
+ export declare function getSupportedCurrency(currency?: Currency): Currency;
531
+
532
+ /**
533
+ * Get the supported locale for a given currency
534
+ * @param currency - The currency to use
535
+ * @returns The supported locale
536
+ */
537
+ export declare function getSupportedLocale(currency?: Currency): (typeof locales)[LocalesKey];
538
+
445
539
  declare type HandshakeRequestEvent = {
446
540
  iframeLifecycle: "handshake";
447
541
  data: {
@@ -462,7 +556,7 @@ declare type HandshakeResponse = {
462
556
  * @param data The params to encode
463
557
  * @ignore
464
558
  */
465
- export declare function hashAndCompressData<T>(data: T): Promise<CompressedData>;
559
+ export declare function hashAndCompressData<T>(data: T): CompressedData;
466
560
 
467
561
  /**
468
562
  * The encoded data to send to a client / received by a client
@@ -476,6 +570,41 @@ declare type HearbeatEvent = {
476
570
  clientLifecycle: "heartbeat";
477
571
  };
478
572
 
573
+ /**
574
+ * Custom i18n configuration for the modal
575
+ * See [i18next json format](https://www.i18next.com/misc/json-format#i18next-json-v4)
576
+ *
577
+ * Available variables
578
+ * - `{{ productName }}` : The name of your website (`metadata.name`)
579
+ * - `{{ productOrigin }}` : The origin url of your website
580
+ * - `{{ estimatedReward }}` : The estimated reward for the user (based on the specific `targetInteraction` you can specify, or the max referrer reward if no target interaction is specified)
581
+ *
582
+ * Context of the translation [see i18n context](https://www.i18next.com/translation-function/context)
583
+ * - For modal display, the key of the final action (`sharing`, `reward`, or undefined)
584
+ * - For embedded wallet display, the key of the logged in action (`sharing` or undefined)
585
+ *
586
+ * @example
587
+ * ```ts
588
+ * // Multi language config
589
+ * const multiI18n = {
590
+ * fr: {
591
+ * "sdk.modal.title": "Titre de modal",
592
+ * "sdk.modal.description": "Description de modal, avec {{ estimatedReward }} de gains possible",
593
+ * },
594
+ * en: "https://example.com/en.json"
595
+ * }
596
+ *
597
+ * // Single language config
598
+ * const singleI18n = {
599
+ * "sdk.modal.title": "Modal title",
600
+ * "sdk.modal.description": "Modal description, with {{ estimatedReward }} of gains possible",
601
+ * }
602
+ * ```
603
+ *
604
+ * @category Config
605
+ */
606
+ export declare type I18nConfig = Record<Language, LocalizedI18nConfig> | LocalizedI18nConfig;
607
+
479
608
  /**
480
609
  * Represent an iframe event
481
610
  */
@@ -496,10 +625,7 @@ export declare type IFrameLifecycleEvent = {
496
625
  export declare type IFrameRpcEvent = {
497
626
  id: string;
498
627
  topic: ExtractedParametersFromRpc<IFrameRpcSchema>["method"];
499
- data: {
500
- compressed: string;
501
- compressedHash: string;
502
- };
628
+ data: CompressedData;
503
629
  };
504
630
 
505
631
  /**
@@ -552,8 +678,8 @@ export declare type IFrameRpcSchema = [
552
678
  Method: "frak_displayModal";
553
679
  Parameters: [
554
680
  requests: ModalRpcStepsInput,
555
- name: string,
556
- metadata?: ModalRpcMetadata
681
+ metadata: ModalRpcMetadata | undefined,
682
+ configMetadata: FrakWalletSdkConfig["metadata"]
557
683
  ];
558
684
  ReturnType: ModalRpcStepsResultType;
559
685
  },
@@ -594,11 +720,14 @@ export declare type IFrameRpcSchema = [
594
720
  ReturnType: GetProductInformationReturnType;
595
721
  },
596
722
  /**
597
- * Method to show the embeded wallet, with potential customisation
723
+ * Method to show the embedded wallet, with potential customization
598
724
  */
599
725
  {
600
726
  Method: "frak_displayEmbededWallet";
601
- Parameters: [DisplayEmbededWalletParamsType, name: string];
727
+ Parameters: [
728
+ request: DisplayEmbededWalletParamsType,
729
+ metadata: FrakWalletSdkConfig["metadata"]
730
+ ];
602
731
  ReturnType: undefined;
603
732
  }
604
733
  ];
@@ -672,6 +801,12 @@ export declare type InteractionTypesKey = {
672
801
  */
673
802
  export declare type KeyProvider<DataType> = (value: DataType) => string[];
674
803
 
804
+ /**
805
+ * All the languages available
806
+ * @category Config
807
+ */
808
+ export declare type Language = "fr" | "en";
809
+
675
810
  /**
676
811
  * Type used for a listening request
677
812
  * @inline
@@ -679,13 +814,36 @@ export declare type KeyProvider<DataType> = (value: DataType) => string[];
679
814
  declare type ListenerRequestFn<TRpcSchema extends RpcSchema> = <TParameters extends ExtractedParametersFromRpc<TRpcSchema> = ExtractedParametersFromRpc<TRpcSchema>, _ReturnType = ExtractedReturnTypeFromRpc<TRpcSchema, TParameters>>(args: TParameters, callback: (result: _ReturnType) => void) => Promise<void>;
680
815
 
681
816
  /**
682
- * Some configuration options for the embeded view
817
+ * Map the currency to the locale
818
+ */
819
+ export declare const locales: {
820
+ readonly eur: "fr-FR";
821
+ readonly usd: "en-US";
822
+ readonly gbp: "en-GB";
823
+ };
824
+
825
+ /**
826
+ * The keys for each locales
827
+ * @inline
828
+ */
829
+ export declare type LocalesKey = keyof typeof locales;
830
+
831
+ /**
832
+ * A localized i18n config
833
+ * @category Config
834
+ */
835
+ export declare type LocalizedI18nConfig = `${string}.css` | {
836
+ [key: string]: string;
837
+ };
838
+
839
+ /**
840
+ * Some configuration options for the embedded view
683
841
  *
684
- * @group Embeded wallet
842
+ * @group Embedded wallet
685
843
  */
686
844
  export declare type LoggedInEmbededView = {
687
845
  /**
688
- * The main action to display on the logged in embeded view
846
+ * The main action to display on the logged in embedded view
689
847
  * If none specified, the user will see his wallet with the activation button
690
848
  */
691
849
  action?: EmbededViewAction;
@@ -693,26 +851,28 @@ export declare type LoggedInEmbededView = {
693
851
 
694
852
  /**
695
853
  * The view when a user is logged out
696
- * @group Embeded wallet
854
+ * @group Embedded wallet
697
855
  */
698
856
  export declare type LoggedOutEmbededView = {
699
857
  /**
700
- * Metadata option when displaying the embeded view
858
+ * Metadata option when displaying the embedded view
701
859
  */
702
860
  metadata?: {
703
861
  /**
704
862
  * The main CTA for the logged out view
705
863
  * - can include some variable, available ones are:
706
- * - {REWARD} -> The maximum reward a user can receive when itneracting on your website
864
+ * - {REWARD} -> The maximum reward a user can receive when interacting on your website
707
865
  * - can be formatted in markdown
708
866
  *
709
- * If not sert, it will default to a internalised message
867
+ * If not set, it will default to a internationalized message
868
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
710
869
  */
711
870
  text?: string;
712
871
  /**
713
872
  * The text that will be displayed on the login button
714
873
  *
715
- * If not set, it will default to a internalised message
874
+ * If not set, it will default to a internationalized message
875
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
716
876
  */
717
877
  buttonText?: string;
718
878
  };
@@ -739,7 +899,7 @@ declare type LoginWithoutSso = {
739
899
  /** @inline */
740
900
  declare type LoginWithSso = {
741
901
  allowSso: true;
742
- ssoMetadata: SsoMetadata;
902
+ ssoMetadata?: SsoMetadata;
743
903
  };
744
904
 
745
905
  /**
@@ -752,11 +912,16 @@ export declare type ModalRpcMetadata = {
752
912
  title?: string;
753
913
  icon?: string;
754
914
  };
755
- context?: string;
756
- lang?: "en" | "fr";
757
915
  targetInteraction?: FullInteractionTypesKey;
916
+ /**
917
+ * Some i18n override for the displayed modal (i.e. update the displayed text only for this modal)
918
+ */
919
+ i18n?: I18nConfig;
758
920
  } & ({
759
921
  isDismissible: true;
922
+ /**
923
+ * @deprecated Use `config.customizations.i18n` or `metadata.i18n` instead
924
+ */
760
925
  dismissActionTxt?: string;
761
926
  } | {
762
927
  isDismissible?: false;
@@ -790,29 +955,34 @@ export declare type ModalRpcStepsResultType<T extends ModalStepTypes[] = ModalSt
790
955
  };
791
956
 
792
957
  /**
793
- * Metadata that can be used to customise a modal step
958
+ * Metadata that can be used to customize a modal step
794
959
  * @group Modal Display
960
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
795
961
  */
796
962
  export declare type ModalStepMetadata = {
797
963
  metadata?: {
798
964
  /**
799
965
  * Custom title for the step
800
- * If none provided, it will use an internationalised text
966
+ * If none provided, it will use an internationalized text
967
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
801
968
  */
802
969
  title?: string;
803
970
  /**
804
971
  * Custom description for the step
805
- * If none provided, it will use an internationalised text
972
+ * If none provided, it will use an internationalized text
973
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
806
974
  */
807
975
  description?: string;
808
976
  /**
809
977
  * Custom text for the primary action of the step
810
- * If none provided, it will use an internationalised text
978
+ * If none provided, it will use an internationalized text
979
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
811
980
  */
812
981
  primaryActionText?: string;
813
982
  /**
814
983
  * Custom text for the secondary action of the step
815
- * If none provided, it will use an internationalised text
984
+ * If none provided, it will use an internationalized text
985
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
816
986
  */
817
987
  secondaryActionText?: string;
818
988
  };
@@ -1106,6 +1276,16 @@ export declare type SsoMetadata = {
1106
1276
  homepageLink?: string;
1107
1277
  };
1108
1278
 
1279
+ /**
1280
+ * The type for the amount of tokens
1281
+ */
1282
+ export declare type TokenAmountType = {
1283
+ amount: number;
1284
+ eurAmount: number;
1285
+ usdAmount: number;
1286
+ gbpAmount: number;
1287
+ };
1288
+
1109
1289
  /**
1110
1290
  * Populate the current url with the given Frak context
1111
1291
  * @param args
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import*as e from"async-lz-string";import*as t from"js-sha256";import*as n from"viem";class r extends Error{code;data;constructor(e,t,n){super(t),this.code=e,this.data=n}}class a extends r{constructor(e){super(s.internalError,e)}}class o extends r{constructor(){super(s.clientNotConnected,"Client not found")}}let s={parseError:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internalError:-32603,serverError:-32e3,clientNotConnected:-32001,configError:-32002,corruptedResponse:-32003,clientAborted:-32004,walletNotConnected:-32005,serverErrorForInteractionDelegation:-32006};class i{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e){this.lastResponse={event:e.data,origin:e.origin,timestamp:Date.now()}}setLastRequest(e,t){this.lastRequest={event:e,target:t,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn("Failed to encode debug data",e),btoa("Failed to encode data")}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute("loading"),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?+("complete"===this.iframe.contentDocument.readyState):-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let t=this.getIframeStatus(),n=this.getNavigatorInfo(),a="Unknown";return e instanceof r?a=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?a=e.message:"string"==typeof e&&(a=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):"no-config",navigatorInfo:n?this.base64Encode(n):"no-navigator",iframeStatus:t?this.base64Encode(t):"not-iframe",lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):"No Frak request logged",lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):"No Frak response logged",clientStatus:this.isSetupDone?"setup":"not-setup",error:a}}static empty(){return new i}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
1
+ import*as e from"@jsonjoy.com/json-pack/lib/cbor";import*as t from"viem";class n extends Error{code;data;constructor(e,t,n){super(t),this.code=e,this.data=n}}class r extends n{constructor(e){super(a.internalError,e)}}class o extends n{constructor(){super(a.clientNotConnected,"Client not found")}}let a={parseError:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internalError:-32603,serverError:-32e3,clientNotConnected:-32001,configError:-32002,corruptedResponse:-32003,clientAborted:-32004,walletNotConnected:-32005,serverErrorForInteractionDelegation:-32006};class i{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e){this.lastResponse={event:e.data,origin:e.origin,timestamp:Date.now()}}setLastRequest(e,t){this.lastRequest={event:e,target:t,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn("Failed to encode debug data",e),btoa("Failed to encode data")}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute("loading"),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?+("complete"===this.iframe.contentDocument.readyState):-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let t=this.getIframeStatus(),r=this.getNavigatorInfo(),o="Unknown";return e instanceof n?o=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?o=e.message:"string"==typeof e&&(o=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):"no-config",navigatorInfo:r?this.base64Encode(r):"no-navigator",iframeStatus:t?this.base64Encode(t):"not-iframe",lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):"No Frak request logged",lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):"No Frak response logged",clientStatus:this.isSetupDone?"setup":"not-setup",error:o}}static empty(){return new i}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
2
2
  Debug Information:
3
3
  -----------------
4
4
  Timestamp: ${t.timestamp}
@@ -10,4 +10,4 @@ import*as e from"async-lz-string";import*as t from"js-sha256";import*as n from"v
10
10
  Last Response: ${t.lastResponse}
11
11
  Client Status: ${t.clientStatus}
12
12
  Error: ${t.error}
13
- `.trim()}}class c{_promise;_resolve;_reject;constructor(){this._promise=new Promise((e,t)=>{this._resolve=e,this._reject=t})}get promise(){return this._promise}resolve=e=>{this._resolve?.(e)};reject=e=>{this._reject?.(e)}}async function l(e){if(!(e?.compressed&&e?.compressedHash))throw new r(s.corruptedResponse,"Missing compressed data");let n=await d(e.compressed);if(!n)throw new r(s.corruptedResponse,"Invalid compressed data");if(!n?.validationHash)throw new r(s.corruptedResponse,"Missing validation hash");if((0,t.sha256)(e.compressed)!==e.compressedHash)throw new r(s.corruptedResponse,"Invalid compressed hash");let{validationHash:a,...o}=n;if((0,t.sha256)(JSON.stringify(o))!==n.validationHash)throw new r(s.corruptedResponse,"Invalid data validation hash");return n}async function d(t){let n=await (0,e.decompressFromBase64)(t);try{return JSON.parse(n)}catch(e){return console.error("Invalid compressed data",{e,decompressed:n}),null}}async function u(e){let n=(0,t.sha256)(JSON.stringify(e)),r={...e,validationHash:n},a=await f(r),o=(0,t.sha256)(a);return{compressed:a,compressedHash:o}}async function f(t){return(0,e.compressToBase64)(JSON.stringify(t))}let p="nexus-wallet-backup",h={id:"nexus-wallet",name:"nexus-wallet",allow:"publickey-credentials-get *; clipboard-write; web-share *",style:{width:"0",height:"0",border:"0",position:"absolute",zIndex:2000001,top:"-1000px",left:"-1000px"}};function m({walletBaseUrl:e,config:t}){let n=document.querySelector("#nexus-wallet");n&&n.remove();let r=document.createElement("iframe");return r.id=h.id,r.name=h.name,r.allow=h.allow,r.style.zIndex=h.style.zIndex.toString(),w({iframe:r,isVisible:!1}),document.body.appendChild(r),new Promise(n=>{r?.addEventListener("load",()=>n(r)),r.src=`${t?.walletUrl??e??"https://wallet.frak.id"}/listener`})}function w({iframe:e,isVisible:t}){if(!t){e.style.width="0",e.style.height="0",e.style.border="0",e.style.position="fixed",e.style.top="-1000px",e.style.left="-1000px";return}e.style.position="fixed",e.style.top="0",e.style.left="0",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}function g({config:e,iframe:t}){let n=function(){let e=new Map;return{createChannel:t=>{let n=Math.random().toString(36).substring(7);return e.set(n,t),n},getRpcResolver:t=>e.get(t),removeChannel:t=>e.delete(t),destroy:()=>e.clear()}}(),o=function({iframe:e}){let t=new c;return{handleEvent:async n=>{switch(n.iframeLifecycle){case"connected":t.resolve(!0);break;case"do-backup":n.data.backup?localStorage.setItem(p,n.data.backup):localStorage.removeItem(p);break;case"remove-backup":localStorage.removeItem(p);break;case"show":case"hide":w({iframe:e,isVisible:"show"===n.iframeLifecycle});break;case"handshake":e.contentWindow?.postMessage({clientLifecycle:"handshake-response",data:{token:n.data.token,currentUrl:window.location.href}},"*")}},isConnected:t.promise}}({iframe:t}),d=new i(e,t),f=function({frakWalletUrl:e,iframe:t,channelManager:n,iframeLifecycleManager:a,debugInfo:o}){if("undefined"==typeof window)throw new r(s.configError,"iframe client should be used in the browser");if(!t.contentWindow)throw new r(s.configError,"The iframe does not have a product window");let i=t.contentWindow;async function c(t){if(!t.origin)return;try{if(new URL(t.origin).origin.toLowerCase()!==new URL(e).origin.toLowerCase())return}catch(e){console.log("Unable to check frak msg origin",e);return}if("object"!=typeof t.data)return;if(o.setLastResponse(t),"iframeLifecycle"in t.data){await a.handleEvent(t.data);return}if("clientLifecycle"in t.data){console.error("Client lifecycle event received on the client side, dismissing it");return}let r=t.data.id,s=n.getRpcResolver(r);s&&await s(t.data)}return window.addEventListener("message",c),{sendEvent:function(t){i.postMessage(t,{targetOrigin:e}),o.setLastRequest(t,e)},cleanup:function(){window.removeEventListener("message",c)}}}({frakWalletUrl:e?.walletUrl??"https://wallet.frak.id",iframe:t,channelManager:n,iframeLifecycleManager:o,debugInfo:d}),h=async e=>{if(!await o.isConnected)throw new r(s.clientNotConnected,"The iframe provider isn't connected yet");let t=new c,a=n.createChannel(async e=>{let o=await l(e.data);o.error?t.reject(new r(o.error.code,o.error.message,o.error?.data)):t.resolve(o.result),n.removeChannel(a)}),i=await u(e);return f.sendEvent({id:a,topic:e.method,data:i}),t.promise},m=async(e,t)=>{if(!await o.isConnected)throw new r(s.clientNotConnected,"The iframe provider isn't connected yet");let i=n.createChannel(async e=>{let n=await l(e.data);if(n.result)t(n.result);else throw new a("No valid result in the response")}),c=await u(e);f.sendEvent({id:i,topic:e.method,data:c})},g=function(e,t){let n,r;let a=()=>e.sendEvent({clientLifecycle:"heartbeat"});function o(){n&&clearInterval(n),r&&clearTimeout(r)}return async function(){a(),n=setInterval(a,100),r=setTimeout(()=>{o(),console.log("Heartbeat timeout: connection failed")},3e4),await t.isConnected,o()}(),o}(f,o),v=async()=>{g(),n.destroy(),f.cleanup(),t.remove()},b=y({config:e,messageHandler:f,lifecycleManager:o}).then(()=>d.updateSetupStatus(!0));return{config:e,debugInfo:d,waitForConnection:o.isConnected,waitForSetup:b,request:h,listenerRequest:m,destroy:v}}async function y({config:e,messageHandler:t,lifecycleManager:n}){await n.isConnected;let r=async()=>{let n=e.metadata.css;n&&t.sendEvent({clientLifecycle:"modal-css",data:{cssLink:n}})},a=async()=>{if("undefined"==typeof window)return;let e=window.localStorage.getItem(p);e&&t.sendEvent({clientLifecycle:"restore-backup",data:{backup:e}})};await Promise.all([r(),a()])}async function v({config:e}){let t=await m({config:e});if(!t){console.error("Failed to create iframe");return}let n=g({config:e,iframe:t});if(await n.waitForSetup,!await n.waitForConnection){console.error("Failed to connect to client");return}return n}let b="fCtx";function R(e){if(e?.r)try{var t;return t=(0,n.hexToBytes)(e.r),btoa(Array.from(t,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}catch(t){console.error("Error compressing Frak context",{e:t,context:e})}}function C(e){if(e&&0!==e.length)try{let t=function(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(e.length+(0===t?0:4-t),"=")),e=>e.charCodeAt(0))}(e);return{r:(0,n.bytesToHex)(t,{size:20})}}catch(t){console.error("Error decompressing Frak context",{e:t,context:e})}}function S({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(b);return t?C(t):null}function x({url:e,context:t}){if(!e)return null;let n=S({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let a=R(r);if(!a)return null;let o=new URL(e);return o.searchParams.set(b,a),o.toString()}function E(e){let t=new URL(e);return t.searchParams.delete(b),t.toString()}let I={compress:R,decompress:C,parse:S,update:x,remove:E,replaceUrl:function({url:e,context:t}){let n;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let r=e??window.location.href;(n=null!==t?x({url:r,context:t}):E(r))&&window.history.replaceState(null,"",n.toString())}},k={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31},L=Object.entries(k).reduce((e,[t,n])=>(e[t]=BigInt(1)<<BigInt(n),e),{}),F={press:{openArticle:"0xc0a24ffb",readArticle:"0xd5bd0fbe"},dapp:{proofVerifiableStorageUpdate:"0x2ab2aeef",callableVerifiableStorageUpdate:"0xa07da986"},webshop:{open:"0xb311798f"},referral:{referred:"0x010cc3b9",createLink:"0xb2c0f17c"},purchase:{started:"0xd87e90c3",completed:"0x8403aeb4",unsafeCompleted:"0x4d5b14e0"},retail:{customerMeeting:"0x74489004"}};export{o as ClientNotFound,i as DebugInfoGatherer,c as Deferred,I as FrakContextManager,r as FrakRpcError,s as RpcErrorCodes,h as baseIframeProps,f as compressJson,g as createIFrameFrakClient,m as createIframe,l as decompressDataAndCheckHash,d as decompressJson,u as hashAndCompressData,F as interactionTypes,k as productTypes,L as productTypesMask,v as setupClient};
13
+ `.trim()}}class s{_promise;_resolve;_reject;constructor(){this._promise=new Promise((e,t)=>{this._resolve=e,this._reject=t})}get promise(){return this._promise}resolve=e=>{this._resolve?.(e)};reject=e=>{this._reject?.(e)}}function c(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function l(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(e.length+(0===t?0:4-t),"=")),e=>e.charCodeAt(0))}let d=new e.CborEncoder;function u(e){let t={...e,validationHash:h(e)};return d.encode(t)}function f(e){return d.encode(e)}function p(e){return c(f(e))}function h(e){return(0,t.sha256)(d.encode(e))}let m=new e.CborDecoder;function g(e){if(!e.length)throw new n(a.corruptedResponse,"Missing compressed data");let t=w(e);if(!t)throw new n(a.corruptedResponse,"Invalid compressed data");if(!t?.validationHash)throw new n(a.corruptedResponse,"Missing validation hash");let{validationHash:r,...o}=t;if(h(o)!==t.validationHash)throw new n(a.corruptedResponse,"Invalid data validation hash");return t}function w(e){try{return m.decode(e)}catch(t){return console.error("Invalid compressed data",{e:t,data:e}),null}}function y(e){return w(l(e))}let b="nexus-wallet-backup",v={id:"frak-wallet",name:"frak-wallet",allow:"publickey-credentials-get *; clipboard-write; web-share *",style:{width:"0",height:"0",border:"0",position:"absolute",zIndex:2000001,top:"-1000px",left:"-1000px"}};function C({walletBaseUrl:e,config:t}){let n=document.querySelector("#frak-wallet");n&&n.remove();let r=document.createElement("iframe");return r.id=v.id,r.name=v.name,r.allow=v.allow,r.style.zIndex=v.style.zIndex.toString(),R({iframe:r,isVisible:!1}),document.body.appendChild(r),new Promise(n=>{r?.addEventListener("load",()=>n(r)),r.src=`${t?.walletUrl??e??"https://wallet.frak.id"}/listener`})}function R({iframe:e,isVisible:t}){if(!t){e.style.width="0",e.style.height="0",e.style.border="0",e.style.position="fixed",e.style.top="-1000px",e.style.left="-1000px";return}e.style.position="fixed",e.style.top="0",e.style.left="0",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}function S({config:e,iframe:t}){let o=function(){let e=new Map;return{createChannel:t=>{let n=Math.random().toString(36).substring(7);return e.set(n,t),n},getRpcResolver:t=>e.get(t),removeChannel:t=>e.delete(t),destroy:()=>e.clear()}}(),c=function({iframe:e}){let t=new s;return{handleEvent:async n=>{switch(n.iframeLifecycle){case"connected":t.resolve(!0);break;case"do-backup":n.data.backup?localStorage.setItem(b,n.data.backup):localStorage.removeItem(b);break;case"remove-backup":localStorage.removeItem(b);break;case"show":case"hide":R({iframe:e,isVisible:"show"===n.iframeLifecycle});break;case"handshake":e.contentWindow?.postMessage({clientLifecycle:"handshake-response",data:{token:n.data.token,currentUrl:window.location.href}},"*")}},isConnected:t.promise}}({iframe:t}),l=new i(e,t),d=function({frakWalletUrl:e,iframe:t,channelManager:r,iframeLifecycleManager:o,debugInfo:i}){if("undefined"==typeof window)throw new n(a.configError,"iframe client should be used in the browser");if(!t.contentWindow)throw new n(a.configError,"The iframe does not have a product window");let s=t.contentWindow;async function c(t){if(!t.origin)return;try{if(new URL(t.origin).origin.toLowerCase()!==new URL(e).origin.toLowerCase())return}catch(e){console.log("Unable to check frak msg origin",e);return}if("object"!=typeof t.data)return;if(i.setLastResponse(t),"iframeLifecycle"in t.data){await o.handleEvent(t.data);return}if("clientLifecycle"in t.data){console.error("Client lifecycle event received on the client side, dismissing it");return}let n=t.data.id,a=r.getRpcResolver(n);a&&a(t.data)}return window.addEventListener("message",c),{sendEvent:function(t){s.postMessage(t,{targetOrigin:e}),i.setLastRequest(t,e)},cleanup:function(){window.removeEventListener("message",c)}}}({frakWalletUrl:e?.walletUrl??"https://wallet.frak.id",iframe:t,channelManager:o,iframeLifecycleManager:c,debugInfo:l}),f=async e=>{if(!await c.isConnected)throw new n(a.clientNotConnected,"The iframe provider isn't connected yet");let t=new s,r=o.createChannel(e=>{let a=g(e.data);a.error?t.reject(new n(a.error.code,a.error.message,a.error?.data)):t.resolve(a.result),o.removeChannel(r)}),i=u(e);return d.sendEvent({id:r,topic:e.method,data:i}),t.promise},p=async(e,t)=>{if(!await c.isConnected)throw new n(a.clientNotConnected,"The iframe provider isn't connected yet");let i=o.createChannel(e=>{let n=g(e.data);if(n.result)t(n.result);else throw new r("No valid result in the response")}),s=u(e);d.sendEvent({id:i,topic:e.method,data:s})},h=function(e,t){let n,r;let o=()=>e.sendEvent({clientLifecycle:"heartbeat"});function a(){n&&clearInterval(n),r&&clearTimeout(r)}return async function(){o(),n=setInterval(o,100),r=setTimeout(()=>{a(),console.log("Heartbeat timeout: connection failed")},3e4),await t.isConnected,a()}(),a}(d,c),m=async()=>{h(),o.destroy(),d.cleanup(),t.remove()},w=E({config:e,messageHandler:d,lifecycleManager:c}).then(()=>l.updateSetupStatus(!0));return{config:e,debugInfo:l,waitForConnection:c.isConnected,waitForSetup:w,request:f,listenerRequest:p,destroy:m}}async function E({config:e,messageHandler:t,lifecycleManager:n}){async function r(){let n=e.customizations?.css;n&&t.sendEvent({clientLifecycle:"modal-css",data:{cssLink:n}})}async function o(){let n=e.customizations?.i18n;n&&t.sendEvent({clientLifecycle:"modal-i18n",data:{i18n:n}})}async function a(){if("undefined"==typeof window)return;let e=window.localStorage.getItem(b);e&&t.sendEvent({clientLifecycle:"restore-backup",data:{backup:e}})}await n.isConnected,await Promise.all([r(),o(),a()])}let k={eur:"fr-FR",usd:"en-US",gbp:"en-GB"};function x(e){return e&&e in k?e:"eur"}async function I({config:e}){let t=function(e){let t=x(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}(e),n=await C({config:t});if(!n){console.error("Failed to create iframe");return}let r=S({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error("Failed to connect to client");return}return r}function L(e){return e?`${e}Amount`:"eurAmount"}let F="fCtx";function D(e){if(e?.r)try{let n=(0,t.hexToBytes)(e.r);return c(n)}catch(t){console.error("Error compressing Frak context",{e:t,context:e})}}function U(e){if(e&&0!==e.length)try{let n=l(e);return{r:(0,t.bytesToHex)(n,{size:20})}}catch(t){console.error("Error decompressing Frak context",{e:t,context:e})}}function A({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(F);return t?U(t):null}function N({url:e,context:t}){if(!e)return null;let n=A({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let o=D(r);if(!o)return null;let a=new URL(e);return a.searchParams.set(F,o),a.toString()}function $(e){let t=new URL(e);return t.searchParams.delete(F),t.toString()}let q={compress:D,decompress:U,parse:A,update:N,remove:$,replaceUrl:function({url:e,context:t}){let n;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let r=e??window.location.href;(n=null!==t?N({url:r,context:t}):$(r))&&window.history.replaceState(null,"",n.toString())}};function T(e){return e?k[e]??k.eur:k.eur}function j(e,t){let n=T(t),r=x(t);return e.toLocaleString(n,{style:"currency",currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}let _={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31},M=Object.entries(_).reduce((e,[t,n])=>(e[t]=BigInt(1)<<BigInt(n),e),{}),P={press:{openArticle:"0xc0a24ffb",readArticle:"0xd5bd0fbe"},dapp:{proofVerifiableStorageUpdate:"0x2ab2aeef",callableVerifiableStorageUpdate:"0xa07da986"},webshop:{open:"0xb311798f"},referral:{referred:"0x010cc3b9",createLink:"0xb2c0f17c"},purchase:{started:"0xd87e90c3",completed:"0x8403aeb4",unsafeCompleted:"0x4d5b14e0"},retail:{customerMeeting:"0x74489004"}};export{o as ClientNotFound,i as DebugInfoGatherer,s as Deferred,q as FrakContextManager,n as FrakRpcError,a as RpcErrorCodes,l as base64urlDecode,c as base64urlEncode,v as baseIframeProps,f as compressJson,p as compressJsonToB64,S as createIFrameFrakClient,C as createIframe,g as decompressDataAndCheckHash,w as decompressJson,y as decompressJsonFromB64,j as formatAmount,L as getCurrencyAmountKey,x as getSupportedCurrency,T as getSupportedLocale,u as hashAndCompressData,P as interactionTypes,k as locales,_ as productTypes,M as productTypesMask,I as setupClient};