rn-linkrunner 2.10.1 → 2.11.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.
Files changed (32) hide show
  1. package/LinkrunnerSDK.podspec +1 -1
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/io/linkrunner/LinkrunnerModule.kt +37 -0
  4. package/ios/LinkrunnerSDK.m +4 -0
  5. package/ios/LinkrunnerSDK.swift +31 -4
  6. package/ios/Podfile +1 -1
  7. package/lib/commonjs/index.js +18 -0
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/module/index.js +18 -0
  10. package/lib/module/index.js.map +1 -1
  11. package/lib/typescript/index.d.ts +1 -0
  12. package/lib/typescript/index.d.ts.map +1 -1
  13. package/package.json +1 -1
  14. package/src/index.ts +22 -0
  15. package/ios/Pods/LinkrunnerKit/LICENSE +0 -21
  16. package/ios/Pods/LinkrunnerKit/README.md +0 -15
  17. package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/HmacSignatureGenerator.swift +0 -95
  18. package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/Linkrunner.swift +0 -1109
  19. package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/Models.swift +0 -356
  20. package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/RequestSigningInterceptor.swift +0 -110
  21. package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/SHA256.swift +0 -12
  22. package/ios/Pods/LinkrunnerKit/Sources/Linkrunner/SKAdNetworkService.swift +0 -428
  23. package/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -440
  24. package/ios/Pods/Pods.xcodeproj/xcuserdata/shofiyabootwala.xcuserdatad/xcschemes/LinkrunnerKit.xcscheme +0 -58
  25. package/ios/Pods/Pods.xcodeproj/xcuserdata/shofiyabootwala.xcuserdatad/xcschemes/xcschememanagement.plist +0 -16
  26. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-Info.plist +0 -26
  27. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-dummy.m +0 -5
  28. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-prefix.pch +0 -12
  29. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit-umbrella.h +0 -16
  30. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit.debug.xcconfig +0 -17
  31. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit.modulemap +0 -6
  32. package/ios/Pods/Target Support Files/LinkrunnerKit/LinkrunnerKit.release.xcconfig +0 -17
@@ -1,356 +0,0 @@
1
- import Foundation
2
-
3
- // MARK: - Error Types
4
-
5
- public enum LinkrunnerError: Error {
6
- case notInitialized
7
- case invalidUrl
8
- case httpError(Int)
9
- case apiError(String)
10
- case jsonEncodingFailed
11
- case jsonDecodingFailed
12
- case invalidResponse
13
- case invalidParameters(String)
14
- }
15
-
16
- extension LinkrunnerError: LocalizedError {
17
- public var errorDescription: String? {
18
- switch self {
19
- case .notInitialized:
20
- return "Linkrunner not initialized. Call initialize(token:) first."
21
- case .invalidUrl:
22
- return "Invalid URL"
23
- case .httpError(let code):
24
- return "HTTP error: \(code)"
25
- case .apiError(let message):
26
- return "API error: \(message)"
27
- case .jsonEncodingFailed:
28
- return "Failed to encode JSON"
29
- case .jsonDecodingFailed:
30
- return "Failed to decode JSON"
31
- case .invalidResponse:
32
- return "Invalid API response"
33
- case .invalidParameters(let message):
34
- return "Invalid parameters: \(message)"
35
- }
36
- }
37
- }
38
-
39
- // Sendable dictionary type alias
40
- public typealias SendableDictionary = [String: Any]
41
- extension SendableDictionary: @unchecked Sendable {}
42
-
43
- // MARK: - Model Types
44
-
45
- public struct UserData: Sendable {
46
- public let id: String
47
- public let name: String?
48
- public let phone: String?
49
- public let email: String?
50
- public let isFirstTimeUser: Bool?
51
- public let userCreatedAt: String?
52
- public let mixPanelDistinctId: String?
53
- public let amplitudeDeviceId: String?
54
- public let posthogDistinctId: String?
55
- public let brazeDeviceId: String?
56
- public let gaAppInstanceId: String?
57
-
58
- public init(id: String, name: String? = nil, phone: String? = nil, email: String? = nil, isFirstTimeUser: Bool? = nil, userCreatedAt: String? = nil, mixPanelDistinctId: String? = nil, amplitudeDeviceId: String? = nil, posthogDistinctId: String? = nil, brazeDeviceId: String? = nil, gaAppInstanceId: String? = nil) {
59
- self.id = id
60
- self.name = name
61
- self.phone = phone
62
- self.email = email
63
- self.isFirstTimeUser = isFirstTimeUser
64
- self.userCreatedAt = userCreatedAt
65
- self.mixPanelDistinctId = mixPanelDistinctId
66
- self.amplitudeDeviceId = amplitudeDeviceId
67
- self.posthogDistinctId = posthogDistinctId
68
- self.brazeDeviceId = brazeDeviceId
69
- self.gaAppInstanceId = gaAppInstanceId
70
- }
71
-
72
- /// Converts UserData to a dictionary, optionally hashing PII fields
73
- /// - Parameter hashPII: Whether to hash PII fields
74
- /// - Returns: Dictionary representation of UserData
75
- func toDictionary(hashPII: Bool = false) -> SendableDictionary {
76
- var dict: SendableDictionary = ["id": id]
77
-
78
- if let name = name {
79
- dict["name"] = hashPII ? LinkrunnerSDK.shared.hashWithSHA256(name) : name
80
- }
81
-
82
- if let phone = phone {
83
- dict["phone"] = hashPII ? LinkrunnerSDK.shared.hashWithSHA256(phone) : phone
84
- }
85
-
86
- if let email = email {
87
- dict["email"] = hashPII ? LinkrunnerSDK.shared.hashWithSHA256(email) : email
88
- }
89
-
90
- if let isFirstTimeUser = isFirstTimeUser {
91
- dict["is_first_time_user"] = isFirstTimeUser
92
- }
93
-
94
- if let userCreatedAt = userCreatedAt {
95
- dict["user_created_at"] = userCreatedAt
96
- }
97
-
98
- if let mixPanelDistinctId = mixPanelDistinctId {
99
- dict["mixpanel_distinct_id"] = mixPanelDistinctId
100
- }
101
-
102
- if let amplitudeDeviceId = amplitudeDeviceId {
103
- dict["amplitude_device_id"] = amplitudeDeviceId
104
- }
105
-
106
- if let posthogDistinctId = posthogDistinctId {
107
- dict["posthog_distinct_id"] = posthogDistinctId
108
- }
109
-
110
- if let brazeDeviceId = brazeDeviceId {
111
- dict["braze_device_id"] = brazeDeviceId
112
- }
113
-
114
- if let gaAppInstanceId = gaAppInstanceId {
115
- dict["ga_app_instance_id"] = gaAppInstanceId
116
- }
117
-
118
- return dict
119
- }
120
-
121
- /// Legacy dictionary property for backward compatibility
122
- var dictionary: SendableDictionary {
123
- return toDictionary(hashPII: false)
124
- }
125
- }
126
-
127
- public struct CampaignData: Codable, Sendable {
128
- public let id: String
129
- public let name: String
130
- public let type: CampaignType
131
- public let adNetwork: AdNetwork?
132
- public let groupName: String?
133
- public let assetGroupName: String?
134
- public let assetName: String?
135
- public let installedAt: Date?
136
- public let storeClickAt: Date?
137
-
138
- public enum CampaignType: String, Codable, Sendable {
139
- case organic = "ORGANIC"
140
- case inorganic = "INORGANIC"
141
- }
142
-
143
- public enum AdNetwork: String, Codable, Sendable {
144
- case meta = "META"
145
- case google = "GOOGLE"
146
- }
147
-
148
- enum CodingKeys: String, CodingKey {
149
- case id, name, type
150
- case adNetwork = "ad_network"
151
- case groupName = "group_name"
152
- case assetGroupName = "asset_group_name"
153
- case assetName = "asset_name"
154
- case installedAt = "installed_at"
155
- case storeClickAt = "store_click_at"
156
- }
157
-
158
- init(dictionary: SendableDictionary) throws {
159
- guard let id = dictionary["id"] as? String,
160
- let name = dictionary["name"] as? String,
161
- let type = dictionary["type"] as? String else {
162
- throw LinkrunnerError.invalidResponse
163
- }
164
-
165
- self.id = id
166
- self.name = name
167
- self.type = CampaignType(rawValue: type) ?? .organic
168
- self.adNetwork = (dictionary["ad_network"] as? String).flatMap { AdNetwork(rawValue: $0) }
169
- self.groupName = dictionary["group_name"] as? String
170
- self.assetGroupName = dictionary["asset_group_name"] as? String
171
- self.assetName = dictionary["asset_name"] as? String
172
-
173
- // Parse date strings
174
- let dateFormatter = ISO8601DateFormatter()
175
-
176
- if let installedAtString = dictionary["installed_at"] as? String, installedAtString != "<null>" {
177
- self.installedAt = dateFormatter.date(from: installedAtString)
178
- } else {
179
- self.installedAt = nil
180
- }
181
-
182
- if let storeClickAtString = dictionary["store_click_at"] as? String, storeClickAtString != "<null>" {
183
- self.storeClickAt = dateFormatter.date(from: storeClickAtString)
184
- } else {
185
- self.storeClickAt = nil
186
- }
187
- }
188
-
189
-
190
- public func toDictionary() -> SendableDictionary {
191
- let dateFormatter = ISO8601DateFormatter()
192
- dateFormatter.formatOptions = [.withInternetDateTime]
193
-
194
- var dict: SendableDictionary = [
195
- "id": id,
196
- "name": name,
197
- "type": type.rawValue
198
- ]
199
-
200
- if let adNetwork = adNetwork {
201
- dict["ad_network"] = adNetwork.rawValue
202
- }
203
-
204
- if let groupName = groupName {
205
- dict["group_name"] = groupName
206
- }
207
-
208
- if let assetGroupName = assetGroupName {
209
- dict["asset_group_name"] = assetGroupName
210
- }
211
-
212
- if let assetName = assetName {
213
- dict["asset_name"] = assetName
214
- }
215
-
216
- if let installedAt = installedAt {
217
- dict["installed_at"] = dateFormatter.string(from: installedAt)
218
- }
219
-
220
- if let storeClickAt = storeClickAt {
221
- dict["store_click_at"] = dateFormatter.string(from: storeClickAt)
222
- }
223
-
224
- return dict
225
- }
226
- }
227
-
228
- public struct IntegrationData: Sendable {
229
- public let clevertapId: String?
230
-
231
- public init(clevertapId: String? = nil) {
232
- self.clevertapId = clevertapId
233
- }
234
-
235
- func toDictionary() -> SendableDictionary {
236
- var dict: SendableDictionary = [:]
237
-
238
- if let clevertapId = clevertapId {
239
- dict["clevertap_id"] = clevertapId
240
- }
241
-
242
- return dict
243
- }
244
- }
245
-
246
- public enum PaymentType: String, Sendable {
247
- case firstPayment = "FIRST_PAYMENT"
248
- case secondPayment = "SECOND_PAYMENT"
249
- case walletTopup = "WALLET_TOPUP"
250
- case fundsWithdrawal = "FUNDS_WITHDRAWAL"
251
- case subscriptionCreated = "SUBSCRIPTION_CREATED"
252
- case subscriptionRenewed = "SUBSCRIPTION_RENEWED"
253
- case oneTime = "ONE_TIME"
254
- case recurring = "RECURRING"
255
- case `default` = "DEFAULT"
256
- }
257
-
258
- public enum PaymentStatus: String, Sendable {
259
- case initiated = "PAYMENT_INITIATED"
260
- case completed = "PAYMENT_COMPLETED"
261
- case failed = "PAYMENT_FAILED"
262
- case cancelled = "PAYMENT_CANCELLED"
263
- }
264
-
265
- // MARK: - API Response Models
266
-
267
- /// Response model for capture-payment endpoint
268
- public struct CapturePaymentResponse: Codable, Sendable {
269
- public let success: Bool
270
- public let message: String
271
- public let data: String?
272
-
273
- enum CodingKeys: String, CodingKey {
274
- case success
275
- case message
276
- case data
277
- }
278
- }
279
-
280
- /// Response model for capture-event endpoint
281
- public struct CaptureEventResponse: Codable, Sendable {
282
- public let success: Bool
283
- public let message: String
284
- public let data: String?
285
-
286
- enum CodingKeys: String, CodingKey {
287
- case success
288
- case message
289
- case data
290
- }
291
- }
292
-
293
- /// Response model for attribution data
294
- public struct LRAttributionDataResponse: Codable, Sendable {
295
-
296
- public let attributionSource: String
297
- public let campaignData: CampaignData?
298
- public let deeplink: String?
299
-
300
- enum CodingKeys: String, CodingKey {
301
- case attributionSource = "attribution_source"
302
- case campaignData = "campaign_data"
303
- case deeplink
304
- }
305
-
306
- // Public initializer for creating empty/default responses
307
- public init(attributionSource: String, campaignData: CampaignData?, deeplink: String?) {
308
- self.attributionSource = attributionSource
309
- self.campaignData = campaignData
310
- self.deeplink = deeplink
311
- }
312
-
313
- // Custom decoder to handle Bool/Int conversion for rootDomain
314
- public init(from decoder: Decoder) throws {
315
- let container = try decoder.container(keyedBy: CodingKeys.self)
316
-
317
- attributionSource = try container.decodeIfPresent(String.self, forKey: .attributionSource) ?? "UNKNOWN"
318
- campaignData = try container.decodeIfPresent(CampaignData.self, forKey: .campaignData)
319
- deeplink = try container.decodeIfPresent(String.self, forKey: .deeplink)
320
- }
321
-
322
- // Legacy dictionary initializer for backward compatibility
323
- init(dictionary: SendableDictionary) throws {
324
- self.attributionSource = dictionary["attribution_source"] as? String ?? "UNKNOWN"
325
-
326
- // Handle campaign_data - can be null
327
- if let campaignDataDict = dictionary["campaign_data"] as? SendableDictionary {
328
- self.campaignData = try CampaignData(dictionary: campaignDataDict)
329
- } else {
330
- self.campaignData = nil
331
- }
332
-
333
- // Handle deeplink - can be null
334
- if let deeplink = dictionary["deeplink"] as? String, deeplink != "<null>" {
335
- self.deeplink = deeplink
336
- } else {
337
- self.deeplink = nil
338
- }
339
- }
340
-
341
- public func toDictionary() -> SendableDictionary {
342
- var dict: SendableDictionary = [
343
- "attribution_source": attributionSource
344
- ]
345
-
346
- if let campaignData = campaignData {
347
- dict["campaign_data"] = campaignData.toDictionary()
348
- }
349
-
350
- if let deeplink = deeplink {
351
- dict["deeplink"] = deeplink
352
- }
353
-
354
- return dict
355
- }
356
- }
@@ -1,110 +0,0 @@
1
- import Foundation
2
-
3
- public class RequestSigningInterceptor: NSObject {
4
- // MARK: - Constants
5
- private static let AUTHORIZATION_HEADER = "Authorization"
6
- private static let TIMESTAMP_HEADER = "x-Timestamp"
7
- private static let SIGNATURE_HEADER = "x-Signature"
8
- private static let KEY_ID_HEADER = "x-Key-Id"
9
-
10
- // MARK: - Properties
11
- private var generator: HmacSignatureGenerator?
12
-
13
- // Dedicated URLSession for the SDK to avoid interference with app's networking
14
- private let sdkSession: URLSession
15
-
16
- // MARK: - Initialization
17
- public override init() {
18
- // Create a dedicated URLSession with ephemeral configuration for the SDK
19
- // This ensures it doesn't share cookies, cache or credentials with the app's sessions
20
- let config = URLSessionConfiguration.ephemeral
21
- config.timeoutIntervalForRequest = 30.0
22
-
23
- self.sdkSession = URLSession(configuration: config)
24
- super.init()
25
- }
26
-
27
-
28
- /// Configure the interceptor with the necessary credentials using raw data
29
- /// - Parameters:
30
- /// - secretKeyData: The raw secret key data
31
- /// - keyId: The key ID for signing requests
32
- public func configure(secretKey: String, keyId: String) {
33
- self.generator = HmacSignatureGenerator(secretKey: secretKey, keyId: keyId)
34
- }
35
-
36
- /// Reset the interceptor configuration
37
- public func reset() {
38
- self.generator = nil
39
- }
40
-
41
- // MARK: - Request Signing Methods
42
-
43
- /// Sign a URL request with HMAC authentication
44
- /// - Parameter request: The original request to sign
45
- /// - Returns: A signed copy of the request, or the original if signing fails or credentials aren't set
46
- public func signRequest(_ request: URLRequest) -> URLRequest {
47
- // If the generator is not configured (no credentials set), return the original request
48
- guard let generator = self.generator else {
49
- return request
50
- }
51
-
52
- // Attempt to sign the request, but don't block the request if signing fails
53
- do {
54
- var requestBody: String? = nil
55
-
56
- if let bodyData = request.httpBody {
57
- requestBody = String(data: bodyData, encoding: .utf8)
58
- }
59
-
60
- let signedData = generator.signRequest(payload: requestBody)
61
-
62
- let signedRequest = addSignatureHeaders(
63
- originalRequest: request,
64
- signature: signedData.signature,
65
- timestamp: signedData.timestamp
66
- )
67
-
68
- return signedRequest
69
- } catch {
70
- return request
71
- }
72
- }
73
-
74
- // MARK: - Private Methods
75
-
76
- /// Add signature headers to the request
77
- /// - Parameters:
78
- /// - originalRequest: The original request
79
- /// - signature: The generated signature
80
- /// - timestamp: The timestamp used for signing
81
- /// - Returns: A new request with signature headers
82
- private func addSignatureHeaders(
83
- originalRequest: URLRequest,
84
- signature: String,
85
- timestamp: Int64
86
- ) -> URLRequest {
87
- var request = originalRequest
88
- request.setValue("HMAC", forHTTPHeaderField: RequestSigningInterceptor.AUTHORIZATION_HEADER)
89
- request.setValue(generator?.signRequest(payload: nil).keyId, forHTTPHeaderField: RequestSigningInterceptor.KEY_ID_HEADER)
90
- request.setValue(String(timestamp), forHTTPHeaderField: RequestSigningInterceptor.TIMESTAMP_HEADER)
91
- request.setValue(signature, forHTTPHeaderField: RequestSigningInterceptor.SIGNATURE_HEADER)
92
- return request
93
- }
94
- }
95
-
96
- // MARK: - Request Signing Methods
97
-
98
- @available(iOS 15.0, macOS 12.0, watchOS 8.0, tvOS 15.0, *)
99
- extension RequestSigningInterceptor {
100
- /// Sign and send a request using the SDK's dedicated URLSession
101
- /// - Parameter request: The request to sign and send
102
- /// - Returns: A tuple containing Data and URLResponse
103
- public func signAndSendRequest(_ request: URLRequest) async throws -> (Data, URLResponse) {
104
- let signedRequest = signRequest(request)
105
-
106
- let (data, response) = try await sdkSession.data(for: signedRequest)
107
-
108
- return (data, response)
109
- }
110
- }
@@ -1,12 +0,0 @@
1
- import Foundation
2
- import CryptoKit
3
-
4
- /// Simple SHA-256 hashing utility for LinkrunnerSDK
5
- enum SHA256 {
6
- /// Hashes data using SHA-256 algorithm
7
- /// - Parameter data: The data to hash
8
- /// - Returns: The hashed data
9
- static func hash(data: Data) -> Data {
10
- return Data(CryptoKit.SHA256.hash(data: data))
11
- }
12
- }