@frak-labs/core-sdk 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +58 -0
  2. package/cdn/bundle.js +14 -0
  3. package/dist/actions.cjs +1 -1
  4. package/dist/actions.d.cts +3 -3
  5. package/dist/actions.d.ts +3 -3
  6. package/dist/actions.js +1 -1
  7. package/dist/bundle.cjs +1 -1
  8. package/dist/bundle.d.cts +4 -6
  9. package/dist/bundle.d.ts +4 -6
  10. package/dist/bundle.js +1 -1
  11. package/dist/{index-CRsQWnTs.d.cts → computeLegacyProductId-BkyJ4rEY.d.ts} +197 -10
  12. package/dist/{index-Ck1hudEi.d.ts → computeLegacyProductId-Raks6FXg.d.cts} +197 -10
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +3 -4
  15. package/dist/index.d.ts +3 -4
  16. package/dist/index.js +1 -1
  17. package/dist/{openSso-D--Airj6.d.cts → openSso-BCJGchIb.d.cts} +135 -131
  18. package/dist/{openSso-DsKJ4y0j.d.ts → openSso-DG-_9CED.d.ts} +135 -131
  19. package/dist/setupClient-CQrMDGyZ.js +13 -0
  20. package/dist/setupClient-Ccv3XxwL.cjs +13 -0
  21. package/dist/{index-d8xS4ryI.d.ts → siweAuthenticate-BH7Dn7nZ.d.cts} +90 -65
  22. package/dist/siweAuthenticate-BJHbtty4.js +1 -0
  23. package/dist/{index-C6FxkWPC.d.cts → siweAuthenticate-Btem4QHs.d.ts} +90 -65
  24. package/dist/siweAuthenticate-Cwj3HP0m.cjs +1 -0
  25. package/dist/trackEvent-M2RLTQ2p.js +1 -0
  26. package/dist/trackEvent-T_R9ER2S.cjs +1 -0
  27. package/package.json +11 -22
  28. package/src/actions/displayEmbeddedWallet.ts +1 -0
  29. package/src/actions/displayModal.test.ts +12 -11
  30. package/src/actions/displayModal.ts +7 -18
  31. package/src/actions/ensureIdentity.ts +68 -0
  32. package/src/actions/{getProductInformation.test.ts → getMerchantInformation.test.ts} +33 -50
  33. package/src/actions/getMerchantInformation.ts +16 -0
  34. package/src/actions/index.ts +3 -2
  35. package/src/actions/openSso.ts +4 -2
  36. package/src/actions/referral/processReferral.test.ts +42 -151
  37. package/src/actions/referral/processReferral.ts +18 -42
  38. package/src/actions/referral/referralInteraction.test.ts +1 -7
  39. package/src/actions/referral/referralInteraction.ts +1 -6
  40. package/src/actions/sendInteraction.ts +46 -22
  41. package/src/actions/trackPurchaseStatus.test.ts +354 -141
  42. package/src/actions/trackPurchaseStatus.ts +48 -11
  43. package/src/actions/watchWalletStatus.ts +2 -3
  44. package/src/actions/wrapper/modalBuilder.test.ts +0 -14
  45. package/src/actions/wrapper/modalBuilder.ts +3 -12
  46. package/src/bundle.ts +0 -1
  47. package/src/clients/createIFrameFrakClient.ts +10 -5
  48. package/src/clients/transports/iframeLifecycleManager.test.ts +163 -4
  49. package/src/clients/transports/iframeLifecycleManager.ts +172 -33
  50. package/src/constants/interactionTypes.ts +12 -41
  51. package/src/index.ts +24 -16
  52. package/src/types/config.ts +6 -0
  53. package/src/types/index.ts +13 -10
  54. package/src/types/lifecycle/client.ts +24 -1
  55. package/src/types/lifecycle/iframe.ts +6 -0
  56. package/src/types/rpc/displayModal.ts +2 -4
  57. package/src/types/rpc/embedded/index.ts +2 -2
  58. package/src/types/rpc/interaction.ts +26 -39
  59. package/src/types/rpc/merchantInformation.ts +77 -0
  60. package/src/types/rpc/modal/index.ts +0 -4
  61. package/src/types/rpc/modal/login.ts +5 -1
  62. package/src/types/rpc/walletStatus.ts +1 -7
  63. package/src/types/rpc.ts +22 -30
  64. package/src/types/tracking.ts +60 -0
  65. package/src/utils/backendUrl.test.ts +83 -0
  66. package/src/utils/backendUrl.ts +62 -0
  67. package/src/utils/clientId.test.ts +41 -0
  68. package/src/utils/clientId.ts +43 -0
  69. package/src/utils/compression/compress.test.ts +1 -1
  70. package/src/utils/compression/compress.ts +2 -2
  71. package/src/utils/compression/decompress.test.ts +8 -4
  72. package/src/utils/compression/decompress.ts +2 -2
  73. package/src/utils/{computeProductId.ts → computeLegacyProductId.ts} +2 -2
  74. package/src/utils/constants.ts +5 -0
  75. package/src/utils/deepLinkWithFallback.test.ts +243 -0
  76. package/src/utils/deepLinkWithFallback.ts +103 -0
  77. package/src/utils/formatAmount.ts +6 -0
  78. package/src/utils/iframeHelper.test.ts +18 -5
  79. package/src/utils/iframeHelper.ts +10 -3
  80. package/src/utils/index.ts +16 -1
  81. package/src/utils/merchantId.test.ts +653 -0
  82. package/src/utils/merchantId.ts +143 -0
  83. package/src/utils/sso.ts +18 -11
  84. package/src/utils/trackEvent.test.ts +23 -5
  85. package/src/utils/trackEvent.ts +13 -0
  86. package/cdn/bundle.iife.js +0 -14
  87. package/dist/actions-B5j-i1p0.cjs +0 -1
  88. package/dist/actions-q090Z0oR.js +0 -1
  89. package/dist/index-7OZ39x1U.d.ts +0 -195
  90. package/dist/index-zDq-VlKx.d.cts +0 -195
  91. package/dist/interaction-DMJ3ZfaF.d.cts +0 -45
  92. package/dist/interaction-KX1h9a7V.d.ts +0 -45
  93. package/dist/interactions-DnfM3oe0.js +0 -1
  94. package/dist/interactions-EIXhNLf6.cjs +0 -1
  95. package/dist/interactions.cjs +0 -1
  96. package/dist/interactions.d.cts +0 -2
  97. package/dist/interactions.d.ts +0 -2
  98. package/dist/interactions.js +0 -1
  99. package/dist/productTypes-BUkXJKZ7.cjs +0 -1
  100. package/dist/productTypes-CGb1MmBF.js +0 -1
  101. package/dist/src-1LQ4eLq5.js +0 -13
  102. package/dist/src-hW71KjPN.cjs +0 -13
  103. package/dist/trackEvent-CHnYa85W.js +0 -1
  104. package/dist/trackEvent-GuQm_1Nm.cjs +0 -1
  105. package/src/actions/getProductInformation.ts +0 -14
  106. package/src/actions/openSso.test.ts +0 -407
  107. package/src/actions/sendInteraction.test.ts +0 -219
  108. package/src/constants/interactionTypes.test.ts +0 -128
  109. package/src/constants/productTypes.test.ts +0 -130
  110. package/src/constants/productTypes.ts +0 -33
  111. package/src/interactions/index.ts +0 -5
  112. package/src/interactions/pressEncoder.test.ts +0 -215
  113. package/src/interactions/pressEncoder.ts +0 -53
  114. package/src/interactions/purchaseEncoder.test.ts +0 -291
  115. package/src/interactions/purchaseEncoder.ts +0 -99
  116. package/src/interactions/referralEncoder.test.ts +0 -170
  117. package/src/interactions/referralEncoder.ts +0 -47
  118. package/src/interactions/retailEncoder.test.ts +0 -107
  119. package/src/interactions/retailEncoder.ts +0 -37
  120. package/src/interactions/webshopEncoder.test.ts +0 -56
  121. package/src/interactions/webshopEncoder.ts +0 -30
  122. package/src/types/rpc/modal/openSession.ts +0 -25
  123. package/src/types/rpc/productInformation.ts +0 -59
  124. package/src/utils/computeProductId.test.ts +0 -80
  125. package/src/utils/sso.test.ts +0 -361
@@ -1,6 +1,5 @@
1
1
  import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
2
- import { type Address, type Hex, isAddressEqual } from "viem";
3
- import { ReferralInteractionEncoder } from "../../interactions";
2
+ import { type Address, isAddressEqual } from "viem";
4
3
  import type {
5
4
  DisplayEmbeddedWalletParamsType,
6
5
  FrakClient,
@@ -8,7 +7,8 @@ import type {
8
7
  WalletStatusReturnType,
9
8
  } from "../../types";
10
9
  import { FrakContextManager, trackEvent } from "../../utils";
11
- import { displayEmbeddedWallet, sendInteraction } from "../index";
10
+ import { displayEmbeddedWallet } from "../displayEmbeddedWallet";
11
+ import { sendInteraction } from "../sendInteraction";
12
12
 
13
13
  /**
14
14
  * The different states of the referral process
@@ -19,7 +19,6 @@ type ReferralState =
19
19
  | "processing"
20
20
  | "success"
21
21
  | "no-wallet"
22
- | "no-session"
23
22
  | "error"
24
23
  | "no-referrer"
25
24
  | "self-referral";
@@ -41,11 +40,9 @@ export type ProcessReferralOptions = {
41
40
  * 2. Then check if the user is logged in or not
42
41
  * 2.1 If not logged in, try a soft login, if it fail, display a modal for the user to login
43
42
  * 3. Check if that's not a self-referral (if yes, early exit)
44
- * 4. Check if the user has an interaction session or not
45
- * 4.1 If not, display a modal for the user to open a session
46
- * 5. Push the referred interaction
47
- * 6. Update the current url with the right data
48
- * 7. Return the resulting referral state
43
+ * 4. Track the referral event
44
+ * 5. Update the current url with the right data
45
+ * 6. Return the resulting referral state
49
46
  *
50
47
  * If any error occurs during the process, the function will catch it and return an error state
51
48
  *
@@ -54,13 +51,10 @@ export type ProcessReferralOptions = {
54
51
  * @param args.walletStatus - The current user wallet status
55
52
  * @param args.frakContext - The current frak context
56
53
  * @param args.modalConfig - The modal configuration to display if the user is not logged in
57
- * @param args.productId - The product id to interact with (if not specified will be recomputed from the current domain)
58
54
  * @param args.options - Some options for the referral interaction
59
55
  * @returns A promise with the resulting referral state
60
56
  *
61
57
  * @see {@link displayModal} for more details about the displayed modal
62
- * @see {@link sendInteraction} for more details on the interaction submission part
63
- * @see {@link ReferralInteractionEncoder} for more details about the referred interaction
64
58
  * @see {@link @frak-labs/core-sdk!ModalStepTypes} for more details on each modal steps types
65
59
  */
66
60
  export async function processReferral(
@@ -69,13 +63,11 @@ export async function processReferral(
69
63
  walletStatus,
70
64
  frakContext,
71
65
  modalConfig,
72
- productId,
73
66
  options,
74
67
  }: {
75
68
  walletStatus?: WalletStatusReturnType;
76
69
  frakContext?: Partial<FrakContext> | null;
77
70
  modalConfig?: DisplayEmbeddedWalletParamsType;
78
- productId?: Hex;
79
71
  options?: ProcessReferralOptions;
80
72
  }
81
73
  ) {
@@ -92,6 +84,13 @@ export async function processReferral(
92
84
  },
93
85
  });
94
86
 
87
+ sendInteraction(client, {
88
+ type: "arrival",
89
+ referrerWallet: frakContext.r,
90
+ landingUrl:
91
+ typeof window !== "undefined" ? window.location.href : undefined,
92
+ });
93
+
95
94
  // Helper to fetch a fresh wallet status
96
95
  let walletRequest = false;
97
96
  async function getFreshWalletStatus() {
@@ -112,20 +111,11 @@ export async function processReferral(
112
111
  });
113
112
  }
114
113
 
115
- // Helper function to push the interaction
116
- async function pushReferralInteraction(referrer: Address) {
117
- const interaction = ReferralInteractionEncoder.referred({
118
- referrer,
119
- });
120
- await sendInteraction(client, { productId, interaction });
121
- }
122
-
123
114
  try {
124
115
  // Do the core processing logic
125
116
  const { status, currentWallet } = await processReferralLogic({
126
117
  initialWalletStatus: walletStatus,
127
118
  getFreshWalletStatus,
128
- pushReferralInteraction,
129
119
  // We can enforce this type cause of the condition at the start
130
120
  frakContext: frakContext as Pick<FrakContext, "r">,
131
121
  });
@@ -176,42 +166,30 @@ export async function processReferral(
176
166
  }
177
167
 
178
168
  /**
179
- * Automatically submit a referral interaction when detected
180
- * -> And automatically set the referral context in the url
181
- * @param walletStatus
182
- * @param frakContext
169
+ * Process referral logic - ensure user is logged in and check for self-referral
183
170
  */
184
171
  async function processReferralLogic({
185
172
  initialWalletStatus,
186
173
  getFreshWalletStatus,
187
- pushReferralInteraction,
188
174
  frakContext,
189
175
  }: {
190
176
  initialWalletStatus?: WalletStatusReturnType;
191
177
  getFreshWalletStatus: () => Promise<Address | undefined>;
192
- pushReferralInteraction: (referrer: Address) => Promise<void>;
193
178
  frakContext: Pick<FrakContext, "r">;
194
179
  }) {
195
180
  // Get the current wallet, without auto displaying the modal
196
181
  let currentWallet = initialWalletStatus?.wallet;
197
182
 
198
- // If we don't have a current wallet, display the modal
183
+ // If we don't have a current wallet, display the modal to log in
199
184
  if (!currentWallet) {
200
- // Track the event
201
185
  currentWallet = await getFreshWalletStatus();
202
186
  }
203
187
 
188
+ // Check for self-referral
204
189
  if (currentWallet && isAddressEqual(frakContext.r, currentWallet)) {
205
190
  return { status: "self-referral", currentWallet } as const;
206
191
  }
207
192
 
208
- // If the current wallet doesn't have an interaction session, display the modal
209
- if (!initialWalletStatus?.interactionSession) {
210
- currentWallet = await getFreshWalletStatus();
211
- }
212
-
213
- // Push the referred interaction
214
- await pushReferralInteraction(frakContext.r);
215
193
  return { status: "success", currentWallet } as const;
216
194
  }
217
195
 
@@ -228,8 +206,8 @@ async function ensureWalletConnected(
228
206
  walletStatus?: WalletStatusReturnType;
229
207
  }
230
208
  ) {
231
- // If wallet not connected, or no interaction session
232
- if (!walletStatus?.interactionSession) {
209
+ // If wallet not connected, display modal
210
+ if (walletStatus?.key !== "connected") {
233
211
  const result = await displayEmbeddedWallet(client, modalConfig ?? {});
234
212
  return result?.wallet ?? undefined;
235
213
  }
@@ -246,8 +224,6 @@ function mapErrorToState(error: unknown): ReferralState {
246
224
  switch (error.code) {
247
225
  case RpcErrorCodes.walletNotConnected:
248
226
  return "no-wallet";
249
- case RpcErrorCodes.serverErrorForInteractionDelegation:
250
- return "no-session";
251
227
  default:
252
228
  return "error";
253
229
  }
@@ -21,9 +21,6 @@ describe("referralInteraction", () => {
21
21
  request: vi.fn(),
22
22
  } as any;
23
23
 
24
- const mockProductId =
25
- "0x0000000000000000000000000000000000000000000000000000000000000002" as Hex;
26
-
27
24
  beforeEach(() => {
28
25
  vi.clearAllMocks();
29
26
  Object.defineProperty(global, "window", {
@@ -55,8 +52,8 @@ describe("referralInteraction", () => {
55
52
 
56
53
  vi.mocked(FrakContextManager.parse).mockReturnValue({} as any);
57
54
  vi.mocked(watchWalletStatus).mockResolvedValue({
55
+ key: "connected",
58
56
  wallet: "0x123" as Hex,
59
- interactionSession: true,
60
57
  } as any);
61
58
  vi.mocked(processReferral).mockResolvedValue("success");
62
59
 
@@ -80,7 +77,6 @@ describe("referralInteraction", () => {
80
77
  vi.mocked(processReferral).mockResolvedValue("success");
81
78
 
82
79
  await referralInteraction(mockClient, {
83
- productId: mockProductId,
84
80
  modalConfig: mockModalConfig as any,
85
81
  options: mockOptions,
86
82
  });
@@ -89,7 +85,6 @@ describe("referralInteraction", () => {
89
85
  walletStatus: mockWalletStatus,
90
86
  frakContext: mockContext,
91
87
  modalConfig: mockModalConfig,
92
- productId: mockProductId,
93
88
  options: mockOptions,
94
89
  });
95
90
  });
@@ -145,7 +140,6 @@ describe("referralInteraction", () => {
145
140
  mockClient,
146
141
  expect.objectContaining({
147
142
  modalConfig: undefined,
148
- productId: undefined,
149
143
  options: undefined,
150
144
  })
151
145
  );
@@ -1,4 +1,3 @@
1
- import type { Hex } from "viem";
2
1
  import type { DisplayEmbeddedWalletParamsType, FrakClient } from "../../types";
3
2
  import { FrakContextManager } from "../../utils";
4
3
  import { watchWalletStatus } from "../index";
@@ -8,10 +7,9 @@ import {
8
7
  } from "./processReferral";
9
8
 
10
9
  /**
11
- * Function used to display a modal
10
+ * Function used to handle referral interactions
12
11
  * @param client - The current Frak Client
13
12
  * @param args
14
- * @param args.productId - The product id to interact with (if not specified will be recomputed from the current domain)
15
13
  * @param args.modalConfig - The modal configuration to display if the user is not logged in
16
14
  * @param args.options - Some options for the referral interaction
17
15
  *
@@ -25,11 +23,9 @@ import {
25
23
  export async function referralInteraction(
26
24
  client: FrakClient,
27
25
  {
28
- productId,
29
26
  modalConfig,
30
27
  options,
31
28
  }: {
32
- productId?: Hex;
33
29
  modalConfig?: DisplayEmbeddedWalletParamsType;
34
30
  options?: ProcessReferralOptions;
35
31
  } = {}
@@ -47,7 +43,6 @@ export async function referralInteraction(
47
43
  walletStatus: currentWalletStatus,
48
44
  frakContext,
49
45
  modalConfig,
50
- productId,
51
46
  options,
52
47
  });
53
48
  } catch (error) {
@@ -1,32 +1,56 @@
1
- import type {
2
- FrakClient,
3
- SendInteractionParamsType,
4
- SendInteractionReturnType,
5
- } from "../types";
6
- import { computeProductId } from "../utils/computeProductId";
1
+ import type { FrakClient } from "../types";
2
+ import type { SendInteractionParamsType } from "../types/rpc/interaction";
3
+ import { getClientId } from "../utils/clientId";
7
4
 
8
5
  /**
9
- * Function used to send an interaction
10
- * @param client - The current Frak Client
11
- * @param args
6
+ * Send an interaction to the backend via the listener RPC.
7
+ * Fire-and-forget: errors are caught and logged, not thrown.
8
+ *
9
+ * @param client - The Frak client instance
10
+ * @param params - The interaction parameters
11
+ *
12
+ * @description Sends a user interaction event through the wallet iframe RPC. Supports three interaction types: arrival tracking, sharing events, and custom interactions.
12
13
  *
13
14
  * @example
14
- * const interaction = PressInteractionEncoder.openArticle({
15
- * articleId: keccak256(toHex("article-slug")),
15
+ * Track a user arrival with referral attribution:
16
+ * ```ts
17
+ * await sendInteraction(client, {
18
+ * type: "arrival",
19
+ * referrerWallet: "0x1234...abcd",
20
+ * landingUrl: window.location.href,
21
+ * utmSource: "twitter",
22
+ * utmMedium: "social",
23
+ * utmCampaign: "launch-2026",
16
24
  * });
17
- * const { delegationId } = await sendInteraction(frakConfig, {
18
- * interaction,
25
+ * ```
26
+ *
27
+ * @example
28
+ * Track a sharing event:
29
+ * ```ts
30
+ * await sendInteraction(client, { type: "sharing" });
31
+ * ```
32
+ *
33
+ * @example
34
+ * Send a custom interaction:
35
+ * ```ts
36
+ * await sendInteraction(client, {
37
+ * type: "custom",
38
+ * customType: "newsletter_signup",
39
+ * data: { email: "user@example.com" },
19
40
  * });
20
- * console.log("Delegated interaction id", delegationId);
41
+ * ```
21
42
  */
22
43
  export async function sendInteraction(
23
44
  client: FrakClient,
24
- { productId, interaction, validation }: SendInteractionParamsType
25
- ): Promise<SendInteractionReturnType> {
26
- const pId = productId ?? computeProductId(client.config);
27
-
28
- return await client.request({
29
- method: "frak_sendInteraction",
30
- params: [pId, interaction, validation],
31
- });
45
+ params: SendInteractionParamsType
46
+ ): Promise<void> {
47
+ try {
48
+ await client.request({
49
+ method: "frak_sendInteraction",
50
+ params: [params, { clientId: getClientId() }],
51
+ });
52
+ } catch {
53
+ // Silent failure - fire-and-forget
54
+ console.warn("[Frak SDK] Failed to send interaction:", params.type);
55
+ }
32
56
  }