rampkit-expo-dev 0.0.70 → 0.0.72

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 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
  }
@@ -323,6 +325,8 @@ class RampKitCore {
323
325
  onCloseAction: (screenIndex, _screenId) => {
324
326
  // Track onboarding completed - trigger: closed
325
327
  EventManager_1.eventManager.trackOnboardingCompleted("closed", screenIndex + 1, screens.length, onboardingId);
328
+ // Auto-recheck transactions after onboarding closes (catches purchases made before closing)
329
+ RampKitNative_1.TransactionObserver.recheck().catch(() => { });
326
330
  },
327
331
  });
328
332
  }
@@ -19,6 +19,7 @@ interface RampKitNativeModule {
19
19
  startTransactionObserver(appId: string): Promise<TransactionObserverResult>;
20
20
  stopTransactionObserver(): Promise<void>;
21
21
  clearTrackedTransactions(): Promise<number>;
22
+ recheckEntitlements(): Promise<EntitlementCheckResult>;
22
23
  trackPurchaseCompleted(productId: string, transactionId?: string, originalTransactionId?: string): Promise<void>;
23
24
  trackPurchaseFromProduct(productId: string): Promise<void>;
24
25
  }
@@ -100,6 +101,28 @@ export interface SentEventResult {
100
101
  currency?: string;
101
102
  environment?: string;
102
103
  }
104
+ export interface TrackedTransactionDetail {
105
+ productId: string;
106
+ transactionId: string;
107
+ originalTransactionId: string;
108
+ purchaseDate: string;
109
+ expirationDate?: string;
110
+ environment?: string;
111
+ status: "already_sent" | "skipped";
112
+ reason?: string;
113
+ }
114
+ export interface EntitlementCheckResult {
115
+ totalFound: number;
116
+ alreadyTracked: number;
117
+ newPurchases: number;
118
+ productIds: string[];
119
+ newProductIds: string[];
120
+ sentEvents?: SentEventResult[];
121
+ skippedReasons?: TrackedTransactionDetail[];
122
+ alreadyTrackedDetails?: TrackedTransactionDetail[];
123
+ trackedIdsCount: number;
124
+ error?: string;
125
+ }
103
126
  export interface TransactionObserverResult {
104
127
  configured: boolean;
105
128
  appId: string;
@@ -107,18 +130,7 @@ export interface TransactionObserverResult {
107
130
  previouslyTrackedCount: number;
108
131
  iOSVersion: string;
109
132
  listenerStarted: boolean;
110
- entitlementCheck?: {
111
- totalFound: number;
112
- alreadyTracked: number;
113
- newPurchases: number;
114
- productIds: string[];
115
- newProductIds: string[];
116
- sentEvents?: SentEventResult[];
117
- skippedReasons?: Array<{
118
- productId: string;
119
- reason: string;
120
- }>;
121
- };
133
+ entitlementCheck?: EntitlementCheckResult;
122
134
  error?: string;
123
135
  }
124
136
  export type ImpactStyle = "light" | "medium" | "heavy" | "rigid" | "soft";
@@ -224,4 +236,12 @@ export declare const TransactionObserver: {
224
236
  * @returns The number of tracked transactions that were cleared
225
237
  */
226
238
  clearTracked(): Promise<number>;
239
+ /**
240
+ * Re-check current entitlements for any new purchases
241
+ * Call this after onboarding finishes or after a paywall is shown
242
+ * to catch any purchases that may have been made
243
+ *
244
+ * @returns The entitlement check result with details of all transactions
245
+ */
246
+ recheck(): Promise<EntitlementCheckResult | null>;
227
247
  };
@@ -81,6 +81,17 @@ function createFallbackModule() {
81
81
  },
82
82
  async stopTransactionObserver() { },
83
83
  async clearTrackedTransactions() { return 0; },
84
+ async recheckEntitlements() {
85
+ return {
86
+ totalFound: 0,
87
+ alreadyTracked: 0,
88
+ newPurchases: 0,
89
+ productIds: [],
90
+ newProductIds: [],
91
+ trackedIdsCount: 0,
92
+ error: "Native module not available - using fallback"
93
+ };
94
+ },
84
95
  async trackPurchaseCompleted(_productId, _transactionId, _originalTransactionId) { },
85
96
  async trackPurchaseFromProduct(_productId) { },
86
97
  };
@@ -279,6 +290,72 @@ exports.Notifications = {
279
290
  // ============================================================================
280
291
  // Transaction Observer API (StoreKit 2 / Google Play Billing)
281
292
  // ============================================================================
293
+ /**
294
+ * Helper function to log entitlement check results with full details
295
+ */
296
+ function logEntitlementCheckResult(result, context) {
297
+ console.log("[RampKit] ");
298
+ console.log("[RampKit] ═══════════════════════════════════════════════════════════");
299
+ console.log(`[RampKit] 📊 ENTITLEMENT CHECK RESULT (${context})`);
300
+ console.log("[RampKit] ═══════════════════════════════════════════════════════════");
301
+ console.log("[RampKit] Total entitlements found:", result.totalFound);
302
+ console.log("[RampKit] Already sent to backend: ", result.alreadyTracked);
303
+ console.log("[RampKit] New events sent: ", result.newPurchases);
304
+ console.log("[RampKit] Tracked IDs in storage: ", result.trackedIdsCount);
305
+ console.log("[RampKit] Product IDs: ", result.productIds);
306
+ // Log already tracked transactions with full details
307
+ if (result.alreadyTrackedDetails && result.alreadyTrackedDetails.length > 0) {
308
+ console.log("[RampKit] ");
309
+ console.log("[RampKit] ✅ ALREADY SENT TRANSACTIONS:");
310
+ for (const tx of result.alreadyTrackedDetails) {
311
+ console.log("[RampKit] ────────────────────────────────────────");
312
+ console.log("[RampKit] 📦 Product:", tx.productId);
313
+ console.log("[RampKit] Transaction ID:", tx.transactionId);
314
+ console.log("[RampKit] Original Transaction ID:", tx.originalTransactionId);
315
+ console.log("[RampKit] Purchase Date:", tx.purchaseDate);
316
+ if (tx.expirationDate) {
317
+ console.log("[RampKit] Expiration Date:", tx.expirationDate);
318
+ }
319
+ if (tx.environment) {
320
+ console.log("[RampKit] Environment:", tx.environment);
321
+ }
322
+ console.log("[RampKit] Status: ✅ ALREADY SENT TO BACKEND");
323
+ }
324
+ }
325
+ // Log newly sent events
326
+ if (result.sentEvents && result.sentEvents.length > 0) {
327
+ console.log("[RampKit] ");
328
+ console.log("[RampKit] 📤 NEWLY SENT EVENTS:");
329
+ for (const event of result.sentEvents) {
330
+ console.log("[RampKit] ────────────────────────────────────────");
331
+ console.log("[RampKit] 📦 Product:", event.productId);
332
+ console.log("[RampKit] Transaction ID:", event.transactionId);
333
+ console.log("[RampKit] Original Transaction ID:", event.originalTransactionId);
334
+ console.log("[RampKit] Purchase Date:", event.purchaseDate);
335
+ console.log("[RampKit] Status:", event.status === "sent" ? "✅ SENT" : `❌ ${event.status.toUpperCase()}`);
336
+ if (event.httpStatus) {
337
+ console.log("[RampKit] HTTP Status:", event.httpStatus);
338
+ }
339
+ if (event.error) {
340
+ console.log("[RampKit] Error:", event.error);
341
+ }
342
+ }
343
+ }
344
+ // Log skipped transactions
345
+ if (result.skippedReasons && result.skippedReasons.length > 0) {
346
+ console.log("[RampKit] ");
347
+ console.log("[RampKit] ⏭️ SKIPPED TRANSACTIONS:");
348
+ for (const skipped of result.skippedReasons) {
349
+ console.log("[RampKit] - Product:", skipped.productId, "| Reason:", skipped.reason);
350
+ }
351
+ }
352
+ if (result.error) {
353
+ console.log("[RampKit] ");
354
+ console.log("[RampKit] ⚠️ Error:", result.error);
355
+ }
356
+ console.log("[RampKit] ═══════════════════════════════════════════════════════════");
357
+ console.log("[RampKit] ");
358
+ }
282
359
  exports.TransactionObserver = {
283
360
  /**
284
361
  * Start listening for purchase transactions
@@ -300,29 +377,7 @@ exports.TransactionObserver = {
300
377
  console.log("[RampKit] - previouslyTrackedCount:", result.previouslyTrackedCount);
301
378
  console.log("[RampKit] - listenerStarted:", result.listenerStarted);
302
379
  if (result.entitlementCheck) {
303
- console.log("[RampKit] 📊 Entitlement check results:");
304
- console.log("[RampKit] - totalFound:", result.entitlementCheck.totalFound);
305
- console.log("[RampKit] - alreadyTracked:", result.entitlementCheck.alreadyTracked);
306
- console.log("[RampKit] - newPurchases:", result.entitlementCheck.newPurchases);
307
- console.log("[RampKit] - productIds:", result.entitlementCheck.productIds);
308
- console.log("[RampKit] - newProductIds:", result.entitlementCheck.newProductIds);
309
- // Log sent events details
310
- if (result.entitlementCheck.sentEvents && result.entitlementCheck.sentEvents.length > 0) {
311
- console.log("[RampKit] 📤 Sent events:");
312
- for (const event of result.entitlementCheck.sentEvents) {
313
- console.log("[RampKit] - productId:", event.productId);
314
- console.log("[RampKit] transactionId:", event.transactionId);
315
- console.log("[RampKit] originalTransactionId:", event.originalTransactionId);
316
- console.log("[RampKit] status:", event.status);
317
- console.log("[RampKit] httpStatus:", event.httpStatus);
318
- if (event.error) {
319
- console.log("[RampKit] error:", event.error);
320
- }
321
- if (event.reason) {
322
- console.log("[RampKit] reason:", event.reason);
323
- }
324
- }
325
- }
380
+ logEntitlementCheckResult(result.entitlementCheck, "STARTUP");
326
381
  }
327
382
  if (result.error) {
328
383
  console.warn("[RampKit] ⚠️ Error:", result.error);
@@ -399,4 +454,23 @@ exports.TransactionObserver = {
399
454
  return 0;
400
455
  }
401
456
  },
457
+ /**
458
+ * Re-check current entitlements for any new purchases
459
+ * Call this after onboarding finishes or after a paywall is shown
460
+ * to catch any purchases that may have been made
461
+ *
462
+ * @returns The entitlement check result with details of all transactions
463
+ */
464
+ async recheck() {
465
+ console.log("[RampKit] 🔄 Re-checking entitlements...");
466
+ try {
467
+ const result = await RampKitNativeModule.recheckEntitlements();
468
+ logEntitlementCheckResult(result, "RECHECK");
469
+ return result;
470
+ }
471
+ catch (e) {
472
+ console.warn("[RampKit] ❌ Failed to recheck entitlements:", e);
473
+ return null;
474
+ }
475
+ },
402
476
  };
package/build/index.d.ts CHANGED
@@ -10,6 +10,6 @@ export { collectDeviceInfo, getSessionDurationSeconds, getSessionStartTime, buil
10
10
  export { default as RampKitNative } from "./RampKitNative";
11
11
  export type { NativeDeviceInfo, NativeLaunchData } from "./RampKitNative";
12
12
  export { Haptics, StoreReview, Notifications, TransactionObserver, isNativeModuleAvailable } from "./RampKitNative";
13
- export type { ImpactStyle, NotificationType, NotificationOptions, NotificationPermissionResult, TransactionObserverResult, SentEventResult } from "./RampKitNative";
13
+ export type { ImpactStyle, NotificationType, NotificationOptions, NotificationPermissionResult, TransactionObserverResult, SentEventResult, TrackedTransactionDetail, EntitlementCheckResult } from "./RampKitNative";
14
14
  export type { DeviceInfo, RampKitEvent, EventDevice, EventContext, RampKitConfig, RampKitEventName, RampKitContext, RampKitDeviceContext, RampKitUserContext, NavigationData, ScreenPosition, OnboardingResponse, AppSessionStartedProperties, OnboardingStartedProperties, OnboardingCompletedProperties, OnboardingAbandonedProperties, OptionSelectedProperties, NotificationsResponseProperties, PaywallShownProperties, PurchaseStartedProperties, PurchaseCompletedProperties, PurchaseFailedProperties, PurchaseRestoredProperties, } from "./types";
15
15
  export { SDK_VERSION, CAPABILITIES } from "./constants";
@@ -119,6 +119,15 @@ public class RampKitModule: Module {
119
119
  return count
120
120
  }
121
121
 
122
+ AsyncFunction("recheckEntitlements") { () -> [String: Any] in
123
+ print("[RampKit] 🔄 Re-checking entitlements (called from JS)...")
124
+ if #available(iOS 15.0, *) {
125
+ return await self.checkAndTrackCurrentEntitlements()
126
+ } else {
127
+ return ["error": "iOS 15+ required"]
128
+ }
129
+ }
130
+
122
131
  // ============================================================================
123
132
  // Manual Purchase Tracking (Fallback for Superwall/RevenueCat)
124
133
  // ============================================================================
@@ -477,9 +486,28 @@ public class RampKitModule: Module {
477
486
  /// Check all current entitlements and track any we haven't seen before
478
487
  /// This catches purchases made by Superwall/RevenueCat before our observer started
479
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.
480
493
  @available(iOS 15.0, *)
481
494
  private func checkAndTrackCurrentEntitlements() async -> [String: Any] {
482
- print("[RampKit] 🔍 Checking current entitlements for missed purchases...")
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] ")
508
+
509
+ let formatter = ISO8601DateFormatter()
510
+ formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
483
511
 
484
512
  var foundCount = 0
485
513
  var trackedCount = 0
@@ -488,6 +516,7 @@ public class RampKitModule: Module {
488
516
  var newProductIds: [String] = []
489
517
  var sentEvents: [[String: Any]] = []
490
518
  var skippedReasons: [[String: Any]] = []
519
+ var alreadyTrackedDetails: [[String: Any]] = [] // NEW: Details of already-tracked transactions
491
520
 
492
521
  for await result in Transaction.currentEntitlements {
493
522
  foundCount += 1
@@ -501,26 +530,57 @@ public class RampKitModule: Module {
501
530
  let originalId = String(transaction.originalID)
502
531
  let transactionId = String(transaction.id)
503
532
  productIds.append(transaction.productID)
504
- print("[RampKit] 📦 Found entitlement: \(transaction.productID), originalID: \(originalId), id: \(transactionId)")
533
+
534
+ // Build transaction details for logging
535
+ var txDetails: [String: Any] = [
536
+ "productId": transaction.productID,
537
+ "transactionId": transactionId,
538
+ "originalTransactionId": originalId,
539
+ "purchaseDate": formatter.string(from: transaction.purchaseDate)
540
+ ]
541
+ if let expirationDate = transaction.expirationDate {
542
+ txDetails["expirationDate"] = formatter.string(from: expirationDate)
543
+ }
544
+ if #available(iOS 16.0, *) {
545
+ txDetails["environment"] = transaction.environment.rawValue
546
+ }
547
+
548
+ print("[RampKit] 📦 Found entitlement:")
549
+ print("[RampKit] - productId: \(transaction.productID)")
550
+ print("[RampKit] - transactionId: \(transactionId)")
551
+ print("[RampKit] - originalTransactionId: \(originalId)")
552
+ print("[RampKit] - purchaseDate: \(formatter.string(from: transaction.purchaseDate))")
505
553
 
506
554
  // Check if we've already tracked this transaction
555
+ // "Tracked" means we successfully sent a purchase_completed event to the backend
556
+ // and received an HTTP 2xx response. We store the originalTransactionId after success.
507
557
  if trackedTransactionIds.contains(originalId) {
508
558
  trackedCount += 1
509
- print("[RampKit] Already tracked: \(transaction.productID)")
559
+ txDetails["status"] = "already_sent"
560
+ alreadyTrackedDetails.append(txDetails)
561
+ print("[RampKit] ✅ STATUS: ALREADY SENT TO BACKEND")
562
+ print("[RampKit] (originalTransactionId \(originalId) is in our sent-transactions storage)")
563
+ print("[RampKit] This means we previously sent a purchase_completed event")
564
+ print("[RampKit] and received a successful HTTP 2xx response.")
565
+ print("[RampKit] ")
510
566
  continue
511
567
  }
512
568
 
513
569
  // Skip renewals and revocations
514
570
  guard transaction.originalID == transaction.id,
515
571
  transaction.revocationDate == nil else {
516
- skippedReasons.append(["productId": transaction.productID, "reason": "renewal or revoked"])
572
+ let reason = transaction.revocationDate != nil ? "revoked" : "renewal"
573
+ txDetails["status"] = "skipped"
574
+ txDetails["reason"] = reason
575
+ skippedReasons.append(txDetails)
576
+ print("[RampKit] ⏭️ STATUS: Skipped (\(reason))")
517
577
  continue
518
578
  }
519
579
 
520
580
  // NEW transaction we haven't seen!
521
581
  newCount += 1
522
582
  newProductIds.append(transaction.productID)
523
- print("[RampKit] 🆕 NEW purchase detected: \(transaction.productID)")
583
+ print("[RampKit] 🆕 STATUS: NEW purchase - will send to backend now...")
524
584
 
525
585
  // Track it and get the result
526
586
  let sendResult = await self.handleTransactionWithResult(transaction)
@@ -530,16 +590,28 @@ public class RampKitModule: Module {
530
590
  if let status = sendResult["status"] as? String, status == "sent" {
531
591
  trackedTransactionIds.insert(originalId)
532
592
  saveTrackedTransactions()
533
- print("[RampKit] ✅ Marked as tracked after successful send: \(transaction.productID)")
593
+ print("[RampKit] ✅ Event sent successfully! HTTP status: \(sendResult["httpStatus"] ?? "unknown")")
594
+ print("[RampKit] ✅ Marked originalTransactionId \(originalId) as tracked")
534
595
  } else {
535
- print("[RampKit] ⚠️ Send failed, will retry next time: \(transaction.productID)")
596
+ print("[RampKit] Send failed: \(sendResult["error"] ?? "unknown error")")
597
+ print("[RampKit] ⚠️ Will retry on next app launch")
536
598
  }
537
599
  }
538
600
 
539
- print("[RampKit] 🔍 Entitlement check complete:")
540
- print("[RampKit] - Total found: \(foundCount)")
541
- print("[RampKit] - Already tracked: \(trackedCount)")
542
- print("[RampKit] - NEW (sent events): \(newCount)")
601
+ print("[RampKit] ")
602
+ print("[RampKit] ════════════════════════════════════════════════════════════")
603
+ print("[RampKit] 📊 ENTITLEMENT CHECK SUMMARY")
604
+ print("[RampKit] ════════════════════════════════════════════════════════════")
605
+ print("[RampKit] Total entitlements found: \(foundCount)")
606
+ print("[RampKit] Already sent (HTTP 2xx): \(trackedCount) (no action needed)")
607
+ print("[RampKit] Skipped (renewal/revoked): \(skippedReasons.count) (backend gets via S2S)")
608
+ print("[RampKit] NEW events sent this session: \(newCount)")
609
+ print("[RampKit] Total tracked IDs in storage: \(trackedTransactionIds.count)")
610
+ if newCount == 0 && foundCount > 0 {
611
+ print("[RampKit] ")
612
+ print("[RampKit] ℹ️ All purchases already sent or skipped - nothing new to send")
613
+ }
614
+ print("[RampKit] ════════════════════════════════════════════════════════════")
543
615
 
544
616
  return [
545
617
  "totalFound": foundCount,
@@ -548,7 +620,9 @@ public class RampKitModule: Module {
548
620
  "productIds": productIds,
549
621
  "newProductIds": newProductIds,
550
622
  "sentEvents": sentEvents,
551
- "skippedReasons": skippedReasons
623
+ "skippedReasons": skippedReasons,
624
+ "alreadyTrackedDetails": alreadyTrackedDetails, // NEW
625
+ "trackedIdsCount": trackedTransactionIds.count
552
626
  ]
553
627
  }
554
628
 
@@ -865,8 +939,8 @@ public class RampKitModule: Module {
865
939
  }
866
940
  }
867
941
 
868
- private func sendPurchaseEvent(appId: String, userId: String, eventName: String, properties: [String: Any]) async {
869
- let _ = await sendPurchaseEventWithResult(appId: appId, userId: userId, eventName: eventName, properties: properties)
942
+ private func sendPurchaseEvent(appId: String, userId: String, eventName: String, properties: [String: Any], paywallId: String? = nil) async {
943
+ let _ = await sendPurchaseEventWithResult(appId: appId, userId: userId, eventName: eventName, properties: properties, paywallId: paywallId)
870
944
  }
871
945
 
872
946
  private struct SendEventResult {
@@ -875,7 +949,16 @@ public class RampKitModule: Module {
875
949
  let error: String?
876
950
  }
877
951
 
878
- private func sendPurchaseEventWithResult(appId: String, userId: String, eventName: String, properties: [String: Any]) async -> SendEventResult {
952
+ private func sendPurchaseEventWithResult(appId: String, userId: String, eventName: String, properties: [String: Any], paywallId: String? = nil) async -> SendEventResult {
953
+ // Build context with optional paywallId for attribution
954
+ var context: [String: Any] = [
955
+ "locale": Locale.current.identifier,
956
+ "regionCode": Locale.current.regionCode as Any
957
+ ]
958
+ if let paywallId = paywallId {
959
+ context["paywallId"] = paywallId
960
+ }
961
+
879
962
  let event: [String: Any] = [
880
963
  "appId": appId,
881
964
  "appUserId": userId,
@@ -888,17 +971,53 @@ public class RampKitModule: Module {
888
971
  "platformVersion": UIDevice.current.systemVersion,
889
972
  "deviceModel": getDeviceModelIdentifier(),
890
973
  "sdkVersion": "1.0.0",
891
- "appVersion": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
892
- "buildNumber": Bundle.main.infoDictionary?["CFBundleVersion"] as? String
893
- ],
894
- "context": [
895
- "locale": Locale.current.identifier,
896
- "regionCode": Locale.current.regionCode
974
+ "appVersion": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown",
975
+ "buildNumber": Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
897
976
  ],
977
+ "context": context,
898
978
  "properties": properties
899
979
  ]
900
980
 
981
+ // DETAILED LOGGING: Log the full request body
982
+ print("[RampKit] ")
983
+ print("[RampKit] ════════════════════════════════════════════════════════════")
984
+ print("[RampKit] 📤 SENDING PURCHASE EVENT TO BACKEND")
985
+ print("[RampKit] ════════════════════════════════════════════════════════════")
986
+ print("[RampKit] URL: https://uustlzuvjmochxkxatfx.supabase.co/functions/v1/app-user-events")
987
+ print("[RampKit] Method: POST")
988
+ print("[RampKit] ")
989
+ print("[RampKit] 📋 REQUEST BODY:")
990
+ print("[RampKit] appId: \(appId)")
991
+ print("[RampKit] appUserId: \(userId)")
992
+ print("[RampKit] eventName: \(eventName)")
993
+ if let originalTxId = properties["originalTransactionId"] {
994
+ print("[RampKit] properties.originalTransactionId: \(originalTxId) ✓ (CRITICAL for attribution)")
995
+ } else {
996
+ print("[RampKit] ⚠️ WARNING: properties.originalTransactionId is MISSING!")
997
+ }
998
+ if let productId = properties["productId"] {
999
+ print("[RampKit] properties.productId: \(productId)")
1000
+ }
1001
+ if let amount = properties["amount"], let currency = properties["currency"] {
1002
+ print("[RampKit] properties.amount: \(amount) \(currency)")
1003
+ }
1004
+ if let paywallId = paywallId {
1005
+ print("[RampKit] context.paywallId: \(paywallId) ✓")
1006
+ }
1007
+
1008
+ // Log full JSON for debugging
1009
+ if let jsonData = try? JSONSerialization.data(withJSONObject: event, options: .prettyPrinted),
1010
+ let jsonString = String(data: jsonData, encoding: .utf8) {
1011
+ print("[RampKit] ")
1012
+ print("[RampKit] 📄 FULL JSON PAYLOAD:")
1013
+ for line in jsonString.components(separatedBy: "\n") {
1014
+ print("[RampKit] \(line)")
1015
+ }
1016
+ }
1017
+ print("[RampKit] ════════════════════════════════════════════════════════════")
1018
+
901
1019
  guard let url = URL(string: "https://uustlzuvjmochxkxatfx.supabase.co/functions/v1/app-user-events") else {
1020
+ print("[RampKit] ❌ SEND FAILED: Invalid URL")
902
1021
  return SendEventResult(success: false, statusCode: 0, error: "Invalid URL")
903
1022
  }
904
1023
 
@@ -910,15 +1029,40 @@ public class RampKitModule: Module {
910
1029
 
911
1030
  do {
912
1031
  request.httpBody = try JSONSerialization.data(withJSONObject: event)
913
- let (_, response) = try await URLSession.shared.data(for: request)
1032
+ let (data, response) = try await URLSession.shared.data(for: request)
1033
+
914
1034
  if let httpResponse = response as? HTTPURLResponse {
915
- print("[RampKit] Purchase event sent: \(eventName) - Status: \(httpResponse.statusCode)")
916
1035
  let success = httpResponse.statusCode >= 200 && httpResponse.statusCode < 300
917
- return SendEventResult(success: success, statusCode: httpResponse.statusCode, error: success ? nil : "HTTP \(httpResponse.statusCode)")
1036
+ let responseBody = String(data: data, encoding: .utf8) ?? "(empty)"
1037
+
1038
+ // DETAILED LOGGING: Log the response
1039
+ print("[RampKit] ")
1040
+ print("[RampKit] 📥 RESPONSE FROM BACKEND:")
1041
+ print("[RampKit] HTTP Status: \(httpResponse.statusCode)")
1042
+ print("[RampKit] Success: \(success ? "✅ YES" : "❌ NO")")
1043
+ print("[RampKit] Response Body: \(responseBody)")
1044
+
1045
+ if success {
1046
+ print("[RampKit] ")
1047
+ print("[RampKit] ✅ EVENT SENT SUCCESSFULLY!")
1048
+ print("[RampKit] originalTransactionId \(properties["originalTransactionId"] ?? "unknown") will be marked as SENT")
1049
+ print("[RampKit] ════════════════════════════════════════════════════════════")
1050
+ } else {
1051
+ print("[RampKit] ")
1052
+ print("[RampKit] ❌ EVENT SEND FAILED!")
1053
+ print("[RampKit] Will retry on next app launch")
1054
+ print("[RampKit] ════════════════════════════════════════════════════════════")
1055
+ }
1056
+
1057
+ return SendEventResult(success: success, statusCode: httpResponse.statusCode, error: success ? nil : "HTTP \(httpResponse.statusCode): \(responseBody)")
918
1058
  }
1059
+ print("[RampKit] ❌ SEND FAILED: No HTTP response")
919
1060
  return SendEventResult(success: false, statusCode: 0, error: "No HTTP response")
920
1061
  } catch {
921
- print("[RampKit] Failed to send purchase event: \(error)")
1062
+ print("[RampKit] ")
1063
+ print("[RampKit] ❌ SEND FAILED: Network error")
1064
+ print("[RampKit] Error: \(error.localizedDescription)")
1065
+ print("[RampKit] ════════════════════════════════════════════════════════════")
922
1066
  return SendEventResult(success: false, statusCode: 0, error: error.localizedDescription)
923
1067
  }
924
1068
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.70",
3
+ "version": "0.0.72",
4
4
  "description": "The Expo SDK for RampKit. Build, test, and personalize app onboardings with instant updates.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",