@tolinku/react-native-sdk 0.1.0 → 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.
- package/README.md +45 -0
- package/dist/index.d.mts +112 -2
- package/dist/index.d.ts +112 -2
- package/dist/index.js +227 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +227 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -347,6 +347,215 @@ var Analytics = class {
|
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
349
|
};
|
|
350
|
+
var BATCH_SIZE2 = 10;
|
|
351
|
+
var FLUSH_INTERVAL_MS2 = 5e3;
|
|
352
|
+
var MAX_QUEUE_SIZE2 = 500;
|
|
353
|
+
var CART_ID_STORAGE_KEY = "tolinku_ecom_cart_id";
|
|
354
|
+
var Ecommerce = class {
|
|
355
|
+
constructor(client, getUserId) {
|
|
356
|
+
this.queue = [];
|
|
357
|
+
this.flushTimer = null;
|
|
358
|
+
this.appStateSubscription = null;
|
|
359
|
+
this.isFlushing = false;
|
|
360
|
+
this.memoryCartId = null;
|
|
361
|
+
this.handleAppStateChange = (state) => {
|
|
362
|
+
if (state === "background" || state === "inactive") {
|
|
363
|
+
this.flush().catch(() => {
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
this.client = client;
|
|
368
|
+
this.getUserId = getUserId;
|
|
369
|
+
this.appStateSubscription = AppState.addEventListener(
|
|
370
|
+
"change",
|
|
371
|
+
this.handleAppStateChange
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
// ─── Public methods (13 event types) ────────────────────
|
|
375
|
+
async viewItem(params) {
|
|
376
|
+
await this.enqueue({ event_type: "view_item", items: params.items });
|
|
377
|
+
}
|
|
378
|
+
async addToCart(params) {
|
|
379
|
+
const cartId = params.cart_id || await this.getOrCreateCartId();
|
|
380
|
+
await this.enqueue({ event_type: "add_to_cart", items: params.items, cart_id: cartId });
|
|
381
|
+
}
|
|
382
|
+
async removeFromCart(params) {
|
|
383
|
+
const cartId = params.cart_id || await this.getCartId();
|
|
384
|
+
await this.enqueue({ event_type: "remove_from_cart", items: params.items, cart_id: cartId });
|
|
385
|
+
}
|
|
386
|
+
async addToWishlist(params) {
|
|
387
|
+
await this.enqueue({ event_type: "add_to_wishlist", items: params.items });
|
|
388
|
+
}
|
|
389
|
+
async viewCart() {
|
|
390
|
+
const cartId = await this.getCartId();
|
|
391
|
+
await this.enqueue({ event_type: "view_cart", cart_id: cartId });
|
|
392
|
+
}
|
|
393
|
+
async addPaymentInfo(params) {
|
|
394
|
+
const cartId = params?.cart_id || await this.getCartId();
|
|
395
|
+
await this.enqueue({ event_type: "add_payment_info", cart_id: cartId });
|
|
396
|
+
}
|
|
397
|
+
async beginCheckout(params) {
|
|
398
|
+
const cartId = params.cart_id || await this.getCartId();
|
|
399
|
+
await this.enqueue({
|
|
400
|
+
event_type: "begin_checkout",
|
|
401
|
+
revenue: params.revenue,
|
|
402
|
+
currency: params.currency,
|
|
403
|
+
cart_id: cartId,
|
|
404
|
+
items: params.items
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
async purchase(params) {
|
|
408
|
+
const cartId = params.cart_id || await this.getCartId();
|
|
409
|
+
await this.enqueue({
|
|
410
|
+
event_type: "purchase",
|
|
411
|
+
transaction_id: params.transaction_id,
|
|
412
|
+
revenue: params.revenue,
|
|
413
|
+
currency: params.currency,
|
|
414
|
+
cart_id: cartId,
|
|
415
|
+
coupon_code: params.coupon_code,
|
|
416
|
+
discount: params.discount,
|
|
417
|
+
shipping: params.shipping,
|
|
418
|
+
tax: params.tax,
|
|
419
|
+
items: params.items
|
|
420
|
+
});
|
|
421
|
+
await this.clearCartId();
|
|
422
|
+
}
|
|
423
|
+
async refund(params) {
|
|
424
|
+
await this.enqueue({
|
|
425
|
+
event_type: "refund",
|
|
426
|
+
transaction_id: params.transaction_id,
|
|
427
|
+
revenue: params.revenue,
|
|
428
|
+
currency: params.currency,
|
|
429
|
+
items: params.items
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
async search(params) {
|
|
433
|
+
await this.enqueue({ event_type: "search", properties: { search_term: params.search_term } });
|
|
434
|
+
}
|
|
435
|
+
async share(params) {
|
|
436
|
+
const props = {};
|
|
437
|
+
if (params.item_id) props.item_id = params.item_id;
|
|
438
|
+
if (params.url) props.url = params.url;
|
|
439
|
+
if (params.method) props.method = params.method;
|
|
440
|
+
await this.enqueue({ event_type: "share", properties: props });
|
|
441
|
+
}
|
|
442
|
+
async rate(params) {
|
|
443
|
+
await this.enqueue({
|
|
444
|
+
event_type: "rate",
|
|
445
|
+
properties: {
|
|
446
|
+
item_id: params.item_id,
|
|
447
|
+
rating: String(params.rating),
|
|
448
|
+
...params.max_rating != null ? { max_rating: String(params.max_rating) } : {}
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
async spendCredits(params) {
|
|
453
|
+
await this.enqueue({ event_type: "spend_credits", revenue: params.revenue, currency: params.currency });
|
|
454
|
+
}
|
|
455
|
+
// ─── Flush ─────────────────────────────────────────────
|
|
456
|
+
async flush() {
|
|
457
|
+
if (this.queue.length === 0 || this.isFlushing) return;
|
|
458
|
+
this.isFlushing = true;
|
|
459
|
+
const events = this.queue.splice(0);
|
|
460
|
+
this.cancelFlushTimer();
|
|
461
|
+
try {
|
|
462
|
+
debugLog(`Flushing ${events.length} ecommerce event(s)`);
|
|
463
|
+
const result = await this.client.post(
|
|
464
|
+
"/v1/api/analytics/ecommerce/batch",
|
|
465
|
+
{ events }
|
|
466
|
+
);
|
|
467
|
+
if (result.errors && result.errors.length > 0) {
|
|
468
|
+
debugWarn(`Ecommerce batch partial failure: ${result.errors.join(", ")}`);
|
|
469
|
+
}
|
|
470
|
+
} catch (err) {
|
|
471
|
+
debugWarn(`Failed to flush ecommerce events: ${err.message}`);
|
|
472
|
+
const spaceLeft = MAX_QUEUE_SIZE2 - this.queue.length;
|
|
473
|
+
if (spaceLeft > 0) {
|
|
474
|
+
this.queue.unshift(...events.slice(0, spaceLeft));
|
|
475
|
+
}
|
|
476
|
+
} finally {
|
|
477
|
+
this.isFlushing = false;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async destroy() {
|
|
481
|
+
this.cancelFlushTimer();
|
|
482
|
+
this.appStateSubscription?.remove();
|
|
483
|
+
this.appStateSubscription = null;
|
|
484
|
+
try {
|
|
485
|
+
await this.flush();
|
|
486
|
+
} catch {
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// ─── Private ───────────────────────────────────────────
|
|
490
|
+
async enqueue(event) {
|
|
491
|
+
const userId = this.getUserId();
|
|
492
|
+
if (userId) event.user_id = userId;
|
|
493
|
+
if (this.queue.length >= MAX_QUEUE_SIZE2) {
|
|
494
|
+
debugWarn(`Ecommerce queue full (${MAX_QUEUE_SIZE2}). Dropping oldest event.`);
|
|
495
|
+
this.queue.shift();
|
|
496
|
+
}
|
|
497
|
+
this.queue.push(event);
|
|
498
|
+
if (this.queue.length >= BATCH_SIZE2) {
|
|
499
|
+
await this.flush();
|
|
500
|
+
} else if (this.queue.length === 1) {
|
|
501
|
+
this.startFlushTimer();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
startFlushTimer() {
|
|
505
|
+
this.cancelFlushTimer();
|
|
506
|
+
this.flushTimer = setTimeout(() => {
|
|
507
|
+
this.flush().catch((err) => {
|
|
508
|
+
debugWarn(`Ecommerce timer flush failed: ${err.message}`);
|
|
509
|
+
});
|
|
510
|
+
}, FLUSH_INTERVAL_MS2);
|
|
511
|
+
}
|
|
512
|
+
cancelFlushTimer() {
|
|
513
|
+
if (this.flushTimer !== null) {
|
|
514
|
+
clearTimeout(this.flushTimer);
|
|
515
|
+
this.flushTimer = null;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// ─── Cart ID lifecycle (AsyncStorage + memory fallback) ─
|
|
519
|
+
async getOrCreateCartId() {
|
|
520
|
+
const existing = await this.getCartId();
|
|
521
|
+
if (existing) return existing;
|
|
522
|
+
const cartId = this.generateId();
|
|
523
|
+
await this.setCartId(cartId);
|
|
524
|
+
return cartId;
|
|
525
|
+
}
|
|
526
|
+
async getCartId() {
|
|
527
|
+
try {
|
|
528
|
+
const stored = await AsyncStorage.getItem(CART_ID_STORAGE_KEY);
|
|
529
|
+
if (stored) return stored;
|
|
530
|
+
} catch {
|
|
531
|
+
}
|
|
532
|
+
return this.memoryCartId || void 0;
|
|
533
|
+
}
|
|
534
|
+
async setCartId(cartId) {
|
|
535
|
+
this.memoryCartId = cartId;
|
|
536
|
+
try {
|
|
537
|
+
await AsyncStorage.setItem(CART_ID_STORAGE_KEY, cartId);
|
|
538
|
+
} catch {
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
async clearCartId() {
|
|
542
|
+
this.memoryCartId = null;
|
|
543
|
+
try {
|
|
544
|
+
await AsyncStorage.removeItem(CART_ID_STORAGE_KEY);
|
|
545
|
+
} catch {
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
generateId() {
|
|
549
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
550
|
+
return crypto.randomUUID();
|
|
551
|
+
}
|
|
552
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
553
|
+
const r = Math.random() * 16 | 0;
|
|
554
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
555
|
+
return v.toString(16);
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
};
|
|
350
559
|
|
|
351
560
|
// src/referrals.ts
|
|
352
561
|
var Referrals = class {
|
|
@@ -562,6 +771,7 @@ var _Tolinku = class _Tolinku {
|
|
|
562
771
|
setStorageNamespace(config.apiKey);
|
|
563
772
|
_Tolinku.client = new HttpClient(resolvedConfig);
|
|
564
773
|
_Tolinku.analyticsInstance = new Analytics(_Tolinku.client);
|
|
774
|
+
_Tolinku.ecommerceInstance = new Ecommerce(_Tolinku.client, () => _Tolinku._userId);
|
|
565
775
|
_Tolinku.referralsInstance = new Referrals(_Tolinku.client);
|
|
566
776
|
_Tolinku.deferredInstance = new Deferred(_Tolinku.client);
|
|
567
777
|
_Tolinku._initialized = true;
|
|
@@ -602,13 +812,23 @@ var _Tolinku = class _Tolinku {
|
|
|
602
812
|
return _Tolinku.analyticsInstance.track(eventType, mergedProps);
|
|
603
813
|
}
|
|
604
814
|
/**
|
|
605
|
-
* Immediately flush all queued analytics events to the server.
|
|
815
|
+
* Immediately flush all queued analytics and ecommerce events to the server.
|
|
606
816
|
*/
|
|
607
817
|
static async flush() {
|
|
608
818
|
if (!_Tolinku.analyticsInstance) {
|
|
609
819
|
throw new Error("Tolinku: SDK not initialized. Call Tolinku.init() first.");
|
|
610
820
|
}
|
|
611
|
-
|
|
821
|
+
await Promise.all([
|
|
822
|
+
_Tolinku.analyticsInstance.flush(),
|
|
823
|
+
_Tolinku.ecommerceInstance?.flush()
|
|
824
|
+
]);
|
|
825
|
+
}
|
|
826
|
+
/** Ecommerce: track purchases, carts, products, revenue */
|
|
827
|
+
static get ecommerce() {
|
|
828
|
+
if (!_Tolinku.ecommerceInstance) {
|
|
829
|
+
throw new Error("Tolinku: SDK not initialized. Call Tolinku.init() first.");
|
|
830
|
+
}
|
|
831
|
+
return _Tolinku.ecommerceInstance;
|
|
612
832
|
}
|
|
613
833
|
/** Referrals: create, complete, milestone, leaderboard, claimReward */
|
|
614
834
|
static get referrals() {
|
|
@@ -635,12 +855,16 @@ var _Tolinku = class _Tolinku {
|
|
|
635
855
|
if (_Tolinku.analyticsInstance) {
|
|
636
856
|
await _Tolinku.analyticsInstance.destroy();
|
|
637
857
|
}
|
|
858
|
+
if (_Tolinku.ecommerceInstance) {
|
|
859
|
+
await _Tolinku.ecommerceInstance.destroy();
|
|
860
|
+
}
|
|
638
861
|
if (_Tolinku.client) {
|
|
639
862
|
_Tolinku.client.abort();
|
|
640
863
|
}
|
|
641
864
|
resetStorageNamespace();
|
|
642
865
|
_Tolinku.client = null;
|
|
643
866
|
_Tolinku.analyticsInstance = null;
|
|
867
|
+
_Tolinku.ecommerceInstance = null;
|
|
644
868
|
_Tolinku.referralsInstance = null;
|
|
645
869
|
_Tolinku.deferredInstance = null;
|
|
646
870
|
_Tolinku._initialized = false;
|
|
@@ -651,6 +875,7 @@ var _Tolinku = class _Tolinku {
|
|
|
651
875
|
_Tolinku.VERSION = SDK_VERSION;
|
|
652
876
|
_Tolinku.client = null;
|
|
653
877
|
_Tolinku.analyticsInstance = null;
|
|
878
|
+
_Tolinku.ecommerceInstance = null;
|
|
654
879
|
_Tolinku.referralsInstance = null;
|
|
655
880
|
_Tolinku.deferredInstance = null;
|
|
656
881
|
_Tolinku._initialized = false;
|