rampkit-expo-dev 0.0.67 → 0.0.69
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 +7 -1
- package/build/RampKitNative.d.ts +19 -2
- package/build/RampKitNative.js +46 -5
- package/build/index.d.ts +2 -2
- package/build/index.js +2 -1
- package/ios/RampKitModule.swift +134 -114
- package/package.json +1 -1
package/build/RampKit.js
CHANGED
|
@@ -63,7 +63,13 @@ class RampKitCore {
|
|
|
63
63
|
EventManager_1.eventManager.trackAppSessionStarted(this.deviceInfo.isFirstLaunch, this.deviceInfo.launchCount);
|
|
64
64
|
// Step 5: Start transaction observer for automatic purchase tracking
|
|
65
65
|
console.log("[RampKit] Configure: Starting transaction observer...");
|
|
66
|
-
|
|
66
|
+
try {
|
|
67
|
+
await RampKitNative_1.TransactionObserver.start(config.appId);
|
|
68
|
+
console.log("[RampKit] Configure: Transaction observer setup complete");
|
|
69
|
+
}
|
|
70
|
+
catch (txError) {
|
|
71
|
+
console.error("[RampKit] Configure: Transaction observer failed:", txError);
|
|
72
|
+
}
|
|
67
73
|
this.initialized = true;
|
|
68
74
|
}
|
|
69
75
|
catch (e) {
|
package/build/RampKitNative.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ interface RampKitNativeModule {
|
|
|
16
16
|
getStoreUrl(): Promise<string | null>;
|
|
17
17
|
requestNotificationPermissions(options?: NotificationOptions): Promise<NotificationPermissionResult>;
|
|
18
18
|
getNotificationPermissions(): Promise<NotificationPermissionResult>;
|
|
19
|
-
startTransactionObserver(appId: string): Promise<
|
|
19
|
+
startTransactionObserver(appId: string): Promise<TransactionObserverResult>;
|
|
20
20
|
stopTransactionObserver(): Promise<void>;
|
|
21
21
|
trackPurchaseCompleted(productId: string, transactionId?: string, originalTransactionId?: string): Promise<void>;
|
|
22
22
|
trackPurchaseFromProduct(productId: string): Promise<void>;
|
|
@@ -86,9 +86,26 @@ export interface NotificationPermissionResult {
|
|
|
86
86
|
};
|
|
87
87
|
error?: string;
|
|
88
88
|
}
|
|
89
|
+
export interface TransactionObserverResult {
|
|
90
|
+
configured: boolean;
|
|
91
|
+
appId: string;
|
|
92
|
+
userId: string;
|
|
93
|
+
previouslyTrackedCount: number;
|
|
94
|
+
iOSVersion: string;
|
|
95
|
+
listenerStarted: boolean;
|
|
96
|
+
entitlementCheck?: {
|
|
97
|
+
totalFound: number;
|
|
98
|
+
alreadyTracked: number;
|
|
99
|
+
newPurchases: number;
|
|
100
|
+
productIds: string[];
|
|
101
|
+
newProductIds: string[];
|
|
102
|
+
};
|
|
103
|
+
error?: string;
|
|
104
|
+
}
|
|
89
105
|
export type ImpactStyle = "light" | "medium" | "heavy" | "rigid" | "soft";
|
|
90
106
|
export type NotificationType = "success" | "warning" | "error";
|
|
91
107
|
declare let RampKitNativeModule: RampKitNativeModule;
|
|
108
|
+
export declare function isNativeModuleAvailable(): boolean;
|
|
92
109
|
export default RampKitNativeModule;
|
|
93
110
|
export declare function getDeviceInfo(): Promise<NativeDeviceInfo>;
|
|
94
111
|
export declare function getUserId(): Promise<string>;
|
|
@@ -159,7 +176,7 @@ export declare const TransactionObserver: {
|
|
|
159
176
|
* Automatically tracks purchases to the RampKit backend
|
|
160
177
|
* @param appId - The RampKit app ID
|
|
161
178
|
*/
|
|
162
|
-
start(appId: string): Promise<
|
|
179
|
+
start(appId: string): Promise<TransactionObserverResult | null>;
|
|
163
180
|
/**
|
|
164
181
|
* Stop listening for purchase transactions
|
|
165
182
|
*/
|
package/build/RampKitNative.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.TransactionObserver = exports.Notifications = exports.StoreReview = exports.Haptics = void 0;
|
|
8
|
+
exports.isNativeModuleAvailable = isNativeModuleAvailable;
|
|
8
9
|
exports.getDeviceInfo = getDeviceInfo;
|
|
9
10
|
exports.getUserId = getUserId;
|
|
10
11
|
exports.getStoredValue = getStoredValue;
|
|
@@ -14,13 +15,20 @@ const expo_modules_core_1 = require("expo-modules-core");
|
|
|
14
15
|
const react_native_1 = require("react-native");
|
|
15
16
|
// Get the native module
|
|
16
17
|
let RampKitNativeModule;
|
|
18
|
+
let isNativeModuleLoaded = false;
|
|
17
19
|
try {
|
|
18
20
|
RampKitNativeModule = (0, expo_modules_core_1.requireNativeModule)("RampKit");
|
|
21
|
+
isNativeModuleLoaded = true;
|
|
22
|
+
console.log("[RampKit] ✅ Native module loaded successfully");
|
|
19
23
|
}
|
|
20
24
|
catch (e) {
|
|
21
|
-
console.warn("[RampKit] Native module not available. Using JavaScript fallback.");
|
|
25
|
+
console.warn("[RampKit] ⚠️ Native module not available. Using JavaScript fallback.", e);
|
|
22
26
|
RampKitNativeModule = createFallbackModule();
|
|
23
27
|
}
|
|
28
|
+
// Export for debugging
|
|
29
|
+
function isNativeModuleAvailable() {
|
|
30
|
+
return isNativeModuleLoaded;
|
|
31
|
+
}
|
|
24
32
|
// Fallback module for when native module is not available
|
|
25
33
|
function createFallbackModule() {
|
|
26
34
|
return {
|
|
@@ -60,7 +68,17 @@ function createFallbackModule() {
|
|
|
60
68
|
async getNotificationPermissions() {
|
|
61
69
|
return { granted: false, status: "denied", canAskAgain: false };
|
|
62
70
|
},
|
|
63
|
-
async startTransactionObserver(_appId) {
|
|
71
|
+
async startTransactionObserver(_appId) {
|
|
72
|
+
return {
|
|
73
|
+
configured: false,
|
|
74
|
+
appId: _appId,
|
|
75
|
+
userId: "fallback",
|
|
76
|
+
previouslyTrackedCount: 0,
|
|
77
|
+
iOSVersion: "N/A",
|
|
78
|
+
listenerStarted: false,
|
|
79
|
+
error: "Native module not available - using fallback"
|
|
80
|
+
};
|
|
81
|
+
},
|
|
64
82
|
async stopTransactionObserver() { },
|
|
65
83
|
async trackPurchaseCompleted(_productId, _transactionId, _originalTransactionId) { },
|
|
66
84
|
async trackPurchaseFromProduct(_productId) { },
|
|
@@ -267,12 +285,35 @@ exports.TransactionObserver = {
|
|
|
267
285
|
* @param appId - The RampKit app ID
|
|
268
286
|
*/
|
|
269
287
|
async start(appId) {
|
|
288
|
+
console.log("[RampKit] 🚀 TransactionObserver.start() called");
|
|
289
|
+
console.log("[RampKit] - appId:", appId);
|
|
290
|
+
console.log("[RampKit] - Native module loaded:", isNativeModuleLoaded);
|
|
270
291
|
try {
|
|
271
|
-
|
|
272
|
-
|
|
292
|
+
console.log("[RampKit] 📡 Calling native startTransactionObserver...");
|
|
293
|
+
const result = await RampKitNativeModule.startTransactionObserver(appId);
|
|
294
|
+
// Log the full result for debugging
|
|
295
|
+
console.log("[RampKit] ✅ Transaction observer result:");
|
|
296
|
+
console.log("[RampKit] - configured:", result.configured);
|
|
297
|
+
console.log("[RampKit] - userId:", result.userId);
|
|
298
|
+
console.log("[RampKit] - iOSVersion:", result.iOSVersion);
|
|
299
|
+
console.log("[RampKit] - previouslyTrackedCount:", result.previouslyTrackedCount);
|
|
300
|
+
console.log("[RampKit] - listenerStarted:", result.listenerStarted);
|
|
301
|
+
if (result.entitlementCheck) {
|
|
302
|
+
console.log("[RampKit] 📊 Entitlement check results:");
|
|
303
|
+
console.log("[RampKit] - totalFound:", result.entitlementCheck.totalFound);
|
|
304
|
+
console.log("[RampKit] - alreadyTracked:", result.entitlementCheck.alreadyTracked);
|
|
305
|
+
console.log("[RampKit] - newPurchases:", result.entitlementCheck.newPurchases);
|
|
306
|
+
console.log("[RampKit] - productIds:", result.entitlementCheck.productIds);
|
|
307
|
+
console.log("[RampKit] - newProductIds:", result.entitlementCheck.newProductIds);
|
|
308
|
+
}
|
|
309
|
+
if (result.error) {
|
|
310
|
+
console.warn("[RampKit] ⚠️ Error:", result.error);
|
|
311
|
+
}
|
|
312
|
+
return result;
|
|
273
313
|
}
|
|
274
314
|
catch (e) {
|
|
275
|
-
console.warn("[RampKit] Failed to start transaction observer:", e);
|
|
315
|
+
console.warn("[RampKit] ❌ Failed to start transaction observer:", e);
|
|
316
|
+
return null;
|
|
276
317
|
}
|
|
277
318
|
},
|
|
278
319
|
/**
|
package/build/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { eventManager } from "./EventManager";
|
|
|
9
9
|
export { collectDeviceInfo, getSessionDurationSeconds, getSessionStartTime, buildRampKitContext, } from "./DeviceInfoCollector";
|
|
10
10
|
export { default as RampKitNative } from "./RampKitNative";
|
|
11
11
|
export type { NativeDeviceInfo, NativeLaunchData } from "./RampKitNative";
|
|
12
|
-
export { Haptics, StoreReview, Notifications, TransactionObserver } from "./RampKitNative";
|
|
13
|
-
export type { ImpactStyle, NotificationType, NotificationOptions, NotificationPermissionResult } from "./RampKitNative";
|
|
12
|
+
export { Haptics, StoreReview, Notifications, TransactionObserver, isNativeModuleAvailable } from "./RampKitNative";
|
|
13
|
+
export type { ImpactStyle, NotificationType, NotificationOptions, NotificationPermissionResult, TransactionObserverResult } 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";
|
package/build/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.CAPABILITIES = exports.SDK_VERSION = exports.TransactionObserver = exports.Notifications = exports.StoreReview = exports.Haptics = exports.RampKitNative = exports.buildRampKitContext = exports.getSessionStartTime = exports.getSessionDurationSeconds = exports.collectDeviceInfo = exports.eventManager = exports.getRampKitUserId = exports.RampKit = void 0;
|
|
10
|
+
exports.CAPABILITIES = exports.SDK_VERSION = exports.isNativeModuleAvailable = exports.TransactionObserver = exports.Notifications = exports.StoreReview = exports.Haptics = exports.RampKitNative = exports.buildRampKitContext = exports.getSessionStartTime = exports.getSessionDurationSeconds = exports.collectDeviceInfo = exports.eventManager = exports.getRampKitUserId = exports.RampKit = void 0;
|
|
11
11
|
const RampKit_1 = require("./RampKit");
|
|
12
12
|
// Main SDK singleton instance
|
|
13
13
|
exports.RampKit = RampKit_1.RampKitCore.instance;
|
|
@@ -32,6 +32,7 @@ Object.defineProperty(exports, "Haptics", { enumerable: true, get: function () {
|
|
|
32
32
|
Object.defineProperty(exports, "StoreReview", { enumerable: true, get: function () { return RampKitNative_2.StoreReview; } });
|
|
33
33
|
Object.defineProperty(exports, "Notifications", { enumerable: true, get: function () { return RampKitNative_2.Notifications; } });
|
|
34
34
|
Object.defineProperty(exports, "TransactionObserver", { enumerable: true, get: function () { return RampKitNative_2.TransactionObserver; } });
|
|
35
|
+
Object.defineProperty(exports, "isNativeModuleAvailable", { enumerable: true, get: function () { return RampKitNative_2.isNativeModuleAvailable; } });
|
|
35
36
|
// Export constants
|
|
36
37
|
var constants_1 = require("./constants");
|
|
37
38
|
Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return constants_1.SDK_VERSION; } });
|
package/ios/RampKitModule.swift
CHANGED
|
@@ -9,22 +9,26 @@ public class RampKitModule: Module {
|
|
|
9
9
|
private let installDateKey = "rk_install_date"
|
|
10
10
|
private let launchCountKey = "rk_launch_count"
|
|
11
11
|
private let lastLaunchKey = "rk_last_launch"
|
|
12
|
+
private let trackedTransactionsKey = "rk_tracked_transactions"
|
|
12
13
|
|
|
13
14
|
// Transaction observer task
|
|
14
15
|
private var transactionObserverTask: Task<Void, Never>?
|
|
15
16
|
private var appId: String?
|
|
16
17
|
private var userId: String?
|
|
17
|
-
|
|
18
|
-
// Queue for transactions received before SDK is configured
|
|
19
|
-
private var pendingTransactions: [Any] = []
|
|
20
18
|
private var isConfigured = false
|
|
21
19
|
|
|
20
|
+
// Set of already-tracked originalTransactionIds to prevent duplicates
|
|
21
|
+
private var trackedTransactionIds: Set<String> = []
|
|
22
|
+
|
|
22
23
|
public func definition() -> ModuleDefinition {
|
|
23
24
|
Name("RampKit")
|
|
24
25
|
|
|
25
|
-
//
|
|
26
|
+
// OnCreate runs when JS first requires the module - may be too late for some transactions
|
|
26
27
|
OnCreate {
|
|
27
|
-
|
|
28
|
+
print("[RampKit] ⚡ OnCreate called - module being initialized")
|
|
29
|
+
self.loadTrackedTransactions()
|
|
30
|
+
self.userId = self.getOrCreateUserId()
|
|
31
|
+
print("[RampKit] ⚡ OnCreate complete, userId: \(self.userId ?? "nil")")
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
// ============================================================================
|
|
@@ -99,8 +103,8 @@ public class RampKitModule: Module {
|
|
|
99
103
|
// Transaction Observer (StoreKit 2)
|
|
100
104
|
// ============================================================================
|
|
101
105
|
|
|
102
|
-
AsyncFunction("startTransactionObserver") { (appId: String) in
|
|
103
|
-
self.startTransactionObserver(appId: appId)
|
|
106
|
+
AsyncFunction("startTransactionObserver") { (appId: String) -> [String: Any] in
|
|
107
|
+
return await self.startTransactionObserver(appId: appId)
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
AsyncFunction("stopTransactionObserver") { () in
|
|
@@ -249,8 +253,23 @@ public class RampKitModule: Module {
|
|
|
249
253
|
SecItemAdd(addQuery as CFDictionary, nil)
|
|
250
254
|
}
|
|
251
255
|
|
|
256
|
+
// MARK: - Tracked Transactions (Deduplication)
|
|
257
|
+
|
|
258
|
+
private func loadTrackedTransactions() {
|
|
259
|
+
if let stored = UserDefaults.standard.array(forKey: trackedTransactionsKey) as? [String] {
|
|
260
|
+
trackedTransactionIds = Set(stored)
|
|
261
|
+
print("[RampKit] 📚 Loaded \(trackedTransactionIds.count) tracked transaction IDs")
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private func saveTrackedTransactions() {
|
|
266
|
+
let array = Array(trackedTransactionIds)
|
|
267
|
+
UserDefaults.standard.set(array, forKey: trackedTransactionsKey)
|
|
268
|
+
print("[RampKit] 💾 Saved \(trackedTransactionIds.count) tracked transaction IDs")
|
|
269
|
+
}
|
|
270
|
+
|
|
252
271
|
// MARK: - Launch Tracking
|
|
253
|
-
|
|
272
|
+
|
|
254
273
|
private func getLaunchTrackingData() -> [String: Any?] {
|
|
255
274
|
let defaults = UserDefaults.standard
|
|
256
275
|
let now = ISO8601DateFormatter().string(from: Date())
|
|
@@ -412,149 +431,150 @@ public class RampKitModule: Module {
|
|
|
412
431
|
|
|
413
432
|
// MARK: - StoreKit 2 Transaction Observer
|
|
414
433
|
|
|
415
|
-
/// Called
|
|
416
|
-
|
|
417
|
-
|
|
434
|
+
/// Called from JavaScript - sets appId and IMMEDIATELY checks for purchases we may have missed
|
|
435
|
+
/// Returns debug info for JavaScript logging
|
|
436
|
+
private func startTransactionObserver(appId: String) async -> [String: Any] {
|
|
437
|
+
self.appId = appId
|
|
418
438
|
self.userId = getOrCreateUserId()
|
|
439
|
+
self.isConfigured = true
|
|
419
440
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Don't restart if already running
|
|
426
|
-
guard transactionObserverTask == nil else {
|
|
427
|
-
print("[RampKit] Transaction observer already running")
|
|
428
|
-
return
|
|
429
|
-
}
|
|
441
|
+
print("[RampKit] ✅ Transaction observer configured with appId: \(appId)")
|
|
442
|
+
print("[RampKit] 📊 Already tracked \(trackedTransactionIds.count) transactions")
|
|
430
443
|
|
|
431
|
-
|
|
444
|
+
var result: [String: Any] = [
|
|
445
|
+
"configured": true,
|
|
446
|
+
"appId": appId,
|
|
447
|
+
"userId": self.userId ?? "unknown",
|
|
448
|
+
"previouslyTrackedCount": trackedTransactionIds.count,
|
|
449
|
+
"iOSVersion": UIDevice.current.systemVersion
|
|
450
|
+
]
|
|
432
451
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
452
|
+
if #available(iOS 15.0, *) {
|
|
453
|
+
// CRITICAL: Check current entitlements for any purchases we missed
|
|
454
|
+
// This is the KEY mechanism for catching Superwall/RevenueCat purchases
|
|
455
|
+
let entitlementResult = await self.checkAndTrackCurrentEntitlements()
|
|
456
|
+
result["entitlementCheck"] = entitlementResult
|
|
457
|
+
|
|
458
|
+
// Also start listening for future transactions
|
|
459
|
+
await self.startTransactionUpdatesListener()
|
|
460
|
+
result["listenerStarted"] = true
|
|
461
|
+
} else {
|
|
462
|
+
result["error"] = "iOS 15+ required for StoreKit 2"
|
|
463
|
+
result["listenerStarted"] = false
|
|
440
464
|
}
|
|
441
465
|
|
|
442
|
-
|
|
443
|
-
Task {
|
|
444
|
-
await self.handleUnfinishedTransactions()
|
|
445
|
-
}
|
|
466
|
+
return result
|
|
446
467
|
}
|
|
447
468
|
|
|
448
|
-
///
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
469
|
+
/// Check all current entitlements and track any we haven't seen before
|
|
470
|
+
/// This catches purchases made by Superwall/RevenueCat before our observer started
|
|
471
|
+
/// Returns a dictionary with the results for JavaScript logging
|
|
472
|
+
@available(iOS 15.0, *)
|
|
473
|
+
private func checkAndTrackCurrentEntitlements() async -> [String: Any] {
|
|
474
|
+
print("[RampKit] 🔍 Checking current entitlements for missed purchases...")
|
|
453
475
|
|
|
454
|
-
|
|
476
|
+
var foundCount = 0
|
|
477
|
+
var trackedCount = 0
|
|
478
|
+
var newCount = 0
|
|
479
|
+
var productIds: [String] = []
|
|
480
|
+
var newProductIds: [String] = []
|
|
455
481
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
482
|
+
for await result in Transaction.currentEntitlements {
|
|
483
|
+
foundCount += 1
|
|
484
|
+
|
|
485
|
+
guard case .verified(let transaction) = result else {
|
|
486
|
+
print("[RampKit] ⚠️ Unverified entitlement skipped")
|
|
487
|
+
continue
|
|
460
488
|
}
|
|
461
489
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
490
|
+
let originalId = String(transaction.originalID)
|
|
491
|
+
productIds.append(transaction.productID)
|
|
492
|
+
print("[RampKit] 📦 Found entitlement: \(transaction.productID), originalID: \(originalId)")
|
|
493
|
+
|
|
494
|
+
// Check if we've already tracked this transaction
|
|
495
|
+
if trackedTransactionIds.contains(originalId) {
|
|
496
|
+
trackedCount += 1
|
|
497
|
+
print("[RampKit] ✓ Already tracked: \(transaction.productID)")
|
|
498
|
+
continue
|
|
465
499
|
}
|
|
466
|
-
}
|
|
467
500
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
501
|
+
// NEW transaction we haven't seen!
|
|
502
|
+
newCount += 1
|
|
503
|
+
newProductIds.append(transaction.productID)
|
|
504
|
+
print("[RampKit] 🆕 NEW purchase detected: \(transaction.productID)")
|
|
505
|
+
|
|
506
|
+
// Track it
|
|
507
|
+
await self.handleTransaction(transaction)
|
|
508
|
+
|
|
509
|
+
// Mark as tracked
|
|
510
|
+
trackedTransactionIds.insert(originalId)
|
|
511
|
+
saveTrackedTransactions()
|
|
471
512
|
}
|
|
513
|
+
|
|
514
|
+
print("[RampKit] 🔍 Entitlement check complete:")
|
|
515
|
+
print("[RampKit] - Total found: \(foundCount)")
|
|
516
|
+
print("[RampKit] - Already tracked: \(trackedCount)")
|
|
517
|
+
print("[RampKit] - NEW (sent events): \(newCount)")
|
|
518
|
+
|
|
519
|
+
return [
|
|
520
|
+
"totalFound": foundCount,
|
|
521
|
+
"alreadyTracked": trackedCount,
|
|
522
|
+
"newPurchases": newCount,
|
|
523
|
+
"productIds": productIds,
|
|
524
|
+
"newProductIds": newProductIds
|
|
525
|
+
]
|
|
472
526
|
}
|
|
473
527
|
|
|
528
|
+
/// Start listening for Transaction.updates (for future purchases)
|
|
474
529
|
@available(iOS 15.0, *)
|
|
475
|
-
private func
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
530
|
+
private func startTransactionUpdatesListener() async {
|
|
531
|
+
guard transactionObserverTask == nil else {
|
|
532
|
+
print("[RampKit] Transaction updates listener already running")
|
|
533
|
+
return
|
|
534
|
+
}
|
|
479
535
|
|
|
480
|
-
|
|
481
|
-
// We're configured, process immediately
|
|
482
|
-
await self.handleTransaction(transaction)
|
|
483
|
-
} else {
|
|
484
|
-
// Not configured yet, queue it
|
|
485
|
-
print("[RampKit] 📦 Queueing transaction (SDK not configured yet): \(transaction.productID)")
|
|
486
|
-
self.pendingTransactions.append(transaction)
|
|
487
|
-
}
|
|
536
|
+
print("[RampKit] 👂 Starting Transaction.updates listener...")
|
|
488
537
|
|
|
489
|
-
|
|
490
|
-
await
|
|
491
|
-
|
|
492
|
-
} catch {
|
|
493
|
-
print("[RampKit] ❌ Transaction verification failed: \(error)")
|
|
494
|
-
}
|
|
495
|
-
}
|
|
538
|
+
transactionObserverTask = Task {
|
|
539
|
+
for await result in Transaction.updates {
|
|
540
|
+
print("[RampKit] 🎉 Transaction.updates received!")
|
|
496
541
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
542
|
+
guard case .verified(let transaction) = result else {
|
|
543
|
+
print("[RampKit] ⚠️ Unverified transaction update")
|
|
544
|
+
continue
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
let originalId = String(transaction.originalID)
|
|
500
548
|
|
|
501
|
-
|
|
549
|
+
// Skip if already tracked
|
|
550
|
+
if self.trackedTransactionIds.contains(originalId) {
|
|
551
|
+
print("[RampKit] ✓ Transaction.updates: Already tracked \(transaction.productID)")
|
|
552
|
+
await transaction.finish()
|
|
553
|
+
continue
|
|
554
|
+
}
|
|
502
555
|
|
|
503
|
-
|
|
504
|
-
|
|
556
|
+
print("[RampKit] 🆕 Transaction.updates: NEW purchase \(transaction.productID)")
|
|
557
|
+
|
|
558
|
+
// Track it
|
|
505
559
|
await self.handleTransaction(transaction)
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
560
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
561
|
+
// Mark as tracked
|
|
562
|
+
self.trackedTransactionIds.insert(originalId)
|
|
563
|
+
self.saveTrackedTransactions()
|
|
512
564
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
print("[RampKit] 🔍 Checking current entitlements...")
|
|
516
|
-
var count = 0
|
|
517
|
-
for await result in Transaction.currentEntitlements {
|
|
518
|
-
if case .verified(let transaction) = result {
|
|
519
|
-
count += 1
|
|
520
|
-
print("[RampKit] 📦 Current entitlement: \(transaction.productID), originalID: \(transaction.originalID), id: \(transaction.id)")
|
|
565
|
+
// Finish the transaction
|
|
566
|
+
await transaction.finish()
|
|
521
567
|
}
|
|
522
568
|
}
|
|
523
|
-
print("[RampKit] 🔍 Found \(count) current entitlements")
|
|
524
569
|
}
|
|
525
570
|
|
|
526
571
|
private func stopTransactionObserver() {
|
|
527
572
|
transactionObserverTask?.cancel()
|
|
528
573
|
transactionObserverTask = nil
|
|
529
574
|
isConfigured = false
|
|
530
|
-
pendingTransactions.removeAll()
|
|
531
575
|
print("[RampKit] Transaction observer stopped")
|
|
532
576
|
}
|
|
533
577
|
|
|
534
|
-
@available(iOS 15.0, *)
|
|
535
|
-
private func handleUnfinishedTransactions() async {
|
|
536
|
-
print("[RampKit] 🔍 Checking for unfinished transactions...")
|
|
537
|
-
var count = 0
|
|
538
|
-
for await result in Transaction.unfinished {
|
|
539
|
-
count += 1
|
|
540
|
-
print("[RampKit] 📦 Found unfinished transaction #\(count)")
|
|
541
|
-
await self.handleTransactionUpdate(result)
|
|
542
|
-
}
|
|
543
|
-
print("[RampKit] 🔍 Finished checking unfinished transactions. Found: \(count)")
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
@available(iOS 15.0, *)
|
|
547
|
-
private func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
|
|
548
|
-
switch result {
|
|
549
|
-
case .unverified(_, let error):
|
|
550
|
-
throw error
|
|
551
|
-
case .verified(let safe):
|
|
552
|
-
return safe
|
|
553
|
-
@unknown default:
|
|
554
|
-
fatalError("Unknown VerificationResult case")
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
578
|
@available(iOS 15.0, *)
|
|
559
579
|
private func handleTransaction(_ transaction: Transaction) async {
|
|
560
580
|
print("[RampKit] 🔄 handleTransaction called for: \(transaction.productID)")
|
package/package.json
CHANGED