rampkit-expo-dev 0.0.71 â 0.0.73
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/build/RampKit.js +6 -0
- package/ios/RampKitModule.swift +147 -49
- package/package.json +1 -1
package/build/RampKit.js
CHANGED
|
@@ -297,6 +297,8 @@ class RampKitCore {
|
|
|
297
297
|
var _a;
|
|
298
298
|
// Track onboarding completed - trigger: finished
|
|
299
299
|
EventManager_1.eventManager.trackOnboardingCompleted("finished", screens.length, screens.length, onboardingId);
|
|
300
|
+
// Auto-recheck transactions after onboarding finishes (catches purchases made during onboarding)
|
|
301
|
+
RampKitNative_1.TransactionObserver.recheck().catch(() => { });
|
|
300
302
|
try {
|
|
301
303
|
(_a = this.onOnboardingFinished) === null || _a === void 0 ? void 0 : _a.call(this, payload);
|
|
302
304
|
}
|
|
@@ -306,6 +308,8 @@ class RampKitCore {
|
|
|
306
308
|
// Track onboarding completed - trigger: paywall_shown
|
|
307
309
|
EventManager_1.eventManager.trackOnboardingCompleted("paywall_shown", screens.length, // We don't know exact step, use total
|
|
308
310
|
screens.length, onboardingId);
|
|
311
|
+
// Auto-recheck transactions after paywall shown (catches purchases made during onboarding)
|
|
312
|
+
RampKitNative_1.TransactionObserver.recheck().catch(() => { });
|
|
309
313
|
// Call the original callback
|
|
310
314
|
const paywallCallback = (opts === null || opts === void 0 ? void 0 : opts.onShowPaywall) || (opts === null || opts === void 0 ? void 0 : opts.showPaywall) || this.onShowPaywall;
|
|
311
315
|
try {
|
|
@@ -323,6 +327,8 @@ class RampKitCore {
|
|
|
323
327
|
onCloseAction: (screenIndex, _screenId) => {
|
|
324
328
|
// Track onboarding completed - trigger: closed
|
|
325
329
|
EventManager_1.eventManager.trackOnboardingCompleted("closed", screenIndex + 1, screens.length, onboardingId);
|
|
330
|
+
// Auto-recheck transactions after onboarding closes (catches purchases made before closing)
|
|
331
|
+
RampKitNative_1.TransactionObserver.recheck().catch(() => { });
|
|
326
332
|
},
|
|
327
333
|
});
|
|
328
334
|
}
|
package/ios/RampKitModule.swift
CHANGED
|
@@ -486,10 +486,25 @@ public class RampKitModule: Module {
|
|
|
486
486
|
/// Check all current entitlements and track any we haven't seen before
|
|
487
487
|
/// This catches purchases made by Superwall/RevenueCat before our observer started
|
|
488
488
|
/// Returns a dictionary with the results for JavaScript logging
|
|
489
|
+
///
|
|
490
|
+
/// IMPORTANT: "Already sent" means we previously sent this transaction to the backend
|
|
491
|
+
/// and received a successful HTTP 2xx response. The originalTransactionId is stored
|
|
492
|
+
/// in UserDefaults ONLY after a successful send.
|
|
489
493
|
@available(iOS 15.0, *)
|
|
490
494
|
private func checkAndTrackCurrentEntitlements() async -> [String: Any] {
|
|
491
|
-
print("[RampKit]
|
|
492
|
-
print("[RampKit]
|
|
495
|
+
print("[RampKit] ")
|
|
496
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
497
|
+
print("[RampKit] đ CHECKING ENTITLEMENTS FOR UNSENT PURCHASES")
|
|
498
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
499
|
+
print("[RampKit] ")
|
|
500
|
+
print("[RampKit] đ Tracked transaction IDs in storage: \(trackedTransactionIds.count)")
|
|
501
|
+
if !trackedTransactionIds.isEmpty {
|
|
502
|
+
print("[RampKit] These IDs were SUCCESSFULLY sent to backend (HTTP 2xx):")
|
|
503
|
+
for id in trackedTransactionIds {
|
|
504
|
+
print("[RampKit] - \(id)")
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
print("[RampKit] ")
|
|
493
508
|
|
|
494
509
|
let formatter = ISO8601DateFormatter()
|
|
495
510
|
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
|
@@ -537,25 +552,35 @@ public class RampKitModule: Module {
|
|
|
537
552
|
print("[RampKit] - purchaseDate: \(formatter.string(from: transaction.purchaseDate))")
|
|
538
553
|
|
|
539
554
|
// Check if we've already tracked this transaction
|
|
540
|
-
|
|
555
|
+
// "Tracked" means we successfully sent a purchase_completed event to the backend
|
|
556
|
+
// and received an HTTP 2xx response. We store the transactionId after success.
|
|
557
|
+
// NOTE: We track by transactionId (not originalTransactionId) so renewals are also sent.
|
|
558
|
+
if trackedTransactionIds.contains(transactionId) {
|
|
541
559
|
trackedCount += 1
|
|
542
560
|
txDetails["status"] = "already_sent"
|
|
543
561
|
alreadyTrackedDetails.append(txDetails)
|
|
544
|
-
print("[RampKit]
|
|
562
|
+
print("[RampKit] â
STATUS: ALREADY SENT TO BACKEND")
|
|
563
|
+
print("[RampKit] (transactionId \(transactionId) is in our sent-transactions storage)")
|
|
564
|
+
print("[RampKit] This means we previously sent a purchase_completed event")
|
|
565
|
+
print("[RampKit] and received a successful HTTP 2xx response.")
|
|
566
|
+
print("[RampKit] ")
|
|
545
567
|
continue
|
|
546
568
|
}
|
|
547
569
|
|
|
548
|
-
// Skip renewals
|
|
549
|
-
|
|
550
|
-
transaction.revocationDate == nil else {
|
|
551
|
-
let reason = transaction.revocationDate != nil ? "revoked" : "renewal"
|
|
570
|
+
// Skip revocations only (NOT renewals - we want to track renewals too!)
|
|
571
|
+
if transaction.revocationDate != nil {
|
|
552
572
|
txDetails["status"] = "skipped"
|
|
553
|
-
txDetails["reason"] =
|
|
573
|
+
txDetails["reason"] = "revoked"
|
|
554
574
|
skippedReasons.append(txDetails)
|
|
555
|
-
print("[RampKit] âī¸ STATUS: Skipped (
|
|
575
|
+
print("[RampKit] âī¸ STATUS: Skipped (revoked)")
|
|
556
576
|
continue
|
|
557
577
|
}
|
|
558
578
|
|
|
579
|
+
// Log if this is a renewal
|
|
580
|
+
if transaction.originalID != transaction.id {
|
|
581
|
+
print("[RampKit] âšī¸ This is a RENEWAL (originalID != transactionID)")
|
|
582
|
+
}
|
|
583
|
+
|
|
559
584
|
// NEW transaction we haven't seen!
|
|
560
585
|
newCount += 1
|
|
561
586
|
newProductIds.append(transaction.productID)
|
|
@@ -567,10 +592,10 @@ public class RampKitModule: Module {
|
|
|
567
592
|
|
|
568
593
|
// Only mark as tracked if send succeeded
|
|
569
594
|
if let status = sendResult["status"] as? String, status == "sent" {
|
|
570
|
-
trackedTransactionIds.insert(
|
|
595
|
+
trackedTransactionIds.insert(transactionId)
|
|
571
596
|
saveTrackedTransactions()
|
|
572
597
|
print("[RampKit] â
Event sent successfully! HTTP status: \(sendResult["httpStatus"] ?? "unknown")")
|
|
573
|
-
print("[RampKit] â
Marked
|
|
598
|
+
print("[RampKit] â
Marked transactionId \(transactionId) as tracked")
|
|
574
599
|
} else {
|
|
575
600
|
print("[RampKit] â Send failed: \(sendResult["error"] ?? "unknown error")")
|
|
576
601
|
print("[RampKit] â ī¸ Will retry on next app launch")
|
|
@@ -578,15 +603,19 @@ public class RampKitModule: Module {
|
|
|
578
603
|
}
|
|
579
604
|
|
|
580
605
|
print("[RampKit] ")
|
|
581
|
-
print("[RampKit]
|
|
582
|
-
print("[RampKit]
|
|
583
|
-
print("[RampKit]
|
|
584
|
-
print("[RampKit] Total entitlements found:
|
|
585
|
-
print("[RampKit] Already sent
|
|
586
|
-
print("[RampKit] Skipped (renewal/revoked):
|
|
587
|
-
print("[RampKit] NEW events sent:
|
|
588
|
-
print("[RampKit]
|
|
589
|
-
|
|
606
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
607
|
+
print("[RampKit] đ ENTITLEMENT CHECK SUMMARY")
|
|
608
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
609
|
+
print("[RampKit] Total entitlements found: \(foundCount)")
|
|
610
|
+
print("[RampKit] Already sent (HTTP 2xx): \(trackedCount) (no action needed)")
|
|
611
|
+
print("[RampKit] Skipped (renewal/revoked): \(skippedReasons.count) (backend gets via S2S)")
|
|
612
|
+
print("[RampKit] NEW events sent this session: \(newCount)")
|
|
613
|
+
print("[RampKit] Total tracked IDs in storage: \(trackedTransactionIds.count)")
|
|
614
|
+
if newCount == 0 && foundCount > 0 {
|
|
615
|
+
print("[RampKit] ")
|
|
616
|
+
print("[RampKit] âšī¸ All purchases already sent or skipped - nothing new to send")
|
|
617
|
+
}
|
|
618
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
590
619
|
|
|
591
620
|
return [
|
|
592
621
|
"totalFound": foundCount,
|
|
@@ -620,39 +649,38 @@ public class RampKitModule: Module {
|
|
|
620
649
|
continue
|
|
621
650
|
}
|
|
622
651
|
|
|
652
|
+
let transactionId = String(transaction.id)
|
|
623
653
|
let originalId = String(transaction.originalID)
|
|
624
654
|
|
|
625
|
-
// Skip if already tracked
|
|
626
|
-
if self.trackedTransactionIds.contains(
|
|
627
|
-
print("[RampKit] â Transaction.updates: Already tracked \(transaction.productID)")
|
|
655
|
+
// Skip if already tracked (by transactionId, not originalId - so renewals are tracked)
|
|
656
|
+
if self.trackedTransactionIds.contains(transactionId) {
|
|
657
|
+
print("[RampKit] â Transaction.updates: Already tracked \(transaction.productID) (txId: \(transactionId))")
|
|
628
658
|
await transaction.finish()
|
|
629
659
|
continue
|
|
630
660
|
}
|
|
631
661
|
|
|
632
|
-
// Skip
|
|
633
|
-
if transaction.originalID != transaction.id {
|
|
634
|
-
print("[RampKit] âī¸ Transaction.updates: skipped (renewal) \(transaction.productID)")
|
|
635
|
-
await transaction.finish()
|
|
636
|
-
continue
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
// Skip revocations - backend gets these from S2S notifications
|
|
662
|
+
// Skip revocations only (NOT renewals - we want to track renewals!)
|
|
640
663
|
if transaction.revocationDate != nil {
|
|
641
664
|
print("[RampKit] âī¸ Transaction.updates: skipped (revoked) \(transaction.productID)")
|
|
642
665
|
await transaction.finish()
|
|
643
666
|
continue
|
|
644
667
|
}
|
|
645
668
|
|
|
646
|
-
|
|
669
|
+
// Log if this is a renewal
|
|
670
|
+
if transaction.originalID != transaction.id {
|
|
671
|
+
print("[RampKit] đ Transaction.updates: RENEWAL detected for \(transaction.productID)")
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
print("[RampKit] đ Transaction.updates: NEW transaction \(transaction.productID) (txId: \(transactionId))")
|
|
647
675
|
|
|
648
676
|
// Track it and check result
|
|
649
677
|
let sendResult = await self.handleTransactionWithResult(transaction)
|
|
650
678
|
|
|
651
|
-
// Only mark as tracked if send succeeded
|
|
679
|
+
// Only mark as tracked if send succeeded (use transactionId for renewals support)
|
|
652
680
|
if let status = sendResult["status"] as? String, status == "sent" {
|
|
653
|
-
self.trackedTransactionIds.insert(
|
|
681
|
+
self.trackedTransactionIds.insert(transactionId)
|
|
654
682
|
self.saveTrackedTransactions()
|
|
655
|
-
print("[RampKit] â
Transaction.updates: Sent and tracked \(transaction.productID)")
|
|
683
|
+
print("[RampKit] â
Transaction.updates: Sent and tracked \(transaction.productID) (txId: \(transactionId))")
|
|
656
684
|
} else {
|
|
657
685
|
print("[RampKit] â ī¸ Transaction.updates: Send failed, will retry \(transaction.productID)")
|
|
658
686
|
}
|
|
@@ -914,8 +942,8 @@ public class RampKitModule: Module {
|
|
|
914
942
|
}
|
|
915
943
|
}
|
|
916
944
|
|
|
917
|
-
private func sendPurchaseEvent(appId: String, userId: String, eventName: String, properties: [String: Any]) async {
|
|
918
|
-
let _ = await sendPurchaseEventWithResult(appId: appId, userId: userId, eventName: eventName, properties: properties)
|
|
945
|
+
private func sendPurchaseEvent(appId: String, userId: String, eventName: String, properties: [String: Any], paywallId: String? = nil) async {
|
|
946
|
+
let _ = await sendPurchaseEventWithResult(appId: appId, userId: userId, eventName: eventName, properties: properties, paywallId: paywallId)
|
|
919
947
|
}
|
|
920
948
|
|
|
921
949
|
private struct SendEventResult {
|
|
@@ -924,7 +952,16 @@ public class RampKitModule: Module {
|
|
|
924
952
|
let error: String?
|
|
925
953
|
}
|
|
926
954
|
|
|
927
|
-
private func sendPurchaseEventWithResult(appId: String, userId: String, eventName: String, properties: [String: Any]) async -> SendEventResult {
|
|
955
|
+
private func sendPurchaseEventWithResult(appId: String, userId: String, eventName: String, properties: [String: Any], paywallId: String? = nil) async -> SendEventResult {
|
|
956
|
+
// Build context with optional paywallId for attribution
|
|
957
|
+
var context: [String: Any] = [
|
|
958
|
+
"locale": Locale.current.identifier,
|
|
959
|
+
"regionCode": Locale.current.regionCode as Any
|
|
960
|
+
]
|
|
961
|
+
if let paywallId = paywallId {
|
|
962
|
+
context["paywallId"] = paywallId
|
|
963
|
+
}
|
|
964
|
+
|
|
928
965
|
let event: [String: Any] = [
|
|
929
966
|
"appId": appId,
|
|
930
967
|
"appUserId": userId,
|
|
@@ -937,17 +974,53 @@ public class RampKitModule: Module {
|
|
|
937
974
|
"platformVersion": UIDevice.current.systemVersion,
|
|
938
975
|
"deviceModel": getDeviceModelIdentifier(),
|
|
939
976
|
"sdkVersion": "1.0.0",
|
|
940
|
-
"appVersion": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
|
|
941
|
-
"buildNumber": Bundle.main.infoDictionary?["CFBundleVersion"] as? String
|
|
942
|
-
],
|
|
943
|
-
"context": [
|
|
944
|
-
"locale": Locale.current.identifier,
|
|
945
|
-
"regionCode": Locale.current.regionCode
|
|
977
|
+
"appVersion": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown",
|
|
978
|
+
"buildNumber": Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
|
|
946
979
|
],
|
|
980
|
+
"context": context,
|
|
947
981
|
"properties": properties
|
|
948
982
|
]
|
|
949
983
|
|
|
984
|
+
// DETAILED LOGGING: Log the full request body
|
|
985
|
+
print("[RampKit] ")
|
|
986
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
987
|
+
print("[RampKit] đ¤ SENDING PURCHASE EVENT TO BACKEND")
|
|
988
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
989
|
+
print("[RampKit] URL: https://uustlzuvjmochxkxatfx.supabase.co/functions/v1/app-user-events")
|
|
990
|
+
print("[RampKit] Method: POST")
|
|
991
|
+
print("[RampKit] ")
|
|
992
|
+
print("[RampKit] đ REQUEST BODY:")
|
|
993
|
+
print("[RampKit] appId: \(appId)")
|
|
994
|
+
print("[RampKit] appUserId: \(userId)")
|
|
995
|
+
print("[RampKit] eventName: \(eventName)")
|
|
996
|
+
if let originalTxId = properties["originalTransactionId"] {
|
|
997
|
+
print("[RampKit] properties.originalTransactionId: \(originalTxId) â (CRITICAL for attribution)")
|
|
998
|
+
} else {
|
|
999
|
+
print("[RampKit] â ī¸ WARNING: properties.originalTransactionId is MISSING!")
|
|
1000
|
+
}
|
|
1001
|
+
if let productId = properties["productId"] {
|
|
1002
|
+
print("[RampKit] properties.productId: \(productId)")
|
|
1003
|
+
}
|
|
1004
|
+
if let amount = properties["amount"], let currency = properties["currency"] {
|
|
1005
|
+
print("[RampKit] properties.amount: \(amount) \(currency)")
|
|
1006
|
+
}
|
|
1007
|
+
if let paywallId = paywallId {
|
|
1008
|
+
print("[RampKit] context.paywallId: \(paywallId) â")
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Log full JSON for debugging
|
|
1012
|
+
if let jsonData = try? JSONSerialization.data(withJSONObject: event, options: .prettyPrinted),
|
|
1013
|
+
let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
1014
|
+
print("[RampKit] ")
|
|
1015
|
+
print("[RampKit] đ FULL JSON PAYLOAD:")
|
|
1016
|
+
for line in jsonString.components(separatedBy: "\n") {
|
|
1017
|
+
print("[RampKit] \(line)")
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
1021
|
+
|
|
950
1022
|
guard let url = URL(string: "https://uustlzuvjmochxkxatfx.supabase.co/functions/v1/app-user-events") else {
|
|
1023
|
+
print("[RampKit] â SEND FAILED: Invalid URL")
|
|
951
1024
|
return SendEventResult(success: false, statusCode: 0, error: "Invalid URL")
|
|
952
1025
|
}
|
|
953
1026
|
|
|
@@ -959,15 +1032,40 @@ public class RampKitModule: Module {
|
|
|
959
1032
|
|
|
960
1033
|
do {
|
|
961
1034
|
request.httpBody = try JSONSerialization.data(withJSONObject: event)
|
|
962
|
-
let (
|
|
1035
|
+
let (data, response) = try await URLSession.shared.data(for: request)
|
|
1036
|
+
|
|
963
1037
|
if let httpResponse = response as? HTTPURLResponse {
|
|
964
|
-
print("[RampKit] Purchase event sent: \(eventName) - Status: \(httpResponse.statusCode)")
|
|
965
1038
|
let success = httpResponse.statusCode >= 200 && httpResponse.statusCode < 300
|
|
966
|
-
|
|
1039
|
+
let responseBody = String(data: data, encoding: .utf8) ?? "(empty)"
|
|
1040
|
+
|
|
1041
|
+
// DETAILED LOGGING: Log the response
|
|
1042
|
+
print("[RampKit] ")
|
|
1043
|
+
print("[RampKit] đĨ RESPONSE FROM BACKEND:")
|
|
1044
|
+
print("[RampKit] HTTP Status: \(httpResponse.statusCode)")
|
|
1045
|
+
print("[RampKit] Success: \(success ? "â
YES" : "â NO")")
|
|
1046
|
+
print("[RampKit] Response Body: \(responseBody)")
|
|
1047
|
+
|
|
1048
|
+
if success {
|
|
1049
|
+
print("[RampKit] ")
|
|
1050
|
+
print("[RampKit] â
EVENT SENT SUCCESSFULLY!")
|
|
1051
|
+
print("[RampKit] originalTransactionId \(properties["originalTransactionId"] ?? "unknown") will be marked as SENT")
|
|
1052
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
1053
|
+
} else {
|
|
1054
|
+
print("[RampKit] ")
|
|
1055
|
+
print("[RampKit] â EVENT SEND FAILED!")
|
|
1056
|
+
print("[RampKit] Will retry on next app launch")
|
|
1057
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
return SendEventResult(success: success, statusCode: httpResponse.statusCode, error: success ? nil : "HTTP \(httpResponse.statusCode): \(responseBody)")
|
|
967
1061
|
}
|
|
1062
|
+
print("[RampKit] â SEND FAILED: No HTTP response")
|
|
968
1063
|
return SendEventResult(success: false, statusCode: 0, error: "No HTTP response")
|
|
969
1064
|
} catch {
|
|
970
|
-
print("[RampKit]
|
|
1065
|
+
print("[RampKit] ")
|
|
1066
|
+
print("[RampKit] â SEND FAILED: Network error")
|
|
1067
|
+
print("[RampKit] Error: \(error.localizedDescription)")
|
|
1068
|
+
print("[RampKit] ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")
|
|
971
1069
|
return SendEventResult(success: false, statusCode: 0, error: error.localizedDescription)
|
|
972
1070
|
}
|
|
973
1071
|
}
|
package/package.json
CHANGED