@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/actions.d.ts CHANGED
@@ -4,6 +4,12 @@ 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
+ * All the currencies available
9
+ * @category Config
10
+ */
11
+ declare type Currency = "eur" | "usd" | "gbp";
12
+
7
13
  /**
8
14
  * Function used to display the Frak embeded wallet popup
9
15
  * @param client - The current Frak Client
@@ -12,36 +18,31 @@ import type { SiweMessage } from 'viem/siwe';
12
18
  export declare function displayEmbededWallet(client: FrakClient, params: DisplayEmbededWalletParamsType): Promise<void>;
13
19
 
14
20
  /**
15
- * The params used to display the embeded wallet
21
+ * The params used to display the embedded wallet
16
22
  *
17
- * @group Embeded wallet
23
+ * @group Embedded wallet
18
24
  */
19
25
  declare type DisplayEmbededWalletParamsType = {
20
26
  /**
21
- * The embeded view to display once the user is logged in
27
+ * The embedded view to display once the user is logged in
22
28
  */
23
29
  loggedIn?: LoggedInEmbededView;
24
30
  /**
25
- * The embeded view to display once the user is logged out
31
+ * The embedded view to display once the user is logged out
26
32
  */
27
33
  loggedOut?: LoggedOutEmbededView;
28
34
  /**
29
- * Some metadata to customise the embeded view
35
+ * Some metadata to customize the embedded view
30
36
  */
31
37
  metadata?: {
32
38
  /**
33
- * Language of the embeded wallet
34
- * If undefined, will default to the browser language
35
- */
36
- lang?: "fr" | "en";
37
- /**
38
- * The logo to display on the embeded wallet
39
+ * The logo to display on the embedded wallet
39
40
  * If undefined, will default to no logo displayed
40
41
  */
41
42
  logo?: string;
42
43
  /**
43
44
  * Link to the homepage of the calling website
44
- * If unedfined, will default to the domain of the calling website
45
+ * If undefined, will default to the domain of the calling website
45
46
  */
46
47
  homepageLink?: string;
47
48
  /**
@@ -52,6 +53,10 @@ declare type DisplayEmbededWalletParamsType = {
52
53
  * The position of the component
53
54
  */
54
55
  position?: "left" | "right";
56
+ /**
57
+ * Some i18n override for the displayed modal (i.e. update the displayed text only for this modal)
58
+ */
59
+ i18n?: I18nConfig;
55
60
  };
56
61
  };
57
62
 
@@ -60,13 +65,13 @@ declare type DisplayEmbededWalletParamsType = {
60
65
  * @param client - The current Frak Client
61
66
  * @param args
62
67
  * @param args.steps - The different steps of the modal
63
- * @param args.metadata - The metadata for the modal (customisation, language etc)
68
+ * @param args.metadata - The metadata for the modal (customization, etc)
64
69
  * @returns The result of each modal steps
65
70
  *
66
71
  * @description This function will display a modal to the user with the provided steps and metadata.
67
72
  *
68
73
  * @remarks
69
- * - The UI of the displayed modal can be configured with the `customCss` property in the `metadata.css` field of the top-level config.
74
+ * - The UI of the displayed modal can be configured with the `customCss` property in the `customizations.css` field of the top-level config.
70
75
  * - The `login` and `openSession` steps will be automatically skipped if the user is already logged in or has an active session. It's safe to include these steps in all cases to ensure proper user state.
71
76
  * - Steps are automatically reordered in the following sequence:
72
77
  * 1. `login` (if needed)
@@ -83,9 +88,9 @@ declare type DisplayEmbededWalletParamsType = {
83
88
  * ```ts
84
89
  * const results = await displayModal(frakConfig, {
85
90
  * steps: {
86
- * // Simple login with no SSO, nor customisation
91
+ * // Simple login with no SSO, nor customization
87
92
  * login: { allowSso: false },
88
- * // Simple session opening, with no customisation
93
+ * // Simple session opening, with no customization
89
94
  * openSession: {},
90
95
  * // Success message
91
96
  * final: {
@@ -104,7 +109,7 @@ declare type DisplayEmbededWalletParamsType = {
104
109
  * ```
105
110
  *
106
111
  * @example
107
- * A full modal example, with a few customisation options, with the steps:
112
+ * A full modal example, with a few customization options, with the steps:
108
113
  * 1. Login (Skipped if already logged in)
109
114
  * 2. Open a session (Skipped if already opened)
110
115
  * 3. Authenticate via SIWE
@@ -121,16 +126,6 @@ declare type DisplayEmbededWalletParamsType = {
121
126
  * logoUrl: "https://my-app.com/logo.png",
122
127
  * homepageLink: "https://my-app.com",
123
128
  * },
124
- * metadata: {
125
- * // Modal title on desktop
126
- * title: "Login on My-App",
127
- * // Modal description (and yep it accept markdown)
128
- * description: "## Please login to continue",
129
- * // Primary button text
130
- * primaryActionText: "Register",
131
- * // Secondary button text
132
- * secondaryActionText: "Login",
133
- * },
134
129
  * },
135
130
  * // Simple session opening, with no customisation
136
131
  * openSession: {},
@@ -142,11 +137,6 @@ declare type DisplayEmbededWalletParamsType = {
142
137
  * nonce: generateSiweNonce(),
143
138
  * version: "1",
144
139
  * },
145
- * metadata: {
146
- * title: "Authenticate with SIWE",
147
- * description: "Please authenticate with SIWE to continue",
148
- * primaryActionText: "Authenticate",
149
- * },
150
140
  * },
151
141
  * // Send batched transaction
152
142
  * sendTransaction: {
@@ -154,10 +144,6 @@ declare type DisplayEmbededWalletParamsType = {
154
144
  * { to: "0xdeadbeef", data: "0xdeadbeef" },
155
145
  * { to: "0xdeadbeef", data: "0xdeadbeef" },
156
146
  * ],
157
- * metadata: {
158
- * title: "Send a transaction",
159
- * description: "Please send a transaction to continue",
160
- * },
161
147
  * },
162
148
  * // Success message with sharing options
163
149
  * final: {
@@ -183,8 +169,6 @@ declare type DisplayEmbededWalletParamsType = {
183
169
  * },
184
170
  * // Context that will be present in every modal steps
185
171
  * context: "My-app overkill flow",
186
- * // Language of the modal
187
- * lang: "fr",
188
172
  * },
189
173
  * });
190
174
  * ```
@@ -202,9 +186,9 @@ declare type DisplayModalParamsType<T extends ModalStepTypes[]> = {
202
186
  };
203
187
 
204
188
  /**
205
- * The different type of action we can have on the embeded view (once the user is logged in)
189
+ * The different type of action we can have on the embedded view (once the user is logged in)
206
190
  *
207
- * @group Embeded wallet
191
+ * @group Embedded wallet
208
192
  */
209
193
  declare type EmbededViewAction = {
210
194
  key: "sharing";
@@ -214,11 +198,13 @@ declare type EmbededViewAction = {
214
198
  options?: {
215
199
  /**
216
200
  * The title that will be displayed on the system popup once the system sharing window is open
201
+ * @deprecated Use the top level `config.metadata.i18n` instead
217
202
  */
218
203
  popupTitle?: string;
219
204
  /**
220
205
  * The text that will be shared alongside the link.
221
206
  * Can contain the variable {LINK} to specify where the link is placed, otherwise it will be added at the end
207
+ * @deprecated Use the top level `config.metadata.i18n` instead
222
208
  */
223
209
  text?: string;
224
210
  /**
@@ -263,7 +249,13 @@ declare type ExtractedReturnTypeFromRpc<TRpcSchema extends RpcSchema, TParameter
263
249
  declare type FinalActionType = {
264
250
  key: "sharing";
265
251
  options?: {
252
+ /**
253
+ * @deprecated Use the top level `config.metadata.i18n` instead
254
+ */
266
255
  popupTitle?: string;
256
+ /**
257
+ * @deprecated Use the top level `config.metadata.i18n` instead
258
+ */
267
259
  text?: string;
268
260
  link?: string;
269
261
  };
@@ -300,13 +292,16 @@ declare type FrakClient = {
300
292
  * The current Frak Context
301
293
  *
302
294
  * For now, only contain a referrer address.
295
+ *
296
+ * @ignore
303
297
  */
304
298
  declare type FrakContext = {
305
299
  r: Address;
306
300
  };
307
301
 
308
302
  /**
309
- * Configuration for the Nexus Wallet SDK
303
+ * Configuration for the Frak Wallet SDK
304
+ * @category Config
310
305
  */
311
306
  declare type FrakWalletSdkConfig = {
312
307
  /**
@@ -322,10 +317,37 @@ declare type FrakWalletSdkConfig = {
322
317
  * Your application name (will be displayed in a few modals and in SSO)
323
318
  */
324
319
  name: string;
320
+ /**
321
+ * Language to display in the modal
322
+ * If undefined, will default to the browser language
323
+ */
324
+ lang?: Language;
325
+ /**
326
+ * The currency to display in the modal
327
+ * @defaultValue `"eur"`
328
+ */
329
+ currency?: Currency;
330
+ /**
331
+ * The logo URL that will be displayed in a few components
332
+ */
333
+ logoUrl?: string;
334
+ /**
335
+ * The homepage link that could be displayed in a few components
336
+ */
337
+ homepageLink?: string;
338
+ };
339
+ /**
340
+ * Some customization for the modal
341
+ */
342
+ customizations?: {
325
343
  /**
326
344
  * Custom CSS styles to apply to the modals and components
327
345
  */
328
- css?: string;
346
+ css?: `${string}.css`;
347
+ /**
348
+ * Custom i18n configuration for the modal
349
+ */
350
+ i18n?: I18nConfig;
329
351
  };
330
352
  /**
331
353
  * The domain name of your application
@@ -387,9 +409,13 @@ declare type GetProductInformationReturnType = {
387
409
  productTypes: ProductTypesKey[];
388
410
  };
389
411
  /**
390
- * The max potential reward in EUR for the given product
412
+ * The max potential reward for the referrer
391
413
  */
392
- estimatedEurReward?: string;
414
+ maxReferrer?: TokenAmountType;
415
+ /**
416
+ * The max potential reward for the referee
417
+ */
418
+ maxReferee?: TokenAmountType;
393
419
  /**
394
420
  * List of all the potentials reward arround this product
395
421
  */
@@ -397,19 +423,46 @@ declare type GetProductInformationReturnType = {
397
423
  token: Address;
398
424
  campaign: Address;
399
425
  interactionTypeKey: FullInteractionTypesKey;
400
- referrer: {
401
- amount: number;
402
- eurAmount: number;
403
- usdAmount: number;
404
- };
405
- referee: {
406
- amount: number;
407
- eurAmount: number;
408
- usdAmount: number;
409
- };
426
+ referrer: TokenAmountType;
427
+ referee: TokenAmountType;
410
428
  }[];
411
429
  };
412
430
 
431
+ /**
432
+ * Custom i18n configuration for the modal
433
+ * See [i18next json format](https://www.i18next.com/misc/json-format#i18next-json-v4)
434
+ *
435
+ * Available variables
436
+ * - `{{ productName }}` : The name of your website (`metadata.name`)
437
+ * - `{{ productOrigin }}` : The origin url of your website
438
+ * - `{{ 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)
439
+ *
440
+ * Context of the translation [see i18n context](https://www.i18next.com/translation-function/context)
441
+ * - For modal display, the key of the final action (`sharing`, `reward`, or undefined)
442
+ * - For embedded wallet display, the key of the logged in action (`sharing` or undefined)
443
+ *
444
+ * @example
445
+ * ```ts
446
+ * // Multi language config
447
+ * const multiI18n = {
448
+ * fr: {
449
+ * "sdk.modal.title": "Titre de modal",
450
+ * "sdk.modal.description": "Description de modal, avec {{ estimatedReward }} de gains possible",
451
+ * },
452
+ * en: "https://example.com/en.json"
453
+ * }
454
+ *
455
+ * // Single language config
456
+ * const singleI18n = {
457
+ * "sdk.modal.title": "Modal title",
458
+ * "sdk.modal.description": "Modal description, with {{ estimatedReward }} of gains possible",
459
+ * }
460
+ * ```
461
+ *
462
+ * @category Config
463
+ */
464
+ declare type I18nConfig = Record<Language, LocalizedI18nConfig> | LocalizedI18nConfig;
465
+
413
466
  /**
414
467
  * RPC interface that's used for the iframe communication
415
468
  *
@@ -460,8 +513,8 @@ declare type IFrameRpcSchema = [
460
513
  Method: "frak_displayModal";
461
514
  Parameters: [
462
515
  requests: ModalRpcStepsInput,
463
- name: string,
464
- metadata?: ModalRpcMetadata
516
+ metadata: ModalRpcMetadata | undefined,
517
+ configMetadata: FrakWalletSdkConfig["metadata"]
465
518
  ];
466
519
  ReturnType: ModalRpcStepsResultType;
467
520
  },
@@ -502,11 +555,14 @@ declare type IFrameRpcSchema = [
502
555
  ReturnType: GetProductInformationReturnType;
503
556
  },
504
557
  /**
505
- * Method to show the embeded wallet, with potential customisation
558
+ * Method to show the embedded wallet, with potential customization
506
559
  */
507
560
  {
508
561
  Method: "frak_displayEmbededWallet";
509
- Parameters: [DisplayEmbededWalletParamsType, name: string];
562
+ Parameters: [
563
+ request: DisplayEmbededWalletParamsType,
564
+ metadata: FrakWalletSdkConfig["metadata"]
565
+ ];
510
566
  ReturnType: undefined;
511
567
  }
512
568
  ];
@@ -566,6 +622,12 @@ declare const interactionTypes: {
566
622
  };
567
623
  };
568
624
 
625
+ /**
626
+ * All the languages available
627
+ * @category Config
628
+ */
629
+ declare type Language = "fr" | "en";
630
+
569
631
  /**
570
632
  * Type used for a listening request
571
633
  * @inline
@@ -573,13 +635,21 @@ declare const interactionTypes: {
573
635
  declare type ListenerRequestFn<TRpcSchema extends RpcSchema> = <TParameters extends ExtractedParametersFromRpc<TRpcSchema> = ExtractedParametersFromRpc<TRpcSchema>, _ReturnType = ExtractedReturnTypeFromRpc<TRpcSchema, TParameters>>(args: TParameters, callback: (result: _ReturnType) => void) => Promise<void>;
574
636
 
575
637
  /**
576
- * Some configuration options for the embeded view
638
+ * A localized i18n config
639
+ * @category Config
640
+ */
641
+ declare type LocalizedI18nConfig = `${string}.css` | {
642
+ [key: string]: string;
643
+ };
644
+
645
+ /**
646
+ * Some configuration options for the embedded view
577
647
  *
578
- * @group Embeded wallet
648
+ * @group Embedded wallet
579
649
  */
580
650
  declare type LoggedInEmbededView = {
581
651
  /**
582
- * The main action to display on the logged in embeded view
652
+ * The main action to display on the logged in embedded view
583
653
  * If none specified, the user will see his wallet with the activation button
584
654
  */
585
655
  action?: EmbededViewAction;
@@ -587,26 +657,28 @@ declare type LoggedInEmbededView = {
587
657
 
588
658
  /**
589
659
  * The view when a user is logged out
590
- * @group Embeded wallet
660
+ * @group Embedded wallet
591
661
  */
592
662
  declare type LoggedOutEmbededView = {
593
663
  /**
594
- * Metadata option when displaying the embeded view
664
+ * Metadata option when displaying the embedded view
595
665
  */
596
666
  metadata?: {
597
667
  /**
598
668
  * The main CTA for the logged out view
599
669
  * - can include some variable, available ones are:
600
- * - {REWARD} -> The maximum reward a user can receive when itneracting on your website
670
+ * - {REWARD} -> The maximum reward a user can receive when interacting on your website
601
671
  * - can be formatted in markdown
602
672
  *
603
- * If not sert, it will default to a internalised message
673
+ * If not set, it will default to a internationalized message
674
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
604
675
  */
605
676
  text?: string;
606
677
  /**
607
678
  * The text that will be displayed on the login button
608
679
  *
609
- * If not set, it will default to a internalised message
680
+ * If not set, it will default to a internationalized message
681
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
610
682
  */
611
683
  buttonText?: string;
612
684
  };
@@ -633,7 +705,7 @@ declare type LoginWithoutSso = {
633
705
  /** @inline */
634
706
  declare type LoginWithSso = {
635
707
  allowSso: true;
636
- ssoMetadata: SsoMetadata;
708
+ ssoMetadata?: SsoMetadata;
637
709
  };
638
710
 
639
711
  /**
@@ -695,11 +767,16 @@ declare type ModalRpcMetadata = {
695
767
  title?: string;
696
768
  icon?: string;
697
769
  };
698
- context?: string;
699
- lang?: "en" | "fr";
700
770
  targetInteraction?: FullInteractionTypesKey;
771
+ /**
772
+ * Some i18n override for the displayed modal (i.e. update the displayed text only for this modal)
773
+ */
774
+ i18n?: I18nConfig;
701
775
  } & ({
702
776
  isDismissible: true;
777
+ /**
778
+ * @deprecated Use `config.customizations.i18n` or `metadata.i18n` instead
779
+ */
703
780
  dismissActionTxt?: string;
704
781
  } | {
705
782
  isDismissible?: false;
@@ -762,29 +839,34 @@ export declare type ModalStepBuilder<Steps extends ModalStepTypes[] = ModalStepT
762
839
  };
763
840
 
764
841
  /**
765
- * Metadata that can be used to customise a modal step
842
+ * Metadata that can be used to customize a modal step
766
843
  * @group Modal Display
844
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
767
845
  */
768
846
  declare type ModalStepMetadata = {
769
847
  metadata?: {
770
848
  /**
771
849
  * Custom title for the step
772
- * If none provided, it will use an internationalised text
850
+ * If none provided, it will use an internationalized text
851
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
773
852
  */
774
853
  title?: string;
775
854
  /**
776
855
  * Custom description for the step
777
- * If none provided, it will use an internationalised text
856
+ * If none provided, it will use an internationalized text
857
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
778
858
  */
779
859
  description?: string;
780
860
  /**
781
861
  * Custom text for the primary action of the step
782
- * If none provided, it will use an internationalised text
862
+ * If none provided, it will use an internationalized text
863
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
783
864
  */
784
865
  primaryActionText?: string;
785
866
  /**
786
867
  * Custom text for the secondary action of the step
787
- * If none provided, it will use an internationalised text
868
+ * If none provided, it will use an internationalized text
869
+ * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead
788
870
  */
789
871
  secondaryActionText?: string;
790
872
  };
@@ -845,7 +927,7 @@ declare type OpenInteractionSessionReturnType = {
845
927
  * ```ts [Redirection]
846
928
  * // Trigger an sso opening within a popup with direct exit
847
929
  * await openSso(frakConfig, {
848
- * redirectUrl: "https://my-app.com/nexus-sso",
930
+ * redirectUrl: "https://my-app.com/frak-sso",
849
931
  * metadata,
850
932
  * });
851
933
  * ```
@@ -1200,6 +1282,16 @@ declare type SsoMetadata = {
1200
1282
  homepageLink?: string;
1201
1283
  };
1202
1284
 
1285
+ /**
1286
+ * The type for the amount of tokens
1287
+ */
1288
+ declare type TokenAmountType = {
1289
+ amount: number;
1290
+ eurAmount: number;
1291
+ usdAmount: number;
1292
+ gbpAmount: number;
1293
+ };
1294
+
1203
1295
  /**
1204
1296
  * Function used to track the status of a purchase
1205
1297
  * when a purchase is tracked, the `purchaseCompleted` interactions will be automatically send for the user when we receive the purchase confirmation via webhook.
package/dist/actions.js CHANGED
@@ -1 +1 @@
1
- import*as e from"viem";import*as t from"viem/siwe";class n{_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 r(e,t){if(!t)return e.request({method:"frak_listenToWalletStatus"}).then(e=>(a(e.interactionToken),e));let r=new n,o=!1;return e.listenerRequest({method:"frak_listenToWalletStatus"},e=>{t(e),a(e.interactionToken),o||(r.resolve(e),o=!0)}).then(()=>r.promise)}function a(e){"undefined"!=typeof window&&(e?window.sessionStorage.setItem("frak-wallet-interaction-token",e):window.sessionStorage.removeItem("frak.interaction-token"))}async function o(t,{productId:n,interaction:r,validation:a}){let o=n??function({domain:t}){let n=t??window.location.host;return(0,e.keccak256)((0,e.toHex)(n))}(t.config);return await t.request({method:"frak_sendInteraction",params:[o,r,a]})}async function i(e,{steps:t,metadata:n}){return await e.request({method:"frak_displayModal",params:[t,e.config.metadata.name,n]})}async function s(e,t){await e.request({method:"frak_displayEmbededWallet",params:[t,e.config.metadata.name]})}async function c(e,t){let{metadata:n}=e.config;await e.request({method:"frak_sso",params:[t,n.name,n.css]})}async function l(e){return await e.request({method:"frak_getProductInformation"})}async function u(e){if("undefined"==typeof window){console.warn("[Frak] No window found, can't track purchase");return}let t=window.sessionStorage.getItem("frak-wallet-interaction-token");if(!t){console.warn("[Frak] No frak session found, skipping purchase check");return}await fetch("https://backend.frak.id/interactions/listenForPurchase",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","x-wallet-sdk-auth":t},body:JSON.stringify(e)})}async function f(e,{siwe:n,metadata:r}){let a=e.config?.domain??window.location.host,o=n?.statement??`I confirm that I want to use my Frak wallet on: ${e.config.metadata.name}`,s={...n,statement:o,nonce:n?.nonce??(0,t.generateSiweNonce)(),uri:n?.uri??`https://${a}`,version:n?.version??"1",domain:a};return(await i(e,{metadata:r,steps:{login:{},siweAuthenticate:{siwe:s}}})).siweAuthenticate}async function d(e,{tx:t,metadata:n}){return(await i(e,{metadata:n,steps:{login:{},sendTransaction:{tx:t}}})).sendTransaction}function w(e,{metadata:t,login:n,openSession:r}){return function e(t,n){async function r(e){return e&&(n.metadata=e(n.metadata??{})),await i(t,n)}return{params:n,sendTx:function(r){return e(t,{...n,steps:{...n.steps,sendTransaction:r}})},reward:function(r){return e(t,{...n,steps:{...n.steps,final:{...r,action:{key:"reward"}}}})},sharing:function(r,a){return e(t,{...n,steps:{...n.steps,final:{...a,action:{key:"sharing",options:r}}}})},display:r}}(e,{steps:{login:n??{},openSession:r??{}},metadata:t})}let p="fCtx";function h({url:t}){if(!t)return null;let n=new URL(t).searchParams.get(p);return n?function(t){if(t&&0!==t.length)try{let n=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))}(t);return{r:(0,e.bytesToHex)(n,{size:20})}}catch(e){console.error("Error decompressing Frak context",{e,context:t})}}(n):null}let m={parse:h,replaceUrl:function({url:t,context:n}){let r;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let a=t??window.location.href;(r=null!==n?function({url:t,context:n}){if(!t)return null;let r=h({url:t}),a=r?{...r,...n}:n;if(!a.r)return null;let o=function(t){if(t?.r)try{var n;return n=(0,e.hexToBytes)(t.r),btoa(Array.from(n,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}catch(e){console.error("Error compressing Frak context",{e,context:t})}}(a);if(!o)return null;let i=new URL(t);return i.searchParams.set(p,o),i.toString()}({url:a,context:n}):function(e){let t=new URL(e);return t.searchParams.delete(p),t.toString()}(a))&&window.history.replaceState(null,"",r.toString())}},g="0x010cc3b9",y="0xb2c0f17c",k={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31};Object.entries(k).reduce((e,[t,n])=>(e[t]=BigInt(1)<<BigInt(n),e),{});let S={createLink:()=>({handlerTypeDenominator:(0,e.toHex)(k.referral),interactionData:y}),referred({referrer:t}){let n=(0,e.concatHex)([g,(0,e.pad)(t,{size:32})]);return{handlerTypeDenominator:(0,e.toHex)(k.referral),interactionData:n}}};class x extends Error{code;data;constructor(e,t,n){super(t),this.code=e,this.data=n}}let _={walletNotConnected:-32005,serverErrorForInteractionDelegation:-32006};async function v(e,{walletStatus:t,frakContext:n,modalConfig:r,productId:a,options:i}){let s=!1;async function c(){if(!s)return s=!0,I(e,{modalConfig:r,walletStatus:t})}async function l(t){let n=S.referred({referrer:t});await o(e,{productId:a,interaction:n})}try{let{status:e,currentWallet:r}=await T({initialWalletStatus:t,getFreshWalletStatus:c,pushReferralInteraction:l,frakContext:n});return m.replaceUrl({url:window.location?.href,context:i?.alwaysAppendUrl?{r:r}:null}),e}catch(e){return console.log("Error processing referral",{error:e}),m.replaceUrl({url:window.location?.href,context:i?.alwaysAppendUrl?{r:t?.wallet}:null}),function(e){if(e instanceof x)switch(e.code){case _.walletNotConnected:return"no-wallet";case _.serverErrorForInteractionDelegation:return"no-session"}return"error"}(e)}}async function T({initialWalletStatus:t,getFreshWalletStatus:n,pushReferralInteraction:r,frakContext:a}){let o=t?.wallet;return a?.r?(o||(o=await n()),o&&(0,e.isAddressEqual)(a.r,o))?{status:"self-referral",currentWallet:o}:(t?.interactionSession||(o=await n()),await r(a.r),{status:"success",currentWallet:o}):{status:"no-referrer",currentWallet:o}}async function I(e,{modalConfig:t,walletStatus:n}){if(!n?.interactionSession){if(!t)return;let n=await i(e,t);return n?.login?.wallet??void 0}return n.wallet??void 0}async function b(e,{productId:t,modalConfig:n,options:a}={}){let o=m.parse({url:window.location.href}),i=await r(e);try{return await v(e,{walletStatus:i,frakContext:o,modalConfig:n,productId:t,options:a})}catch(e){console.warn("Error processing referral",{error:e})}}export{s as displayEmbededWallet,i as displayModal,l as getProductInformation,w as modalBuilder,c as openSso,v as processReferral,b as referralInteraction,o as sendInteraction,d as sendTransaction,f as siweAuthenticate,u as trackPurchaseStatus,r as watchWalletStatus};
1
+ import*as e from"viem";import*as t from"viem/siwe";class n{_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 r(e,t){if(!t)return e.request({method:"frak_listenToWalletStatus"}).then(e=>(a(e.interactionToken),e));let r=new n,o=!1;return e.listenerRequest({method:"frak_listenToWalletStatus"},e=>{t(e),a(e.interactionToken),o||(r.resolve(e),o=!0)}).then(()=>r.promise)}function a(e){"undefined"!=typeof window&&(e?window.sessionStorage.setItem("frak-wallet-interaction-token",e):window.sessionStorage.removeItem("frak.interaction-token"))}async function o(t,{productId:n,interaction:r,validation:a}){let o=n??function({domain:t}){let n=t??window.location.host;return(0,e.keccak256)((0,e.toHex)(n))}(t.config);return await t.request({method:"frak_sendInteraction",params:[o,r,a]})}async function i(e,{steps:t,metadata:n}){return await e.request({method:"frak_displayModal",params:[t,n,e.config.metadata]})}async function s(e,t){await e.request({method:"frak_displayEmbededWallet",params:[t,e.config.metadata]})}async function c(e,t){let{metadata:n,customizations:r}=e.config;await e.request({method:"frak_sso",params:[t,n.name,r?.css]})}async function l(e){return await e.request({method:"frak_getProductInformation"})}async function u(e){if("undefined"==typeof window){console.warn("[Frak] No window found, can't track purchase");return}let t=window.sessionStorage.getItem("frak-wallet-interaction-token");if(!t){console.warn("[Frak] No frak session found, skipping purchase check");return}await fetch("https://backend.frak.id/interactions/listenForPurchase",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","x-wallet-sdk-auth":t},body:JSON.stringify(e)})}async function f(e,{siwe:n,metadata:r}){let a=e.config?.domain??window.location.host,o=n?.statement??`I confirm that I want to use my Frak wallet on: ${e.config.metadata.name}`,s={...n,statement:o,nonce:n?.nonce??(0,t.generateSiweNonce)(),uri:n?.uri??`https://${a}`,version:n?.version??"1",domain:a};return(await i(e,{metadata:r,steps:{login:{},siweAuthenticate:{siwe:s}}})).siweAuthenticate}async function d(e,{tx:t,metadata:n}){return(await i(e,{metadata:n,steps:{login:{},sendTransaction:{tx:t}}})).sendTransaction}function w(e,{metadata:t,login:n,openSession:r}){return function e(t,n){async function r(e){return e&&(n.metadata=e(n.metadata??{})),await i(t,n)}return{params:n,sendTx:function(r){return e(t,{...n,steps:{...n.steps,sendTransaction:r}})},reward:function(r){return e(t,{...n,steps:{...n.steps,final:{...r,action:{key:"reward"}}}})},sharing:function(r,a){return e(t,{...n,steps:{...n.steps,final:{...a,action:{key:"sharing",options:r}}}})},display:r}}(e,{steps:{login:n??{},openSession:r??{}},metadata:t})}let p="fCtx";function h({url:t}){if(!t)return null;let n=new URL(t).searchParams.get(p);return n?function(t){if(t&&0!==t.length)try{let n=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))}(t);return{r:(0,e.bytesToHex)(n,{size:20})}}catch(e){console.error("Error decompressing Frak context",{e,context:t})}}(n):null}let m={parse:h,replaceUrl:function({url:t,context:n}){let r;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let a=t??window.location.href;(r=null!==n?function({url:t,context:n}){if(!t)return null;let r=h({url:t}),a=r?{...r,...n}:n;if(!a.r)return null;let o=function(t){if(t?.r)try{var n;return n=(0,e.hexToBytes)(t.r),btoa(Array.from(n,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}catch(e){console.error("Error compressing Frak context",{e,context:t})}}(a);if(!o)return null;let i=new URL(t);return i.searchParams.set(p,o),i.toString()}({url:a,context:n}):function(e){let t=new URL(e);return t.searchParams.delete(p),t.toString()}(a))&&window.history.replaceState(null,"",r.toString())}},g="0x010cc3b9",y="0xb2c0f17c",k={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31};Object.entries(k).reduce((e,[t,n])=>(e[t]=BigInt(1)<<BigInt(n),e),{});let S={createLink:()=>({handlerTypeDenominator:(0,e.toHex)(k.referral),interactionData:y}),referred({referrer:t}){let n=(0,e.concatHex)([g,(0,e.pad)(t,{size:32})]);return{handlerTypeDenominator:(0,e.toHex)(k.referral),interactionData:n}}};class x extends Error{code;data;constructor(e,t,n){super(t),this.code=e,this.data=n}}let _={walletNotConnected:-32005,serverErrorForInteractionDelegation:-32006};async function v(e,{walletStatus:t,frakContext:n,modalConfig:r,productId:a,options:i}){let s=!1;async function c(){if(!s)return s=!0,I(e,{modalConfig:r,walletStatus:t})}async function l(t){let n=S.referred({referrer:t});await o(e,{productId:a,interaction:n})}try{let{status:e,currentWallet:r}=await T({initialWalletStatus:t,getFreshWalletStatus:c,pushReferralInteraction:l,frakContext:n});return m.replaceUrl({url:window.location?.href,context:i?.alwaysAppendUrl?{r:r}:null}),e}catch(e){return console.log("Error processing referral",{error:e}),m.replaceUrl({url:window.location?.href,context:i?.alwaysAppendUrl?{r:t?.wallet}:null}),function(e){if(e instanceof x)switch(e.code){case _.walletNotConnected:return"no-wallet";case _.serverErrorForInteractionDelegation:return"no-session"}return"error"}(e)}}async function T({initialWalletStatus:t,getFreshWalletStatus:n,pushReferralInteraction:r,frakContext:a}){let o=t?.wallet;return a?.r?(o||(o=await n()),o&&(0,e.isAddressEqual)(a.r,o))?{status:"self-referral",currentWallet:o}:(t?.interactionSession||(o=await n()),await r(a.r),{status:"success",currentWallet:o}):{status:"no-referrer",currentWallet:o}}async function I(e,{modalConfig:t,walletStatus:n}){if(!n?.interactionSession){if(!t)return;let n=await i(e,t);return n?.login?.wallet??void 0}return n.wallet??void 0}async function b(e,{productId:t,modalConfig:n,options:a}={}){let o=m.parse({url:window.location.href}),i=await r(e);try{return await v(e,{walletStatus:i,frakContext:o,modalConfig:n,productId:t,options:a})}catch(e){console.warn("Error processing referral",{error:e})}}export{s as displayEmbededWallet,i as displayModal,l as getProductInformation,w as modalBuilder,c as openSso,v as processReferral,b as referralInteraction,o as sendInteraction,d as sendTransaction,f as siweAuthenticate,u as trackPurchaseStatus,r as watchWalletStatus};
package/dist/index.cjs CHANGED
@@ -1,13 +1,13 @@
1
- "use strict";let __rslib_import_meta_url__="undefined"==typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=function(e,t){for(var r in t)__webpack_require__.o(t,r)&&!__webpack_require__.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},__webpack_require__.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},__webpack_require__.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{DebugInfoGatherer:()=>DebugInfoGatherer,decompressJson:()=>decompressJson,productTypesMask:()=>productTypesMask,Deferred:()=>Deferred,ClientNotFound:()=>ClientNotFound,compressJson:()=>compressJson,FrakContextManager:()=>FrakContextManager,createIFrameFrakClient:()=>createIFrameFrakClient,baseIframeProps:()=>baseIframeProps,RpcErrorCodes:()=>RpcErrorCodes,productTypes:()=>productTypes,setupClient:()=>setupClient,interactionTypes:()=>interactionTypes,createIframe:()=>createIframe,decompressDataAndCheckHash:()=>decompressDataAndCheckHash,FrakRpcError:()=>FrakRpcError,hashAndCompressData:()=>hashAndCompressData});class FrakRpcError extends Error{code;data;constructor(e,t,r){super(t),this.code=e,this.data=r}}class MethodNotFoundError extends FrakRpcError{constructor(e,t){super(RpcErrorCodes.methodNotFound,e,{method:t})}}class InternalError extends FrakRpcError{constructor(e){super(RpcErrorCodes.internalError,e)}}class ClientNotFound extends FrakRpcError{constructor(){super(RpcErrorCodes.clientNotConnected,"Client not found")}}let RpcErrorCodes={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 Deferred{_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)}}let external_async_lz_string_namespaceObject=require("async-lz-string"),external_js_sha256_namespaceObject=require("js-sha256");async function decompressDataAndCheckHash(e){if(!(e?.compressed&&e?.compressedHash))throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Missing compressed data");let t=await decompressJson(e.compressed);if(!t)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Invalid compressed data");if(!t?.validationHash)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Missing validation hash");if((0,external_js_sha256_namespaceObject.sha256)(e.compressed)!==e.compressedHash)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Invalid compressed hash");let{validationHash:r,...a}=t;if((0,external_js_sha256_namespaceObject.sha256)(JSON.stringify(a))!==t.validationHash)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Invalid data validation hash");return t}async function decompressJson(e){let t=await (0,external_async_lz_string_namespaceObject.decompressFromBase64)(e);try{return JSON.parse(t)}catch(e){return console.error("Invalid compressed data",{e,decompressed:t}),null}}async function hashAndCompressData(e){let t=(0,external_js_sha256_namespaceObject.sha256)(JSON.stringify(e)),r={...e,validationHash:t},a=await compressJson(r),n=(0,external_js_sha256_namespaceObject.sha256)(a);return{compressed:a,compressedHash:n}}async function compressJson(e){return(0,external_async_lz_string_namespaceObject.compressToBase64)(JSON.stringify(e))}let BACKUP_KEY="nexus-wallet-backup";class DebugInfoGatherer{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(),a="Unknown";return e instanceof FrakRpcError?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: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:a}}static empty(){return new DebugInfoGatherer}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
1
+ "use strict";let __rslib_import_meta_url__="undefined"==typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,r)=>{for(var t in r)__webpack_require__.o(r,t)&&!__webpack_require__.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},__webpack_require__.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{decompressJson:()=>decompressJson,RpcErrorCodes:()=>RpcErrorCodes,formatAmount:()=>formatAmount,hashAndCompressData:()=>hashAndCompressData,Deferred:()=>Deferred,getCurrencyAmountKey:()=>getCurrencyAmountKey,setupClient:()=>setupClient,getSupportedCurrency:()=>getSupportedCurrency,decompressDataAndCheckHash:()=>decompressDataAndCheckHash,FrakContextManager:()=>FrakContextManager,decompressJsonFromB64:()=>decompressJsonFromB64,getSupportedLocale:()=>getSupportedLocale,locales:()=>locales,ClientNotFound:()=>ClientNotFound,base64urlDecode:()=>base64urlDecode,FrakRpcError:()=>FrakRpcError,baseIframeProps:()=>baseIframeProps,createIframe:()=>createIframe,productTypes:()=>productTypes,interactionTypes:()=>interactionTypes,productTypesMask:()=>productTypesMask,compressJson:()=>compressJson,compressJsonToB64:()=>compressJsonToB64,createIFrameFrakClient:()=>createIFrameFrakClient,DebugInfoGatherer:()=>DebugInfoGatherer,base64urlEncode:()=>base64urlEncode});class FrakRpcError extends Error{code;data;constructor(e,r,t){super(r),this.code=e,this.data=t}}class MethodNotFoundError extends FrakRpcError{constructor(e,r){super(RpcErrorCodes.methodNotFound,e,{method:r})}}class InternalError extends FrakRpcError{constructor(e){super(RpcErrorCodes.internalError,e)}}class ClientNotFound extends FrakRpcError{constructor(){super(RpcErrorCodes.clientNotConnected,"Client not found")}}let RpcErrorCodes={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 Deferred{_promise;_resolve;_reject;constructor(){this._promise=new Promise((e,r)=>{this._resolve=e,this._reject=r})}get promise(){return this._promise}resolve=e=>{this._resolve?.(e)};reject=e=>{this._reject?.(e)}}let cbor_namespaceObject=require("@jsonjoy.com/json-pack/lib/cbor");function base64urlEncode(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function base64urlDecode(e){let r=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(e.length+(0===r?0:4-r),"=")),e=>e.charCodeAt(0))}let external_viem_namespaceObject=require("viem"),encoder=new cbor_namespaceObject.CborEncoder;function hashAndCompressData(e){let r={...e,validationHash:hashJson(e)};return encoder.encode(r)}function compressJson(e){return encoder.encode(e)}function compressJsonToB64(e){return base64urlEncode(compressJson(e))}function hashJson(e){return(0,external_viem_namespaceObject.sha256)(encoder.encode(e))}let decoder=new cbor_namespaceObject.CborDecoder;function decompressDataAndCheckHash(e){if(!e.length)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Missing compressed data");let r=decompressJson(e);if(!r)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Invalid compressed data");if(!r?.validationHash)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Missing validation hash");let{validationHash:t,...n}=r;if(hashJson(n)!==r.validationHash)throw new FrakRpcError(RpcErrorCodes.corruptedResponse,"Invalid data validation hash");return r}function decompressJson(e){try{return decoder.decode(e)}catch(r){return console.error("Invalid compressed data",{e:r,data:e}),null}}function decompressJsonFromB64(e){return decompressJson(base64urlDecode(e))}let BACKUP_KEY="nexus-wallet-backup";class DebugInfoGatherer{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,r){this.config=e,this.iframe=r,this.lastRequest=null,this.lastResponse=null}setLastResponse(e){this.lastResponse={event:e.data,origin:e.origin,timestamp:Date.now()}}setLastRequest(e,r){this.lastRequest={event:e,target:r,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 r=this.getIframeStatus(),t=this.getNavigatorInfo(),n="Unknown";return e instanceof FrakRpcError?n=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?n=e.message:"string"==typeof e&&(n=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):"no-config",navigatorInfo:t?this.base64Encode(t):"no-navigator",iframeStatus:r?this.base64Encode(r):"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:n}}static empty(){return new DebugInfoGatherer}formatDebugInfo(e){let r=this.gatherDebugInfo(e);return`
2
2
  Debug Information:
3
3
  -----------------
4
- Timestamp: ${t.timestamp}
5
- URL: ${t.encodedUrl}
6
- Config: ${t.encodedConfig}
7
- Navigator Info: ${t.navigatorInfo}
8
- IFrame Status: ${t.iframeStatus}
9
- Last Request: ${t.lastRequest}
10
- Last Response: ${t.lastResponse}
11
- Client Status: ${t.clientStatus}
12
- Error: ${t.error}
13
- `.trim()}}function createIFrameChannelManager(){let e=new Map;return{createChannel:t=>{let r=Math.random().toString(36).substring(7);return e.set(r,t),r},getRpcResolver:t=>e.get(t),removeChannel:t=>e.delete(t),destroy:()=>e.clear()}}let baseIframeProps={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 createIframe({walletBaseUrl:e,config:t}){let r=document.querySelector("#nexus-wallet");r&&r.remove();let a=document.createElement("iframe");return a.id=baseIframeProps.id,a.name=baseIframeProps.name,a.allow=baseIframeProps.allow,a.style.zIndex=baseIframeProps.style.zIndex.toString(),changeIframeVisibility({iframe:a,isVisible:!1}),document.body.appendChild(a),new Promise(r=>{a?.addEventListener("load",()=>r(a)),a.src=`${t?.walletUrl??e??"https://wallet.frak.id"}/listener`})}function changeIframeVisibility({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 createIFrameLifecycleManager({iframe:e}){let t=new Deferred;return{handleEvent:async r=>{switch(r.iframeLifecycle){case"connected":t.resolve(!0);break;case"do-backup":r.data.backup?localStorage.setItem(BACKUP_KEY,r.data.backup):localStorage.removeItem(BACKUP_KEY);break;case"remove-backup":localStorage.removeItem(BACKUP_KEY);break;case"show":case"hide":changeIframeVisibility({iframe:e,isVisible:"show"===r.iframeLifecycle});break;case"handshake":e.contentWindow?.postMessage({clientLifecycle:"handshake-response",data:{token:r.data.token,currentUrl:window.location.href}},"*")}},isConnected:t.promise}}function createIFrameMessageHandler({frakWalletUrl:e,iframe:t,channelManager:r,iframeLifecycleManager:a,debugInfo:n}){if("undefined"==typeof window)throw new FrakRpcError(RpcErrorCodes.configError,"iframe client should be used in the browser");if(!t.contentWindow)throw new FrakRpcError(RpcErrorCodes.configError,"The iframe does not have a product window");let o=t.contentWindow;async function s(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(n.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 o=t.data.id,s=r.getRpcResolver(o);s&&await s(t.data)}return window.addEventListener("message",s),{sendEvent:function(t){o.postMessage(t,{targetOrigin:e}),n.setLastRequest(t,e)},cleanup:function(){window.removeEventListener("message",s)}}}function createIFrameFrakClient({config:e,iframe:t}){let r=createIFrameChannelManager(),a=createIFrameLifecycleManager({iframe:t}),n=new DebugInfoGatherer(e,t),o=createIFrameMessageHandler({frakWalletUrl:e?.walletUrl??"https://wallet.frak.id",iframe:t,channelManager:r,iframeLifecycleManager:a,debugInfo:n}),s=async e=>{if(!await a.isConnected)throw new FrakRpcError(RpcErrorCodes.clientNotConnected,"The iframe provider isn't connected yet");let t=new Deferred,n=r.createChannel(async e=>{let a=await decompressDataAndCheckHash(e.data);a.error?t.reject(new FrakRpcError(a.error.code,a.error.message,a.error?.data)):t.resolve(a.result),r.removeChannel(n)}),s=await hashAndCompressData(e);return o.sendEvent({id:n,topic:e.method,data:s}),t.promise},i=async(e,t)=>{if(!await a.isConnected)throw new FrakRpcError(RpcErrorCodes.clientNotConnected,"The iframe provider isn't connected yet");let n=r.createChannel(async e=>{let r=await decompressDataAndCheckHash(e.data);if(r.result)t(r.result);else throw new InternalError("No valid result in the response")}),s=await hashAndCompressData(e);o.sendEvent({id:n,topic:e.method,data:s})},c=setupHeartbeat(o,a),l=async()=>{c(),r.destroy(),o.cleanup(),t.remove()},d=postConnectionSetup({config:e,messageHandler:o,lifecycleManager:a}).then(()=>n.updateSetupStatus(!0));return{config:e,debugInfo:n,waitForConnection:a.isConnected,waitForSetup:d,request:s,listenerRequest:i,destroy:l}}function setupHeartbeat(e,t){let r,a;let n=()=>e.sendEvent({clientLifecycle:"heartbeat"});function o(){r&&clearInterval(r),a&&clearTimeout(a)}return async function(){n(),r=setInterval(n,100),a=setTimeout(()=>{o(),console.log("Heartbeat timeout: connection failed")},3e4),await t.isConnected,o()}(),o}async function postConnectionSetup({config:e,messageHandler:t,lifecycleManager:r}){await r.isConnected;let a=async()=>{let r=e.metadata.css;r&&t.sendEvent({clientLifecycle:"modal-css",data:{cssLink:r}})},n=async()=>{if("undefined"==typeof window)return;let e=window.localStorage.getItem(BACKUP_KEY);e&&t.sendEvent({clientLifecycle:"restore-backup",data:{backup:e}})};await Promise.all([a(),n()])}async function setupClient({config:e}){let t=await createIframe({config:e});if(!t){console.error("Failed to create iframe");return}let r=createIFrameFrakClient({config:e,iframe:t});if(await r.waitForSetup,!await r.waitForConnection){console.error("Failed to connect to client");return}return r}let external_viem_namespaceObject=require("viem"),contextKey="fCtx";function base64url_encode(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function base64url_decode(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))}function compress(e){if(e?.r)try{let t=(0,external_viem_namespaceObject.hexToBytes)(e.r);return base64url_encode(t)}catch(t){console.error("Error compressing Frak context",{e:t,context:e})}}function decompress(e){if(e&&0!==e.length)try{let t=base64url_decode(e);return{r:(0,external_viem_namespaceObject.bytesToHex)(t,{size:20})}}catch(t){console.error("Error decompressing Frak context",{e:t,context:e})}}function parse({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(contextKey);return t?decompress(t):null}function update({url:e,context:t}){if(!e)return null;let r=parse({url:e}),a=r?{...r,...t}:t;if(!a.r)return null;let n=compress(a);if(!n)return null;let o=new URL(e);return o.searchParams.set(contextKey,n),o.toString()}function remove(e){let t=new URL(e);return t.searchParams.delete(contextKey),t.toString()}function replaceUrl({url:e,context:t}){let r;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let a=e??window.location.href;(r=null!==t?update({url:a,context:t}):remove(a))&&window.history.replaceState(null,"",r.toString())}let FrakContextManager={compress,decompress,parse,update,remove,replaceUrl},productTypes={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31},productTypesMask=Object.entries(productTypes).reduce((e,[t,r])=>(e[t]=BigInt(1)<<BigInt(r),e),{}),interactionTypes={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"}};var __webpack_export_target__=exports;for(var __webpack_i__ in __webpack_exports__)__webpack_export_target__[__webpack_i__]=__webpack_exports__[__webpack_i__];__webpack_exports__.__esModule&&Object.defineProperty(__webpack_export_target__,"__esModule",{value:!0});
4
+ Timestamp: ${r.timestamp}
5
+ URL: ${r.encodedUrl}
6
+ Config: ${r.encodedConfig}
7
+ Navigator Info: ${r.navigatorInfo}
8
+ IFrame Status: ${r.iframeStatus}
9
+ Last Request: ${r.lastRequest}
10
+ Last Response: ${r.lastResponse}
11
+ Client Status: ${r.clientStatus}
12
+ Error: ${r.error}
13
+ `.trim()}}function createIFrameChannelManager(){let e=new Map;return{createChannel:r=>{let t=Math.random().toString(36).substring(7);return e.set(t,r),t},getRpcResolver:r=>e.get(r),removeChannel:r=>e.delete(r),destroy:()=>e.clear()}}let baseIframeProps={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 createIframe({walletBaseUrl:e,config:r}){let t=document.querySelector("#frak-wallet");t&&t.remove();let n=document.createElement("iframe");return n.id=baseIframeProps.id,n.name=baseIframeProps.name,n.allow=baseIframeProps.allow,n.style.zIndex=baseIframeProps.style.zIndex.toString(),changeIframeVisibility({iframe:n,isVisible:!1}),document.body.appendChild(n),new Promise(t=>{n?.addEventListener("load",()=>t(n)),n.src=`${r?.walletUrl??e??"https://wallet.frak.id"}/listener`})}function changeIframeVisibility({iframe:e,isVisible:r}){if(!r){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 createIFrameLifecycleManager({iframe:e}){let r=new Deferred;return{handleEvent:async t=>{switch(t.iframeLifecycle){case"connected":r.resolve(!0);break;case"do-backup":t.data.backup?localStorage.setItem(BACKUP_KEY,t.data.backup):localStorage.removeItem(BACKUP_KEY);break;case"remove-backup":localStorage.removeItem(BACKUP_KEY);break;case"show":case"hide":changeIframeVisibility({iframe:e,isVisible:"show"===t.iframeLifecycle});break;case"handshake":e.contentWindow?.postMessage({clientLifecycle:"handshake-response",data:{token:t.data.token,currentUrl:window.location.href}},"*")}},isConnected:r.promise}}function createIFrameMessageHandler({frakWalletUrl:e,iframe:r,channelManager:t,iframeLifecycleManager:n,debugInfo:o}){if("undefined"==typeof window)throw new FrakRpcError(RpcErrorCodes.configError,"iframe client should be used in the browser");if(!r.contentWindow)throw new FrakRpcError(RpcErrorCodes.configError,"The iframe does not have a product window");let a=r.contentWindow;async function s(r){if(!r.origin)return;try{if(new URL(r.origin).origin.toLowerCase()!==new URL(e).origin.toLowerCase())return}catch(e){console.log("Unable to check frak msg origin",e);return}if("object"!=typeof r.data)return;if(o.setLastResponse(r),"iframeLifecycle"in r.data){await n.handleEvent(r.data);return}if("clientLifecycle"in r.data){console.error("Client lifecycle event received on the client side, dismissing it");return}let a=r.data.id,s=t.getRpcResolver(a);s&&s(r.data)}return window.addEventListener("message",s),{sendEvent:function(r){a.postMessage(r,{targetOrigin:e}),o.setLastRequest(r,e)},cleanup:function(){window.removeEventListener("message",s)}}}function createIFrameFrakClient({config:e,iframe:r}){let t=createIFrameChannelManager(),n=createIFrameLifecycleManager({iframe:r}),o=new DebugInfoGatherer(e,r),a=createIFrameMessageHandler({frakWalletUrl:e?.walletUrl??"https://wallet.frak.id",iframe:r,channelManager:t,iframeLifecycleManager:n,debugInfo:o}),s=async e=>{if(!await n.isConnected)throw new FrakRpcError(RpcErrorCodes.clientNotConnected,"The iframe provider isn't connected yet");let r=new Deferred,o=t.createChannel(e=>{let n=decompressDataAndCheckHash(e.data);n.error?r.reject(new FrakRpcError(n.error.code,n.error.message,n.error?.data)):r.resolve(n.result),t.removeChannel(o)}),s=hashAndCompressData(e);return a.sendEvent({id:o,topic:e.method,data:s}),r.promise},c=async(e,r)=>{if(!await n.isConnected)throw new FrakRpcError(RpcErrorCodes.clientNotConnected,"The iframe provider isn't connected yet");let o=t.createChannel(e=>{let t=decompressDataAndCheckHash(e.data);if(t.result)r(t.result);else throw new InternalError("No valid result in the response")}),s=hashAndCompressData(e);a.sendEvent({id:o,topic:e.method,data:s})},i=setupHeartbeat(a,n),l=async()=>{i(),t.destroy(),a.cleanup(),r.remove()},d=postConnectionSetup({config:e,messageHandler:a,lifecycleManager:n}).then(()=>o.updateSetupStatus(!0));return{config:e,debugInfo:o,waitForConnection:n.isConnected,waitForSetup:d,request:s,listenerRequest:c,destroy:l}}function setupHeartbeat(e,r){let t,n;let o=()=>e.sendEvent({clientLifecycle:"heartbeat"});function a(){t&&clearInterval(t),n&&clearTimeout(n)}return async function(){o(),t=setInterval(o,100),n=setTimeout(()=>{a(),console.log("Heartbeat timeout: connection failed")},3e4),await r.isConnected,a()}(),a}async function postConnectionSetup({config:e,messageHandler:r,lifecycleManager:t}){async function n(){let t=e.customizations?.css;t&&r.sendEvent({clientLifecycle:"modal-css",data:{cssLink:t}})}async function o(){let t=e.customizations?.i18n;t&&r.sendEvent({clientLifecycle:"modal-i18n",data:{i18n:t}})}async function a(){if("undefined"==typeof window)return;let e=window.localStorage.getItem(BACKUP_KEY);e&&r.sendEvent({clientLifecycle:"restore-backup",data:{backup:e}})}await t.isConnected,await Promise.all([n(),o(),a()])}let locales={eur:"fr-FR",usd:"en-US",gbp:"en-GB"};function getSupportedCurrency(e){return e&&e in locales?e:"eur"}async function setupClient({config:e}){let r=prepareConfig(e),t=await createIframe({config:r});if(!t){console.error("Failed to create iframe");return}let n=createIFrameFrakClient({config:r,iframe:t});if(await n.waitForSetup,!await n.waitForConnection){console.error("Failed to connect to client");return}return n}function prepareConfig(e){let r=getSupportedCurrency(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:r}}}function getSupportedLocale(e){return e?locales[e]??locales.eur:locales.eur}function formatAmount(e,r){let t=getSupportedLocale(r),n=getSupportedCurrency(r);return e.toLocaleString(t,{style:"currency",currency:n,minimumFractionDigits:0,maximumFractionDigits:2})}function getCurrencyAmountKey(e){return e?`${e}Amount`:"eurAmount"}let contextKey="fCtx";function compress(e){if(e?.r)try{let r=(0,external_viem_namespaceObject.hexToBytes)(e.r);return base64urlEncode(r)}catch(r){console.error("Error compressing Frak context",{e:r,context:e})}}function decompress(e){if(e&&0!==e.length)try{let r=base64urlDecode(e);return{r:(0,external_viem_namespaceObject.bytesToHex)(r,{size:20})}}catch(r){console.error("Error decompressing Frak context",{e:r,context:e})}}function parse({url:e}){if(!e)return null;let r=new URL(e).searchParams.get(contextKey);return r?decompress(r):null}function update({url:e,context:r}){if(!e)return null;let t=parse({url:e}),n=t?{...t,...r}:r;if(!n.r)return null;let o=compress(n);if(!o)return null;let a=new URL(e);return a.searchParams.set(contextKey,o),a.toString()}function remove(e){let r=new URL(e);return r.searchParams.delete(contextKey),r.toString()}function replaceUrl({url:e,context:r}){let t;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let n=e??window.location.href;(t=null!==r?update({url:n,context:r}):remove(n))&&window.history.replaceState(null,"",t.toString())}let FrakContextManager={compress,decompress,parse,update,remove,replaceUrl},productTypes={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31},productTypesMask=Object.entries(productTypes).reduce((e,[r,t])=>(e[r]=BigInt(1)<<BigInt(t),e),{}),interactionTypes={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"}};var __webpack_export_target__=exports;for(var __webpack_i__ in __webpack_exports__)__webpack_export_target__[__webpack_i__]=__webpack_exports__[__webpack_i__];__webpack_exports__.__esModule&&Object.defineProperty(__webpack_export_target__,"__esModule",{value:!0});