@tolinku/react-native-sdk 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -2
- package/dist/index.d.mts +116 -2
- package/dist/index.d.ts +116 -2
- package/dist/index.js +243 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +244 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,6 +105,32 @@ await Tolinku.referrals.claimReward(referral_code);
|
|
|
105
105
|
const { leaderboard } = await Tolinku.referrals.leaderboard(10);
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
### Ecommerce
|
|
109
|
+
|
|
110
|
+
Track purchases, cart activity, and product events with built-in revenue analytics. Available on paid plans.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
Tolinku.setUserId('user_123');
|
|
114
|
+
|
|
115
|
+
// Track a product view
|
|
116
|
+
await Tolinku.ecommerce.viewItem({
|
|
117
|
+
items: [{ item_id: 'sku_1', item_name: 'T-Shirt', price: 24.99 }]
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Track a purchase
|
|
121
|
+
await Tolinku.ecommerce.purchase({
|
|
122
|
+
transaction_id: 'order_456',
|
|
123
|
+
revenue: 49.99,
|
|
124
|
+
currency: 'USD',
|
|
125
|
+
items: [{ item_id: 'sku_1', item_name: 'T-Shirt', price: 24.99, quantity: 2 }]
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Flush ecommerce events
|
|
129
|
+
await Tolinku.ecommerce.flush();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The SDK supports 13 event types covering the full shopping journey. Cart IDs are managed automatically via `AsyncStorage` and cleared after purchase. Events auto-flush when the app enters the background.
|
|
133
|
+
|
|
108
134
|
### Deferred Deep Links
|
|
109
135
|
|
|
110
136
|
Recover deep link context for users who installed your app after clicking a link. Deferred deep linking lets you route users to specific content even when the app was not installed at the time of the click.
|
|
@@ -116,12 +142,17 @@ if (link) {
|
|
|
116
142
|
console.log(link.deep_link_path); // e.g. "/merchant/xyz"
|
|
117
143
|
}
|
|
118
144
|
|
|
119
|
-
// Claim by device signal matching
|
|
145
|
+
// Claim by device signal matching. Timezone, language, screen size, pixel ratio and
|
|
146
|
+
// OS version are detected for you.
|
|
120
147
|
const link = await Tolinku.deferred.claimBySignals({
|
|
121
|
-
appspaceId: '
|
|
148
|
+
appspaceId: '64f0a1b2c3d4e5f60718',
|
|
122
149
|
});
|
|
123
150
|
```
|
|
124
151
|
|
|
152
|
+
`appspaceId` is your Appspace ID, not your subdomain or slug. Copy it from the dashboard
|
|
153
|
+
under **Integrate** or **Settings**. It looks like `64f0a1b2c3d4e5f60718`.
|
|
154
|
+
|
|
155
|
+
|
|
125
156
|
### In-App Messages (React Native Component)
|
|
126
157
|
|
|
127
158
|
Display server-configured in-app messages using the `<TolinkuMessages>` component. Drop it anywhere in your React Native component tree to automatically fetch and render messages as a modal overlay. Messages are created and managed from the Tolinku dashboard without shipping app updates.
|
|
@@ -201,6 +232,25 @@ await Tolinku.destroy();
|
|
|
201
232
|
| `claimReward(code)` | Claim a referral reward |
|
|
202
233
|
| `leaderboard(limit?)` | Fetch the referral leaderboard |
|
|
203
234
|
|
|
235
|
+
### `Tolinku.ecommerce`
|
|
236
|
+
|
|
237
|
+
| Method | Description |
|
|
238
|
+
|--------|-------------|
|
|
239
|
+
| `viewItem(params)` | Track a product view |
|
|
240
|
+
| `addToCart(params)` | Track item added to cart |
|
|
241
|
+
| `removeFromCart(params)` | Track item removed from cart |
|
|
242
|
+
| `addToWishlist(params)` | Track item added to wishlist |
|
|
243
|
+
| `viewCart()` | Track cart view |
|
|
244
|
+
| `addPaymentInfo()` | Track payment info entered |
|
|
245
|
+
| `beginCheckout(params?)` | Track checkout started |
|
|
246
|
+
| `purchase(params)` | Track a purchase |
|
|
247
|
+
| `refund(params)` | Track a refund |
|
|
248
|
+
| `search(params)` | Track a product search |
|
|
249
|
+
| `share(params)` | Track a product share |
|
|
250
|
+
| `rate(params)` | Track a product rating |
|
|
251
|
+
| `spendCredits(params)` | Track loyalty credits spent |
|
|
252
|
+
| `flush()` | Send all queued ecommerce events |
|
|
253
|
+
|
|
204
254
|
### `Tolinku.deferred`
|
|
205
255
|
|
|
206
256
|
| Method | Description |
|
package/dist/index.d.mts
CHANGED
|
@@ -111,6 +111,10 @@ interface ClaimBySignalsOptions {
|
|
|
111
111
|
language?: string;
|
|
112
112
|
screenWidth?: number;
|
|
113
113
|
screenHeight?: number;
|
|
114
|
+
/** Defaults to `PixelRatio.get()`. Override only if you report a custom screen size. */
|
|
115
|
+
devicePixelRatio?: number;
|
|
116
|
+
/** Defaults to `Platform.Version`. Compared on the major component only. */
|
|
117
|
+
osVersion?: string;
|
|
114
118
|
}
|
|
115
119
|
/** In-app message from the API */
|
|
116
120
|
interface Message {
|
|
@@ -146,6 +150,78 @@ interface ShowMessageOptions {
|
|
|
146
150
|
onDismiss?: (messageId: string) => void;
|
|
147
151
|
onButtonPress?: (action: string, messageId: string) => void;
|
|
148
152
|
}
|
|
153
|
+
interface EcommerceItem {
|
|
154
|
+
item_id: string;
|
|
155
|
+
item_name?: string;
|
|
156
|
+
item_category?: string;
|
|
157
|
+
item_brand?: string;
|
|
158
|
+
item_variant?: string;
|
|
159
|
+
item_list_name?: string;
|
|
160
|
+
item_list_id?: string;
|
|
161
|
+
item_image_url?: string;
|
|
162
|
+
price?: number;
|
|
163
|
+
quantity?: number;
|
|
164
|
+
currency?: string;
|
|
165
|
+
coupon_code?: string;
|
|
166
|
+
discount?: number;
|
|
167
|
+
}
|
|
168
|
+
interface PurchaseParams {
|
|
169
|
+
transaction_id: string;
|
|
170
|
+
revenue: number;
|
|
171
|
+
currency: string;
|
|
172
|
+
items?: EcommerceItem[];
|
|
173
|
+
cart_id?: string;
|
|
174
|
+
coupon_code?: string;
|
|
175
|
+
discount?: number;
|
|
176
|
+
shipping?: number;
|
|
177
|
+
tax?: number;
|
|
178
|
+
}
|
|
179
|
+
interface AddToCartParams {
|
|
180
|
+
items: EcommerceItem[];
|
|
181
|
+
cart_id?: string;
|
|
182
|
+
}
|
|
183
|
+
interface RemoveFromCartParams {
|
|
184
|
+
items: EcommerceItem[];
|
|
185
|
+
cart_id?: string;
|
|
186
|
+
}
|
|
187
|
+
interface AddToWishlistParams {
|
|
188
|
+
items: EcommerceItem[];
|
|
189
|
+
}
|
|
190
|
+
interface BeginCheckoutParams {
|
|
191
|
+
revenue?: number;
|
|
192
|
+
currency?: string;
|
|
193
|
+
cart_id?: string;
|
|
194
|
+
items?: EcommerceItem[];
|
|
195
|
+
}
|
|
196
|
+
interface RefundParams {
|
|
197
|
+
transaction_id: string;
|
|
198
|
+
revenue: number;
|
|
199
|
+
currency?: string;
|
|
200
|
+
items?: EcommerceItem[];
|
|
201
|
+
}
|
|
202
|
+
interface ViewItemParams {
|
|
203
|
+
items: EcommerceItem[];
|
|
204
|
+
}
|
|
205
|
+
interface SearchParams {
|
|
206
|
+
search_term: string;
|
|
207
|
+
}
|
|
208
|
+
interface AddPaymentInfoParams {
|
|
209
|
+
cart_id?: string;
|
|
210
|
+
}
|
|
211
|
+
interface ShareParams {
|
|
212
|
+
item_id?: string;
|
|
213
|
+
url?: string;
|
|
214
|
+
method?: string;
|
|
215
|
+
}
|
|
216
|
+
interface RateParams {
|
|
217
|
+
item_id: string;
|
|
218
|
+
rating: number;
|
|
219
|
+
max_rating?: number;
|
|
220
|
+
}
|
|
221
|
+
interface SpendCreditsParams {
|
|
222
|
+
revenue: number;
|
|
223
|
+
currency: string;
|
|
224
|
+
}
|
|
149
225
|
|
|
150
226
|
declare class HttpClient {
|
|
151
227
|
private baseUrl;
|
|
@@ -185,6 +261,41 @@ declare class TolinkuError extends Error {
|
|
|
185
261
|
constructor(message: string, status: number, code?: string);
|
|
186
262
|
}
|
|
187
263
|
|
|
264
|
+
declare class Ecommerce {
|
|
265
|
+
private client;
|
|
266
|
+
private queue;
|
|
267
|
+
private flushTimer;
|
|
268
|
+
private appStateSubscription;
|
|
269
|
+
private isFlushing;
|
|
270
|
+
private getUserId;
|
|
271
|
+
private memoryCartId;
|
|
272
|
+
constructor(client: HttpClient, getUserId: () => string | null);
|
|
273
|
+
viewItem(params: ViewItemParams): Promise<void>;
|
|
274
|
+
addToCart(params: AddToCartParams): Promise<void>;
|
|
275
|
+
removeFromCart(params: RemoveFromCartParams): Promise<void>;
|
|
276
|
+
addToWishlist(params: AddToWishlistParams): Promise<void>;
|
|
277
|
+
viewCart(): Promise<void>;
|
|
278
|
+
addPaymentInfo(params?: AddPaymentInfoParams): Promise<void>;
|
|
279
|
+
beginCheckout(params: BeginCheckoutParams): Promise<void>;
|
|
280
|
+
purchase(params: PurchaseParams): Promise<void>;
|
|
281
|
+
refund(params: RefundParams): Promise<void>;
|
|
282
|
+
search(params: SearchParams): Promise<void>;
|
|
283
|
+
share(params: ShareParams): Promise<void>;
|
|
284
|
+
rate(params: RateParams): Promise<void>;
|
|
285
|
+
spendCredits(params: SpendCreditsParams): Promise<void>;
|
|
286
|
+
flush(): Promise<void>;
|
|
287
|
+
destroy(): Promise<void>;
|
|
288
|
+
private enqueue;
|
|
289
|
+
private handleAppStateChange;
|
|
290
|
+
private startFlushTimer;
|
|
291
|
+
private cancelFlushTimer;
|
|
292
|
+
private getOrCreateCartId;
|
|
293
|
+
private getCartId;
|
|
294
|
+
private setCartId;
|
|
295
|
+
private clearCartId;
|
|
296
|
+
private generateId;
|
|
297
|
+
}
|
|
298
|
+
|
|
188
299
|
declare class Referrals {
|
|
189
300
|
private client;
|
|
190
301
|
constructor(client: HttpClient);
|
|
@@ -230,6 +341,7 @@ declare class Tolinku {
|
|
|
230
341
|
static readonly VERSION = "0.1.0";
|
|
231
342
|
private static client;
|
|
232
343
|
private static analyticsInstance;
|
|
344
|
+
private static ecommerceInstance;
|
|
233
345
|
private static referralsInstance;
|
|
234
346
|
private static deferredInstance;
|
|
235
347
|
private static _initialized;
|
|
@@ -259,9 +371,11 @@ declare class Tolinku {
|
|
|
259
371
|
*/
|
|
260
372
|
static track(eventType: string, properties?: TrackProperties): Promise<void>;
|
|
261
373
|
/**
|
|
262
|
-
* Immediately flush all queued analytics events to the server.
|
|
374
|
+
* Immediately flush all queued analytics and ecommerce events to the server.
|
|
263
375
|
*/
|
|
264
376
|
static flush(): Promise<void>;
|
|
377
|
+
/** Ecommerce: track purchases, carts, products, revenue */
|
|
378
|
+
static get ecommerce(): Ecommerce;
|
|
265
379
|
/** Referrals: create, complete, milestone, leaderboard, claimReward */
|
|
266
380
|
static get referrals(): Referrals;
|
|
267
381
|
/** Deferred deep links: claimByToken, claimBySignals */
|
|
@@ -303,4 +417,4 @@ declare function TolinkuMessages({ trigger, triggerValue, onDismiss, onButtonPre
|
|
|
303
417
|
*/
|
|
304
418
|
declare function isSafeUrl(url: string): boolean;
|
|
305
419
|
|
|
306
|
-
export { type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type ReferralInfo, type ResolvedTolinkuConfig, type ShowMessageOptions, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, isSafeUrl };
|
|
420
|
+
export { type AddPaymentInfoParams, type AddToCartParams, type AddToWishlistParams, type BeginCheckoutParams, type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type EcommerceItem, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type PurchaseParams, type RateParams, type ReferralInfo, type RefundParams, type RemoveFromCartParams, type ResolvedTolinkuConfig, type SearchParams, type ShareParams, type ShowMessageOptions, type SpendCreditsParams, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, type ViewItemParams, isSafeUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -111,6 +111,10 @@ interface ClaimBySignalsOptions {
|
|
|
111
111
|
language?: string;
|
|
112
112
|
screenWidth?: number;
|
|
113
113
|
screenHeight?: number;
|
|
114
|
+
/** Defaults to `PixelRatio.get()`. Override only if you report a custom screen size. */
|
|
115
|
+
devicePixelRatio?: number;
|
|
116
|
+
/** Defaults to `Platform.Version`. Compared on the major component only. */
|
|
117
|
+
osVersion?: string;
|
|
114
118
|
}
|
|
115
119
|
/** In-app message from the API */
|
|
116
120
|
interface Message {
|
|
@@ -146,6 +150,78 @@ interface ShowMessageOptions {
|
|
|
146
150
|
onDismiss?: (messageId: string) => void;
|
|
147
151
|
onButtonPress?: (action: string, messageId: string) => void;
|
|
148
152
|
}
|
|
153
|
+
interface EcommerceItem {
|
|
154
|
+
item_id: string;
|
|
155
|
+
item_name?: string;
|
|
156
|
+
item_category?: string;
|
|
157
|
+
item_brand?: string;
|
|
158
|
+
item_variant?: string;
|
|
159
|
+
item_list_name?: string;
|
|
160
|
+
item_list_id?: string;
|
|
161
|
+
item_image_url?: string;
|
|
162
|
+
price?: number;
|
|
163
|
+
quantity?: number;
|
|
164
|
+
currency?: string;
|
|
165
|
+
coupon_code?: string;
|
|
166
|
+
discount?: number;
|
|
167
|
+
}
|
|
168
|
+
interface PurchaseParams {
|
|
169
|
+
transaction_id: string;
|
|
170
|
+
revenue: number;
|
|
171
|
+
currency: string;
|
|
172
|
+
items?: EcommerceItem[];
|
|
173
|
+
cart_id?: string;
|
|
174
|
+
coupon_code?: string;
|
|
175
|
+
discount?: number;
|
|
176
|
+
shipping?: number;
|
|
177
|
+
tax?: number;
|
|
178
|
+
}
|
|
179
|
+
interface AddToCartParams {
|
|
180
|
+
items: EcommerceItem[];
|
|
181
|
+
cart_id?: string;
|
|
182
|
+
}
|
|
183
|
+
interface RemoveFromCartParams {
|
|
184
|
+
items: EcommerceItem[];
|
|
185
|
+
cart_id?: string;
|
|
186
|
+
}
|
|
187
|
+
interface AddToWishlistParams {
|
|
188
|
+
items: EcommerceItem[];
|
|
189
|
+
}
|
|
190
|
+
interface BeginCheckoutParams {
|
|
191
|
+
revenue?: number;
|
|
192
|
+
currency?: string;
|
|
193
|
+
cart_id?: string;
|
|
194
|
+
items?: EcommerceItem[];
|
|
195
|
+
}
|
|
196
|
+
interface RefundParams {
|
|
197
|
+
transaction_id: string;
|
|
198
|
+
revenue: number;
|
|
199
|
+
currency?: string;
|
|
200
|
+
items?: EcommerceItem[];
|
|
201
|
+
}
|
|
202
|
+
interface ViewItemParams {
|
|
203
|
+
items: EcommerceItem[];
|
|
204
|
+
}
|
|
205
|
+
interface SearchParams {
|
|
206
|
+
search_term: string;
|
|
207
|
+
}
|
|
208
|
+
interface AddPaymentInfoParams {
|
|
209
|
+
cart_id?: string;
|
|
210
|
+
}
|
|
211
|
+
interface ShareParams {
|
|
212
|
+
item_id?: string;
|
|
213
|
+
url?: string;
|
|
214
|
+
method?: string;
|
|
215
|
+
}
|
|
216
|
+
interface RateParams {
|
|
217
|
+
item_id: string;
|
|
218
|
+
rating: number;
|
|
219
|
+
max_rating?: number;
|
|
220
|
+
}
|
|
221
|
+
interface SpendCreditsParams {
|
|
222
|
+
revenue: number;
|
|
223
|
+
currency: string;
|
|
224
|
+
}
|
|
149
225
|
|
|
150
226
|
declare class HttpClient {
|
|
151
227
|
private baseUrl;
|
|
@@ -185,6 +261,41 @@ declare class TolinkuError extends Error {
|
|
|
185
261
|
constructor(message: string, status: number, code?: string);
|
|
186
262
|
}
|
|
187
263
|
|
|
264
|
+
declare class Ecommerce {
|
|
265
|
+
private client;
|
|
266
|
+
private queue;
|
|
267
|
+
private flushTimer;
|
|
268
|
+
private appStateSubscription;
|
|
269
|
+
private isFlushing;
|
|
270
|
+
private getUserId;
|
|
271
|
+
private memoryCartId;
|
|
272
|
+
constructor(client: HttpClient, getUserId: () => string | null);
|
|
273
|
+
viewItem(params: ViewItemParams): Promise<void>;
|
|
274
|
+
addToCart(params: AddToCartParams): Promise<void>;
|
|
275
|
+
removeFromCart(params: RemoveFromCartParams): Promise<void>;
|
|
276
|
+
addToWishlist(params: AddToWishlistParams): Promise<void>;
|
|
277
|
+
viewCart(): Promise<void>;
|
|
278
|
+
addPaymentInfo(params?: AddPaymentInfoParams): Promise<void>;
|
|
279
|
+
beginCheckout(params: BeginCheckoutParams): Promise<void>;
|
|
280
|
+
purchase(params: PurchaseParams): Promise<void>;
|
|
281
|
+
refund(params: RefundParams): Promise<void>;
|
|
282
|
+
search(params: SearchParams): Promise<void>;
|
|
283
|
+
share(params: ShareParams): Promise<void>;
|
|
284
|
+
rate(params: RateParams): Promise<void>;
|
|
285
|
+
spendCredits(params: SpendCreditsParams): Promise<void>;
|
|
286
|
+
flush(): Promise<void>;
|
|
287
|
+
destroy(): Promise<void>;
|
|
288
|
+
private enqueue;
|
|
289
|
+
private handleAppStateChange;
|
|
290
|
+
private startFlushTimer;
|
|
291
|
+
private cancelFlushTimer;
|
|
292
|
+
private getOrCreateCartId;
|
|
293
|
+
private getCartId;
|
|
294
|
+
private setCartId;
|
|
295
|
+
private clearCartId;
|
|
296
|
+
private generateId;
|
|
297
|
+
}
|
|
298
|
+
|
|
188
299
|
declare class Referrals {
|
|
189
300
|
private client;
|
|
190
301
|
constructor(client: HttpClient);
|
|
@@ -230,6 +341,7 @@ declare class Tolinku {
|
|
|
230
341
|
static readonly VERSION = "0.1.0";
|
|
231
342
|
private static client;
|
|
232
343
|
private static analyticsInstance;
|
|
344
|
+
private static ecommerceInstance;
|
|
233
345
|
private static referralsInstance;
|
|
234
346
|
private static deferredInstance;
|
|
235
347
|
private static _initialized;
|
|
@@ -259,9 +371,11 @@ declare class Tolinku {
|
|
|
259
371
|
*/
|
|
260
372
|
static track(eventType: string, properties?: TrackProperties): Promise<void>;
|
|
261
373
|
/**
|
|
262
|
-
* Immediately flush all queued analytics events to the server.
|
|
374
|
+
* Immediately flush all queued analytics and ecommerce events to the server.
|
|
263
375
|
*/
|
|
264
376
|
static flush(): Promise<void>;
|
|
377
|
+
/** Ecommerce: track purchases, carts, products, revenue */
|
|
378
|
+
static get ecommerce(): Ecommerce;
|
|
265
379
|
/** Referrals: create, complete, milestone, leaderboard, claimReward */
|
|
266
380
|
static get referrals(): Referrals;
|
|
267
381
|
/** Deferred deep links: claimByToken, claimBySignals */
|
|
@@ -303,4 +417,4 @@ declare function TolinkuMessages({ trigger, triggerValue, onDismiss, onButtonPre
|
|
|
303
417
|
*/
|
|
304
418
|
declare function isSafeUrl(url: string): boolean;
|
|
305
419
|
|
|
306
|
-
export { type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type ReferralInfo, type ResolvedTolinkuConfig, type ShowMessageOptions, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, isSafeUrl };
|
|
420
|
+
export { type AddPaymentInfoParams, type AddToCartParams, type AddToWishlistParams, type BeginCheckoutParams, type ClaimBySignalsOptions, type CompleteReferralOptions, type CompleteReferralResult, type CreateReferralOptions, type CreateReferralResult, type DeferredLink, type EcommerceItem, type LeaderboardEntry, type Message, type MessageComponent, type MessageContent, type MilestoneOptions, type MilestoneResult, type PurchaseParams, type RateParams, type ReferralInfo, type RefundParams, type RemoveFromCartParams, type ResolvedTolinkuConfig, type SearchParams, type ShareParams, type ShowMessageOptions, type SpendCreditsParams, Tolinku, type TolinkuConfig, TolinkuError, TolinkuMessages, type TrackProperties, type ViewItemParams, isSafeUrl };
|
package/dist/index.js
CHANGED
|
@@ -353,6 +353,215 @@ var Analytics = class {
|
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
};
|
|
356
|
+
var BATCH_SIZE2 = 10;
|
|
357
|
+
var FLUSH_INTERVAL_MS2 = 5e3;
|
|
358
|
+
var MAX_QUEUE_SIZE2 = 500;
|
|
359
|
+
var CART_ID_STORAGE_KEY = "tolinku_ecom_cart_id";
|
|
360
|
+
var Ecommerce = class {
|
|
361
|
+
constructor(client, getUserId) {
|
|
362
|
+
this.queue = [];
|
|
363
|
+
this.flushTimer = null;
|
|
364
|
+
this.appStateSubscription = null;
|
|
365
|
+
this.isFlushing = false;
|
|
366
|
+
this.memoryCartId = null;
|
|
367
|
+
this.handleAppStateChange = (state) => {
|
|
368
|
+
if (state === "background" || state === "inactive") {
|
|
369
|
+
this.flush().catch(() => {
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
this.client = client;
|
|
374
|
+
this.getUserId = getUserId;
|
|
375
|
+
this.appStateSubscription = reactNative.AppState.addEventListener(
|
|
376
|
+
"change",
|
|
377
|
+
this.handleAppStateChange
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
// ─── Public methods (13 event types) ────────────────────
|
|
381
|
+
async viewItem(params) {
|
|
382
|
+
await this.enqueue({ event_type: "view_item", items: params.items });
|
|
383
|
+
}
|
|
384
|
+
async addToCart(params) {
|
|
385
|
+
const cartId = params.cart_id || await this.getOrCreateCartId();
|
|
386
|
+
await this.enqueue({ event_type: "add_to_cart", items: params.items, cart_id: cartId });
|
|
387
|
+
}
|
|
388
|
+
async removeFromCart(params) {
|
|
389
|
+
const cartId = params.cart_id || await this.getCartId();
|
|
390
|
+
await this.enqueue({ event_type: "remove_from_cart", items: params.items, cart_id: cartId });
|
|
391
|
+
}
|
|
392
|
+
async addToWishlist(params) {
|
|
393
|
+
await this.enqueue({ event_type: "add_to_wishlist", items: params.items });
|
|
394
|
+
}
|
|
395
|
+
async viewCart() {
|
|
396
|
+
const cartId = await this.getCartId();
|
|
397
|
+
await this.enqueue({ event_type: "view_cart", cart_id: cartId });
|
|
398
|
+
}
|
|
399
|
+
async addPaymentInfo(params) {
|
|
400
|
+
const cartId = params?.cart_id || await this.getCartId();
|
|
401
|
+
await this.enqueue({ event_type: "add_payment_info", cart_id: cartId });
|
|
402
|
+
}
|
|
403
|
+
async beginCheckout(params) {
|
|
404
|
+
const cartId = params.cart_id || await this.getCartId();
|
|
405
|
+
await this.enqueue({
|
|
406
|
+
event_type: "begin_checkout",
|
|
407
|
+
revenue: params.revenue,
|
|
408
|
+
currency: params.currency,
|
|
409
|
+
cart_id: cartId,
|
|
410
|
+
items: params.items
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
async purchase(params) {
|
|
414
|
+
const cartId = params.cart_id || await this.getCartId();
|
|
415
|
+
await this.enqueue({
|
|
416
|
+
event_type: "purchase",
|
|
417
|
+
transaction_id: params.transaction_id,
|
|
418
|
+
revenue: params.revenue,
|
|
419
|
+
currency: params.currency,
|
|
420
|
+
cart_id: cartId,
|
|
421
|
+
coupon_code: params.coupon_code,
|
|
422
|
+
discount: params.discount,
|
|
423
|
+
shipping: params.shipping,
|
|
424
|
+
tax: params.tax,
|
|
425
|
+
items: params.items
|
|
426
|
+
});
|
|
427
|
+
await this.clearCartId();
|
|
428
|
+
}
|
|
429
|
+
async refund(params) {
|
|
430
|
+
await this.enqueue({
|
|
431
|
+
event_type: "refund",
|
|
432
|
+
transaction_id: params.transaction_id,
|
|
433
|
+
revenue: params.revenue,
|
|
434
|
+
currency: params.currency,
|
|
435
|
+
items: params.items
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
async search(params) {
|
|
439
|
+
await this.enqueue({ event_type: "search", properties: { search_term: params.search_term } });
|
|
440
|
+
}
|
|
441
|
+
async share(params) {
|
|
442
|
+
const props = {};
|
|
443
|
+
if (params.item_id) props.item_id = params.item_id;
|
|
444
|
+
if (params.url) props.url = params.url;
|
|
445
|
+
if (params.method) props.method = params.method;
|
|
446
|
+
await this.enqueue({ event_type: "share", properties: props });
|
|
447
|
+
}
|
|
448
|
+
async rate(params) {
|
|
449
|
+
await this.enqueue({
|
|
450
|
+
event_type: "rate",
|
|
451
|
+
properties: {
|
|
452
|
+
item_id: params.item_id,
|
|
453
|
+
rating: String(params.rating),
|
|
454
|
+
...params.max_rating != null ? { max_rating: String(params.max_rating) } : {}
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
async spendCredits(params) {
|
|
459
|
+
await this.enqueue({ event_type: "spend_credits", revenue: params.revenue, currency: params.currency });
|
|
460
|
+
}
|
|
461
|
+
// ─── Flush ─────────────────────────────────────────────
|
|
462
|
+
async flush() {
|
|
463
|
+
if (this.queue.length === 0 || this.isFlushing) return;
|
|
464
|
+
this.isFlushing = true;
|
|
465
|
+
const events = this.queue.splice(0);
|
|
466
|
+
this.cancelFlushTimer();
|
|
467
|
+
try {
|
|
468
|
+
debugLog(`Flushing ${events.length} ecommerce event(s)`);
|
|
469
|
+
const result = await this.client.post(
|
|
470
|
+
"/v1/api/analytics/ecommerce/batch",
|
|
471
|
+
{ events }
|
|
472
|
+
);
|
|
473
|
+
if (result.errors && result.errors.length > 0) {
|
|
474
|
+
debugWarn(`Ecommerce batch partial failure: ${result.errors.join(", ")}`);
|
|
475
|
+
}
|
|
476
|
+
} catch (err) {
|
|
477
|
+
debugWarn(`Failed to flush ecommerce events: ${err.message}`);
|
|
478
|
+
const spaceLeft = MAX_QUEUE_SIZE2 - this.queue.length;
|
|
479
|
+
if (spaceLeft > 0) {
|
|
480
|
+
this.queue.unshift(...events.slice(0, spaceLeft));
|
|
481
|
+
}
|
|
482
|
+
} finally {
|
|
483
|
+
this.isFlushing = false;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
async destroy() {
|
|
487
|
+
this.cancelFlushTimer();
|
|
488
|
+
this.appStateSubscription?.remove();
|
|
489
|
+
this.appStateSubscription = null;
|
|
490
|
+
try {
|
|
491
|
+
await this.flush();
|
|
492
|
+
} catch {
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// ─── Private ───────────────────────────────────────────
|
|
496
|
+
async enqueue(event) {
|
|
497
|
+
const userId = this.getUserId();
|
|
498
|
+
if (userId) event.user_id = userId;
|
|
499
|
+
if (this.queue.length >= MAX_QUEUE_SIZE2) {
|
|
500
|
+
debugWarn(`Ecommerce queue full (${MAX_QUEUE_SIZE2}). Dropping oldest event.`);
|
|
501
|
+
this.queue.shift();
|
|
502
|
+
}
|
|
503
|
+
this.queue.push(event);
|
|
504
|
+
if (this.queue.length >= BATCH_SIZE2) {
|
|
505
|
+
await this.flush();
|
|
506
|
+
} else if (this.queue.length === 1) {
|
|
507
|
+
this.startFlushTimer();
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
startFlushTimer() {
|
|
511
|
+
this.cancelFlushTimer();
|
|
512
|
+
this.flushTimer = setTimeout(() => {
|
|
513
|
+
this.flush().catch((err) => {
|
|
514
|
+
debugWarn(`Ecommerce timer flush failed: ${err.message}`);
|
|
515
|
+
});
|
|
516
|
+
}, FLUSH_INTERVAL_MS2);
|
|
517
|
+
}
|
|
518
|
+
cancelFlushTimer() {
|
|
519
|
+
if (this.flushTimer !== null) {
|
|
520
|
+
clearTimeout(this.flushTimer);
|
|
521
|
+
this.flushTimer = null;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
// ─── Cart ID lifecycle (AsyncStorage + memory fallback) ─
|
|
525
|
+
async getOrCreateCartId() {
|
|
526
|
+
const existing = await this.getCartId();
|
|
527
|
+
if (existing) return existing;
|
|
528
|
+
const cartId = this.generateId();
|
|
529
|
+
await this.setCartId(cartId);
|
|
530
|
+
return cartId;
|
|
531
|
+
}
|
|
532
|
+
async getCartId() {
|
|
533
|
+
try {
|
|
534
|
+
const stored = await AsyncStorage__default.default.getItem(CART_ID_STORAGE_KEY);
|
|
535
|
+
if (stored) return stored;
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
return this.memoryCartId || void 0;
|
|
539
|
+
}
|
|
540
|
+
async setCartId(cartId) {
|
|
541
|
+
this.memoryCartId = cartId;
|
|
542
|
+
try {
|
|
543
|
+
await AsyncStorage__default.default.setItem(CART_ID_STORAGE_KEY, cartId);
|
|
544
|
+
} catch {
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async clearCartId() {
|
|
548
|
+
this.memoryCartId = null;
|
|
549
|
+
try {
|
|
550
|
+
await AsyncStorage__default.default.removeItem(CART_ID_STORAGE_KEY);
|
|
551
|
+
} catch {
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
generateId() {
|
|
555
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
556
|
+
return crypto.randomUUID();
|
|
557
|
+
}
|
|
558
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
559
|
+
const r = Math.random() * 16 | 0;
|
|
560
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
561
|
+
return v.toString(16);
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
};
|
|
356
565
|
|
|
357
566
|
// src/referrals.ts
|
|
358
567
|
var Referrals = class {
|
|
@@ -445,15 +654,29 @@ var Deferred = class {
|
|
|
445
654
|
try {
|
|
446
655
|
const { width, height } = reactNative.Dimensions.get("screen");
|
|
447
656
|
const resolvedTimezone = options.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
448
|
-
const resolvedLanguage = options.language || "en";
|
|
657
|
+
const resolvedLanguage = options.language || (typeof Intl !== "undefined" && typeof Intl.DateTimeFormat === "function" ? Intl.DateTimeFormat().resolvedOptions().locale : void 0) || "en";
|
|
449
658
|
return await this.client.postPublic("/v1/api/deferred/claim-by-signals", {
|
|
450
659
|
appspace_id: options.appspaceId,
|
|
451
660
|
timezone: resolvedTimezone,
|
|
452
661
|
language: resolvedLanguage,
|
|
453
662
|
screen_width: options.screenWidth || width,
|
|
454
|
-
screen_height: options.screenHeight || height
|
|
663
|
+
screen_height: options.screenHeight || height,
|
|
664
|
+
// Separates devices reporting identical dp dimensions.
|
|
665
|
+
device_pixel_ratio: options.devicePixelRatio || reactNative.PixelRatio.get(),
|
|
666
|
+
os_version: options.osVersion || String(reactNative.Platform.Version)
|
|
455
667
|
});
|
|
456
668
|
} catch (err) {
|
|
669
|
+
const status = err?.statusCode ?? err?.status;
|
|
670
|
+
if (status === 404) {
|
|
671
|
+
debugWarn("Deferred claimBySignals: no match for this device.");
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
if (status === 403) {
|
|
675
|
+
console.warn(
|
|
676
|
+
`[Tolinku] claimBySignals failed with HTTP 403. Check that appspaceId is your Appspace ID (copy it from the dashboard under Settings), not your subdomain or slug. ${err.message}`
|
|
677
|
+
);
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
457
680
|
debugWarn(`Deferred claimBySignals failed: ${err.message}`);
|
|
458
681
|
return null;
|
|
459
682
|
}
|
|
@@ -568,6 +791,7 @@ var _Tolinku = class _Tolinku {
|
|
|
568
791
|
setStorageNamespace(config.apiKey);
|
|
569
792
|
_Tolinku.client = new HttpClient(resolvedConfig);
|
|
570
793
|
_Tolinku.analyticsInstance = new Analytics(_Tolinku.client);
|
|
794
|
+
_Tolinku.ecommerceInstance = new Ecommerce(_Tolinku.client, () => _Tolinku._userId);
|
|
571
795
|
_Tolinku.referralsInstance = new Referrals(_Tolinku.client);
|
|
572
796
|
_Tolinku.deferredInstance = new Deferred(_Tolinku.client);
|
|
573
797
|
_Tolinku._initialized = true;
|
|
@@ -608,13 +832,23 @@ var _Tolinku = class _Tolinku {
|
|
|
608
832
|
return _Tolinku.analyticsInstance.track(eventType, mergedProps);
|
|
609
833
|
}
|
|
610
834
|
/**
|
|
611
|
-
* Immediately flush all queued analytics events to the server.
|
|
835
|
+
* Immediately flush all queued analytics and ecommerce events to the server.
|
|
612
836
|
*/
|
|
613
837
|
static async flush() {
|
|
614
838
|
if (!_Tolinku.analyticsInstance) {
|
|
615
839
|
throw new Error("Tolinku: SDK not initialized. Call Tolinku.init() first.");
|
|
616
840
|
}
|
|
617
|
-
|
|
841
|
+
await Promise.all([
|
|
842
|
+
_Tolinku.analyticsInstance.flush(),
|
|
843
|
+
_Tolinku.ecommerceInstance?.flush()
|
|
844
|
+
]);
|
|
845
|
+
}
|
|
846
|
+
/** Ecommerce: track purchases, carts, products, revenue */
|
|
847
|
+
static get ecommerce() {
|
|
848
|
+
if (!_Tolinku.ecommerceInstance) {
|
|
849
|
+
throw new Error("Tolinku: SDK not initialized. Call Tolinku.init() first.");
|
|
850
|
+
}
|
|
851
|
+
return _Tolinku.ecommerceInstance;
|
|
618
852
|
}
|
|
619
853
|
/** Referrals: create, complete, milestone, leaderboard, claimReward */
|
|
620
854
|
static get referrals() {
|
|
@@ -641,12 +875,16 @@ var _Tolinku = class _Tolinku {
|
|
|
641
875
|
if (_Tolinku.analyticsInstance) {
|
|
642
876
|
await _Tolinku.analyticsInstance.destroy();
|
|
643
877
|
}
|
|
878
|
+
if (_Tolinku.ecommerceInstance) {
|
|
879
|
+
await _Tolinku.ecommerceInstance.destroy();
|
|
880
|
+
}
|
|
644
881
|
if (_Tolinku.client) {
|
|
645
882
|
_Tolinku.client.abort();
|
|
646
883
|
}
|
|
647
884
|
resetStorageNamespace();
|
|
648
885
|
_Tolinku.client = null;
|
|
649
886
|
_Tolinku.analyticsInstance = null;
|
|
887
|
+
_Tolinku.ecommerceInstance = null;
|
|
650
888
|
_Tolinku.referralsInstance = null;
|
|
651
889
|
_Tolinku.deferredInstance = null;
|
|
652
890
|
_Tolinku._initialized = false;
|
|
@@ -657,6 +895,7 @@ var _Tolinku = class _Tolinku {
|
|
|
657
895
|
_Tolinku.VERSION = SDK_VERSION;
|
|
658
896
|
_Tolinku.client = null;
|
|
659
897
|
_Tolinku.analyticsInstance = null;
|
|
898
|
+
_Tolinku.ecommerceInstance = null;
|
|
660
899
|
_Tolinku.referralsInstance = null;
|
|
661
900
|
_Tolinku.deferredInstance = null;
|
|
662
901
|
_Tolinku._initialized = false;
|