linktrail-react-native 0.0.1

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.
@@ -0,0 +1,238 @@
1
+ import Foundation
2
+ import LinkTrailSDK
3
+
4
+ /// Swift half of the LinkTrail TurboModule. The ObjC++ module (LinkTrailModule.mm)
5
+ /// cannot call the Swift-only LinkTrailSDK directly, so this class exposes an
6
+ /// @objc surface with dictionary payloads and closure-based promises.
7
+ @objc(LinkTrailModuleImpl)
8
+ public final class LinkTrailModuleImpl: NSObject {
9
+
10
+ public typealias Resolve = (Any?) -> Void
11
+ public typealias Reject = (String, String) -> Void
12
+
13
+ /// Event sinks wired up by the ObjC++ module to the codegen emitters.
14
+ @objc public var onLink: ((NSDictionary) -> Void)?
15
+ @objc public var onAttribution: ((NSDictionary) -> Void)?
16
+ @objc public var onError: ((NSDictionary) -> Void)?
17
+
18
+ private var sdk: LinkTrailSDK.LinkTrail? { LinkTrailSDK.LinkTrail.shared }
19
+
20
+ // MARK: - Configuration
21
+
22
+ @objc public func configure(
23
+ _ apiKey: String,
24
+ options: NSDictionary?,
25
+ resolve: @escaping Resolve,
26
+ reject: @escaping Reject
27
+ ) {
28
+ do {
29
+ let sdk = try LinkTrailSDK.LinkTrail.configure(apiKey: apiKey, options: Self.parseOptions(options))
30
+ sdk.onAttribution { [weak self] attribution in
31
+ self?.onAttribution?(Self.attributionDict(attribution))
32
+ }
33
+ sdk.onLink { [weak self] link, source in
34
+ self?.onLink?([
35
+ "link": Self.deepLinkDict(link),
36
+ "source": Self.sourceName(source),
37
+ ])
38
+ }
39
+ sdk.onError { [weak self] error in
40
+ self?.onError?([
41
+ "code": Self.errorCode(error),
42
+ "message": error.localizedDescription,
43
+ ])
44
+ }
45
+ resolve(nil)
46
+ } catch {
47
+ reject(Self.errorCode(error), error.localizedDescription)
48
+ }
49
+ }
50
+
51
+ // MARK: - Install / events
52
+
53
+ @objc public func trackInstall(
54
+ _ force: Bool,
55
+ resolve: @escaping Resolve,
56
+ reject: @escaping Reject
57
+ ) {
58
+ guard let sdk = requireSDK(reject) else { return }
59
+ Task {
60
+ do {
61
+ resolve(Self.attributionDict(try await sdk.trackInstall(force: force)))
62
+ } catch {
63
+ reject(Self.errorCode(error), error.localizedDescription)
64
+ }
65
+ }
66
+ }
67
+
68
+ @objc public func trackEvent(
69
+ _ name: String,
70
+ value: NSNumber?,
71
+ currency: String?,
72
+ resolve: @escaping Resolve,
73
+ reject: @escaping Reject
74
+ ) {
75
+ guard let sdk = requireSDK(reject) else { return }
76
+ Task {
77
+ do {
78
+ let result = try await sdk.trackEvent(name: name, value: value?.doubleValue, currency: currency)
79
+ var dict: [String: Any] = ["attributed": result.attributed]
80
+ if let id = result.id { dict["id"] = id }
81
+ resolve(dict)
82
+ } catch {
83
+ reject(Self.errorCode(error), error.localizedDescription)
84
+ }
85
+ }
86
+ }
87
+
88
+ // MARK: - Deep linking
89
+
90
+ @objc public func handleDeepLink(
91
+ _ urlString: String,
92
+ resolve: @escaping Resolve,
93
+ reject: @escaping Reject
94
+ ) {
95
+ guard let sdk = requireSDK(reject) else { return }
96
+ guard let url = URL(string: urlString) else {
97
+ resolve(nil) // unparseable → not a LinkTrail link
98
+ return
99
+ }
100
+ Task {
101
+ do {
102
+ resolve(Self.deepLinkDict(try await sdk.handleDeepLink(url)))
103
+ } catch LinkTrailError.notALinkTrailURL {
104
+ resolve(nil)
105
+ } catch {
106
+ reject(Self.errorCode(error), error.localizedDescription)
107
+ }
108
+ }
109
+ }
110
+
111
+ @objc public func getLastAttribution(_ resolve: @escaping Resolve) {
112
+ resolve(sdk?.lastAttribution.map(Self.attributionDict))
113
+ }
114
+
115
+ @objc public func getLastDeepLink(_ resolve: @escaping Resolve) {
116
+ resolve(sdk?.lastDeepLink.map(Self.deepLinkDict))
117
+ }
118
+
119
+ // MARK: - ATT / SKAdNetwork
120
+
121
+ @objc public func requestTrackingAuthorization(
122
+ _ resolve: @escaping Resolve,
123
+ reject: @escaping Reject
124
+ ) {
125
+ guard let sdk = requireSDK(reject) else { return }
126
+ Task {
127
+ resolve(await sdk.requestTrackingAuthorization())
128
+ }
129
+ }
130
+
131
+ @objc public func registerForSKAdAttribution() {
132
+ sdk?.registerForSKAdAttribution()
133
+ }
134
+
135
+ @objc public func updateConversionValue(_ value: Int, coarseValue: String?) {
136
+ let coarse = coarseValue.flatMap(LinkTrailCoarseConversionValue.init(rawValue:))
137
+ sdk?.updateConversionValue(value, coarseValue: coarse)
138
+ }
139
+
140
+ // MARK: - Testing
141
+
142
+ @objc public func resetForTesting() {
143
+ LinkTrailSDK.LinkTrail.resetForTesting()
144
+ }
145
+
146
+ // MARK: - Helpers
147
+
148
+ private func requireSDK(_ reject: Reject) -> LinkTrailSDK.LinkTrail? {
149
+ guard let sdk else {
150
+ reject("not_configured", "LinkTrail is not configured. Call LinkTrail.configure(apiKey) first.")
151
+ return nil
152
+ }
153
+ return sdk
154
+ }
155
+
156
+ private static func parseOptions(_ dict: NSDictionary?) -> LinkTrailOptions {
157
+ guard let dict else { return LinkTrailOptions() }
158
+ let defaults = LinkTrailOptions()
159
+
160
+ let defaultRetry = LinkTrailRetryPolicy.default
161
+ var retryPolicy = defaultRetry
162
+ if let retry = dict["retryPolicy"] as? NSDictionary {
163
+ retryPolicy = LinkTrailRetryPolicy(
164
+ maxAttempts: (retry["maxAttempts"] as? NSNumber)?.intValue ?? defaultRetry.maxAttempts,
165
+ baseDelay: (retry["baseDelayMillis"] as? NSNumber).map { $0.doubleValue / 1000 } ?? defaultRetry.baseDelay,
166
+ maxDelay: (retry["maxDelayMillis"] as? NSNumber).map { $0.doubleValue / 1000 } ?? defaultRetry.maxDelay
167
+ )
168
+ }
169
+
170
+ return LinkTrailOptions(
171
+ logEnabled: (dict["logEnabled"] as? NSNumber)?.boolValue ?? defaults.logEnabled,
172
+ logLevel: logLevel(dict["logLevel"] as? String) ?? defaults.logLevel,
173
+ requestTimeout: (dict["requestTimeoutMillis"] as? NSNumber).map { $0.doubleValue / 1000 } ?? defaults.requestTimeout,
174
+ retryPolicy: retryPolicy,
175
+ linkDomains: (dict["linkDomains"] as? [Any])?.compactMap { $0 as? String } ?? defaults.linkDomains,
176
+ autoTrackInstall: (dict["autoTrackInstall"] as? NSNumber)?.boolValue ?? defaults.autoTrackInstall
177
+ )
178
+ }
179
+
180
+ private static func logLevel(_ name: String?) -> LinkTrailLogLevel? {
181
+ switch name {
182
+ case "debug": return .debug
183
+ case "info": return .info
184
+ case "warning": return .warning
185
+ case "error": return .error
186
+ case "none": return LinkTrailLogLevel.none
187
+ default: return nil
188
+ }
189
+ }
190
+
191
+ private static func sourceName(_ source: LinkTrailLinkSource) -> String {
192
+ switch source {
193
+ case .deferred: return "deferred"
194
+ case .reengagement: return "reengagement"
195
+ @unknown default: return "reengagement"
196
+ }
197
+ }
198
+
199
+ private static func attributionDict(_ attribution: LinkTrailAttribution) -> NSDictionary {
200
+ var dict: [String: Any] = ["attributed": attribution.attributed]
201
+ if let id = attribution.id { dict["id"] = id }
202
+ if let deepLink = attribution.deepLink { dict["deepLink"] = deepLinkDict(deepLink) }
203
+ return dict as NSDictionary
204
+ }
205
+
206
+ private static func deepLinkDict(_ link: LinkTrailDeepLink) -> NSDictionary {
207
+ var dict: [String: Any] = [
208
+ "path": link.path,
209
+ "hasRoutableDestination": link.hasRoutableDestination,
210
+ ]
211
+ if let slug = link.slug { dict["slug"] = slug }
212
+ if let url = link.url { dict["url"] = url }
213
+ if let deepLinkPath = link.deepLinkPath { dict["deepLinkPath"] = deepLinkPath }
214
+ if let iosURL = link.iosURL { dict["iosUrl"] = iosURL }
215
+ if let androidURL = link.androidURL { dict["androidUrl"] = androidURL }
216
+ if let fallbackURL = link.fallbackURL { dict["fallbackUrl"] = fallbackURL }
217
+ if let campaign = link.campaign { dict["campaign"] = campaign }
218
+ if let channel = link.channel { dict["channel"] = channel }
219
+ if let utm = link.utm { dict["utm"] = utm }
220
+ if let customData = link.customData { dict["customData"] = customData }
221
+ return dict as NSDictionary
222
+ }
223
+
224
+ private static func errorCode(_ error: Error) -> String {
225
+ guard let error = error as? LinkTrailError else { return "unknown" }
226
+ switch error {
227
+ case .invalidURL: return "invalid_url"
228
+ case .transport: return "transport"
229
+ case .server: return "server"
230
+ case .decoding: return "decoding"
231
+ case .emptyResponse: return "empty_response"
232
+ case .notALinkTrailURL: return "not_a_linktrail_url"
233
+ case .missingAPIKey: return "missing_api_key"
234
+ case .invalidAPIKey: return "invalid_api_key"
235
+ @unknown default: return "unknown"
236
+ }
237
+ }
238
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+
5
+ /**
6
+ * Codegen spec for the LinkTrail TurboModule.
7
+ *
8
+ * Payloads that cross the bridge (options, attribution, deep links, events) are
9
+ * typed as `UnsafeObject` here because their shapes contain string-keyed maps
10
+ * (`utm`, `customData`) that codegen cannot express. The public, fully-typed
11
+ * API lives in `types.ts` / `index.ts` — this module is not exported to users.
12
+ */
13
+
14
+ export default TurboModuleRegistry.getEnforcing('LinkTrail');
15
+ //# sourceMappingURL=NativeLinkTrail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeLinkTrail.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAMlD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAgDA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,WAAW,CAAC","ignoreList":[]}
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+
3
+ import { Linking } from 'react-native';
4
+ import NativeLinkTrail from "./NativeLinkTrail.js";
5
+ export * from "./types.js";
6
+ let linkingSubscription = null;
7
+ let initialUrlForwarded = false;
8
+
9
+ /** Forwards RN `Linking` URLs (initial + subsequent) to the native SDK. */
10
+ function startLinkForwarding() {
11
+ if (!initialUrlForwarded) {
12
+ initialUrlForwarded = true;
13
+ Linking.getInitialURL().then(url => url ? NativeLinkTrail.handleDeepLink(url) : null).catch(() => {
14
+ // Non-LinkTrail URLs and transport failures are reported via onError.
15
+ });
16
+ }
17
+ linkingSubscription ??= Linking.addEventListener('url', ({
18
+ url
19
+ }) => {
20
+ NativeLinkTrail.handleDeepLink(url).catch(() => {});
21
+ });
22
+ }
23
+ function stopLinkForwarding() {
24
+ linkingSubscription?.remove();
25
+ linkingSubscription = null;
26
+ }
27
+ export const LinkTrail = {
28
+ /**
29
+ * Configures the SDK with your workspace API key (`lt_live_…`). Call once at
30
+ * app launch, before any other LinkTrail API. The install is tracked
31
+ * automatically unless `options.autoTrackInstall` is `false`.
32
+ *
33
+ * Rejects with code `missing_api_key` when the key is blank.
34
+ */
35
+ async configure(apiKey, options = {}) {
36
+ const {
37
+ autoHandleLinks = true,
38
+ ...nativeOptions
39
+ } = options;
40
+ await NativeLinkTrail.configure(apiKey, nativeOptions);
41
+ if (autoHandleLinks) {
42
+ startLinkForwarding();
43
+ } else {
44
+ stopLinkForwarding();
45
+ }
46
+ },
47
+ /**
48
+ * Registers a single listener for **both** deferred deep links (first launch
49
+ * after install) and re-engagement links (app already installed) — `source`
50
+ * says which. Fires immediately if a deferred link already resolved this
51
+ * session, so registration order vs. the auto-tracked install doesn't matter.
52
+ */
53
+ onLink(listener) {
54
+ return NativeLinkTrail.onLink(payload => {
55
+ const event = payload;
56
+ listener(event.link, event.source);
57
+ });
58
+ },
59
+ /**
60
+ * Registers a listener for attribution results (attributed or organic).
61
+ * Fires immediately with the cached result if one already exists.
62
+ */
63
+ onAttribution(listener) {
64
+ return NativeLinkTrail.onAttribution(payload => {
65
+ listener(payload);
66
+ });
67
+ },
68
+ /**
69
+ * Registers a listener invoked when a fire-and-forget native operation
70
+ * (auto-tracked install, queued event, link open) fails after retries.
71
+ */
72
+ onError(listener) {
73
+ return NativeLinkTrail.onError(payload => {
74
+ listener(payload);
75
+ });
76
+ },
77
+ /**
78
+ * Sends the install event and resolves attribution. Only needed when
79
+ * `autoTrackInstall` is `false` (e.g. deferred until consent) — `configure`
80
+ * does this automatically otherwise. Already-tracked installs resolve from
81
+ * cache unless `force` is `true`.
82
+ */
83
+ trackInstall(force = false) {
84
+ return NativeLinkTrail.trackInstall(force);
85
+ },
86
+ /**
87
+ * Records a custom post-install event (purchase, signup, conversion).
88
+ * On failure the event is queued natively and retried; the returned promise
89
+ * rejects so you can observe the first failure.
90
+ */
91
+ trackEvent(name, options = {}) {
92
+ return NativeLinkTrail.trackEvent(name, options.value, options.currency);
93
+ },
94
+ /**
95
+ * Forwards an incoming URL to the SDK. Resolves with the resolved deep link,
96
+ * or `null` when the URL is not a LinkTrail link. You only need this when
97
+ * `autoHandleLinks` is `false`; routing normally happens via `onLink`.
98
+ */
99
+ handleDeepLink(url) {
100
+ return NativeLinkTrail.handleDeepLink(url);
101
+ },
102
+ /** The most recent attribution result (cached across launches), or `null`. */
103
+ getLastAttribution() {
104
+ return NativeLinkTrail.getLastAttribution();
105
+ },
106
+ /** The most recent resolved deep link from the current session, or `null`. */
107
+ getLastDeepLink() {
108
+ return NativeLinkTrail.getLastDeepLink();
109
+ },
110
+ /**
111
+ * iOS: requests App Tracking Transparency authorization (for apps using
112
+ * SKAdNetwork) and resolves with whether tracking was granted.
113
+ * Android: resolves `false`.
114
+ */
115
+ requestTrackingAuthorization() {
116
+ return NativeLinkTrail.requestTrackingAuthorization();
117
+ },
118
+ /**
119
+ * iOS: registers the app for SKAdNetwork attribution. Call early in the app
120
+ * lifecycle. Android: no-op.
121
+ */
122
+ registerForSKAdAttribution() {
123
+ NativeLinkTrail.registerForSKAdAttribution();
124
+ },
125
+ /**
126
+ * iOS: updates the SKAdNetwork conversion value for a post-install event.
127
+ * Android: no-op.
128
+ */
129
+ updateConversionValue(value, coarseValue) {
130
+ NativeLinkTrail.updateConversionValue(value, coarseValue);
131
+ },
132
+ /**
133
+ * Clears the install flag, cached attribution, queued events, and device id,
134
+ * so the next launch sends a fresh install event. Testing only.
135
+ */
136
+ resetForTesting() {
137
+ NativeLinkTrail.resetForTesting();
138
+ }
139
+ };
140
+ export default LinkTrail;
141
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Linking","NativeLinkTrail","linkingSubscription","initialUrlForwarded","startLinkForwarding","getInitialURL","then","url","handleDeepLink","catch","addEventListener","stopLinkForwarding","remove","LinkTrail","configure","apiKey","options","autoHandleLinks","nativeOptions","onLink","listener","payload","event","link","source","onAttribution","onError","trackInstall","force","trackEvent","name","value","currency","getLastAttribution","getLastDeepLink","requestTrackingAuthorization","registerForSKAdAttribution","updateConversionValue","coarseValue","resetForTesting"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,47 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import type { EventEmitter, UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
3
+ /**
4
+ * Codegen spec for the LinkTrail TurboModule.
5
+ *
6
+ * Payloads that cross the bridge (options, attribution, deep links, events) are
7
+ * typed as `UnsafeObject` here because their shapes contain string-keyed maps
8
+ * (`utm`, `customData`) that codegen cannot express. The public, fully-typed
9
+ * API lives in `types.ts` / `index.ts` — this module is not exported to users.
10
+ */
11
+ export interface Spec extends TurboModule {
12
+ /**
13
+ * Configures the native SDK. Resolves once configured; rejects with
14
+ * `missing_api_key` when the key is blank.
15
+ */
16
+ configure(apiKey: string, options?: UnsafeObject): Promise<void>;
17
+ /** Sends the install event and resolves with the attribution result. */
18
+ trackInstall(force: boolean): Promise<UnsafeObject>;
19
+ /** Records a custom post-install event; resolves with the server ack. */
20
+ trackEvent(name: string, value?: number, currency?: string): Promise<UnsafeObject>;
21
+ /**
22
+ * Handles an incoming deep-link URL. Resolves with the resolved deep link,
23
+ * or `null` when the URL is not a LinkTrail link.
24
+ */
25
+ handleDeepLink(url: string): Promise<UnsafeObject>;
26
+ /** The most recent attribution result (cached across launches), or null. */
27
+ getLastAttribution(): Promise<UnsafeObject>;
28
+ /** The most recent resolved deep link from the current session, or null. */
29
+ getLastDeepLink(): Promise<UnsafeObject>;
30
+ /** iOS: requests ATT authorization. Android: resolves `false`. */
31
+ requestTrackingAuthorization(): Promise<boolean>;
32
+ /** iOS: registers for SKAdNetwork attribution. Android: no-op. */
33
+ registerForSKAdAttribution(): void;
34
+ /** iOS: updates the SKAdNetwork conversion value. Android: no-op. */
35
+ updateConversionValue(value: number, coarseValue?: string): void;
36
+ /** Clears the install flag, cached attribution, queued events, device id. */
37
+ resetForTesting(): void;
38
+ /** Fires for both deferred and re-engagement links: `{ link, source }`. */
39
+ readonly onLink: EventEmitter<UnsafeObject>;
40
+ /** Fires with every attribution result (attributed or organic). */
41
+ readonly onAttribution: EventEmitter<UnsafeObject>;
42
+ /** Fires when a fire-and-forget native operation fails after retries. */
43
+ readonly onError: EventEmitter<UnsafeObject>;
44
+ }
45
+ declare const _default: Spec;
46
+ export default _default;
47
+ //# sourceMappingURL=NativeLinkTrail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeLinkTrail.d.ts","sourceRoot":"","sources":["../../../src/NativeLinkTrail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACb,MAAM,2CAA2C,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjE,wEAAwE;IACxE,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAEpD,yEAAyE;IACzE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAEnF;;;OAGG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAEnD,4EAA4E;IAC5E,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAE5C,4EAA4E;IAC5E,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzC,kEAAkE;IAClE,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjD,kEAAkE;IAClE,0BAA0B,IAAI,IAAI,CAAC;IAEnC,qEAAqE;IACrE,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjE,6EAA6E;IAC7E,eAAe,IAAI,IAAI,CAAC;IAExB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;IAE5C,mEAAmE;IACnE,QAAQ,CAAC,aAAa,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;IAEnD,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CAC9C;;AAED,wBAAmE"}
@@ -0,0 +1,78 @@
1
+ import type { LinkTrailAttribution, LinkTrailCoarseConversionValue, LinkTrailDeepLink, LinkTrailErrorEvent, LinkTrailEventResult, LinkTrailLinkSource, LinkTrailOptions, LinkTrailSubscription } from './types';
2
+ export * from './types';
3
+ export declare const LinkTrail: {
4
+ /**
5
+ * Configures the SDK with your workspace API key (`lt_live_…`). Call once at
6
+ * app launch, before any other LinkTrail API. The install is tracked
7
+ * automatically unless `options.autoTrackInstall` is `false`.
8
+ *
9
+ * Rejects with code `missing_api_key` when the key is blank.
10
+ */
11
+ configure(apiKey: string, options?: LinkTrailOptions): Promise<void>;
12
+ /**
13
+ * Registers a single listener for **both** deferred deep links (first launch
14
+ * after install) and re-engagement links (app already installed) — `source`
15
+ * says which. Fires immediately if a deferred link already resolved this
16
+ * session, so registration order vs. the auto-tracked install doesn't matter.
17
+ */
18
+ onLink(listener: (link: LinkTrailDeepLink, source: LinkTrailLinkSource) => void): LinkTrailSubscription;
19
+ /**
20
+ * Registers a listener for attribution results (attributed or organic).
21
+ * Fires immediately with the cached result if one already exists.
22
+ */
23
+ onAttribution(listener: (attribution: LinkTrailAttribution) => void): LinkTrailSubscription;
24
+ /**
25
+ * Registers a listener invoked when a fire-and-forget native operation
26
+ * (auto-tracked install, queued event, link open) fails after retries.
27
+ */
28
+ onError(listener: (error: LinkTrailErrorEvent) => void): LinkTrailSubscription;
29
+ /**
30
+ * Sends the install event and resolves attribution. Only needed when
31
+ * `autoTrackInstall` is `false` (e.g. deferred until consent) — `configure`
32
+ * does this automatically otherwise. Already-tracked installs resolve from
33
+ * cache unless `force` is `true`.
34
+ */
35
+ trackInstall(force?: boolean): Promise<LinkTrailAttribution>;
36
+ /**
37
+ * Records a custom post-install event (purchase, signup, conversion).
38
+ * On failure the event is queued natively and retried; the returned promise
39
+ * rejects so you can observe the first failure.
40
+ */
41
+ trackEvent(name: string, options?: {
42
+ value?: number;
43
+ currency?: string;
44
+ }): Promise<LinkTrailEventResult>;
45
+ /**
46
+ * Forwards an incoming URL to the SDK. Resolves with the resolved deep link,
47
+ * or `null` when the URL is not a LinkTrail link. You only need this when
48
+ * `autoHandleLinks` is `false`; routing normally happens via `onLink`.
49
+ */
50
+ handleDeepLink(url: string): Promise<LinkTrailDeepLink | null>;
51
+ /** The most recent attribution result (cached across launches), or `null`. */
52
+ getLastAttribution(): Promise<LinkTrailAttribution | null>;
53
+ /** The most recent resolved deep link from the current session, or `null`. */
54
+ getLastDeepLink(): Promise<LinkTrailDeepLink | null>;
55
+ /**
56
+ * iOS: requests App Tracking Transparency authorization (for apps using
57
+ * SKAdNetwork) and resolves with whether tracking was granted.
58
+ * Android: resolves `false`.
59
+ */
60
+ requestTrackingAuthorization(): Promise<boolean>;
61
+ /**
62
+ * iOS: registers the app for SKAdNetwork attribution. Call early in the app
63
+ * lifecycle. Android: no-op.
64
+ */
65
+ registerForSKAdAttribution(): void;
66
+ /**
67
+ * iOS: updates the SKAdNetwork conversion value for a post-install event.
68
+ * Android: no-op.
69
+ */
70
+ updateConversionValue(value: number, coarseValue?: LinkTrailCoarseConversionValue): void;
71
+ /**
72
+ * Clears the install flag, cached attribution, queued events, and device id,
73
+ * so the next launch sends a fresh install event. Testing only.
74
+ */
75
+ resetForTesting(): void;
76
+ };
77
+ export default LinkTrail;
78
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,cAAc,SAAS,CAAC;AAyBxB,eAAO,MAAM,SAAS;IACpB;;;;;;OAMG;sBACqB,MAAM,YAAW,gBAAgB,GAAQ,OAAO,CAAC,IAAI,CAAC;IAU9E;;;;;OAKG;qBAES,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,mBAAmB,KAAK,IAAI,GACvE,qBAAqB;IAUxB;;;OAGG;4BAES,CAAC,WAAW,EAAE,oBAAoB,KAAK,IAAI,GACpD,qBAAqB;IAMxB;;;OAGG;sBAES,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAC7C,qBAAqB;IAMxB;;;;;OAKG;mCAC0B,OAAO,CAAC,oBAAoB,CAAC;IAI1D;;;;OAIG;qBAEK,MAAM,YACH;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,oBAAoB,CAAC;IAQhC;;;;OAIG;wBACiB,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAM9D,8EAA8E;0BACxD,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAI1D,8EAA8E;uBAC3D,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAIpD;;;;OAIG;oCAC6B,OAAO,CAAC,OAAO,CAAC;IAIhD;;;OAGG;kCAC2B,IAAI;IAIlC;;;OAGG;iCAEM,MAAM,gBACC,8BAA8B,GAC3C,IAAI;IAIP;;;OAGG;uBACgB,IAAI;CAGxB,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * The deep-link payload the SDK routes on. Returned by install attribution
3
+ * (deferred deep linking), re-engagement opens, and link resolution.
4
+ */
5
+ export interface LinkTrailDeepLink {
6
+ /** The link's short slug. */
7
+ slug?: string;
8
+ /** The canonical public URL of the link. */
9
+ url?: string;
10
+ /** The in-app destination path, e.g. `/products/42`. */
11
+ deepLinkPath?: string;
12
+ iosUrl?: string;
13
+ androidUrl?: string;
14
+ fallbackUrl?: string;
15
+ campaign?: string;
16
+ channel?: string;
17
+ /** UTM parameters carried by the link. */
18
+ utm?: Record<string, string>;
19
+ /** Arbitrary key/value payload configured on the link. */
20
+ customData?: Record<string, string>;
21
+ /** The destination path to route to, defaulting to `/` when none is set. */
22
+ path: string;
23
+ /** Whether this link points at a specific destination (not the app root). */
24
+ hasRoutableDestination: boolean;
25
+ }
26
+ /** Where a delivered deep link came from. */
27
+ export type LinkTrailLinkSource = 'deferred' | 'reengagement';
28
+ /** The result of recording an install or open and attributing it. */
29
+ export interface LinkTrailAttribution {
30
+ /** Server-side event id for this install/open. */
31
+ id?: number;
32
+ /** Whether the event was matched to a click. */
33
+ attributed: boolean;
34
+ /** The resolved deep link to route on, when attributed. */
35
+ deepLink?: LinkTrailDeepLink;
36
+ }
37
+ /** The acknowledgement returned when recording a custom event. */
38
+ export interface LinkTrailEventResult {
39
+ id?: number;
40
+ attributed: boolean;
41
+ }
42
+ /** An error reported by the native SDK via the `onError` callback. */
43
+ export interface LinkTrailErrorEvent {
44
+ /**
45
+ * Stable machine-readable code: `missing_api_key`, `invalid_api_key`,
46
+ * `transport`, `server`, `decoding`, `empty_response`, `invalid_url`,
47
+ * `not_a_linktrail_url`, `not_configured`, or `unknown`.
48
+ */
49
+ code: string;
50
+ /** Human-readable description. */
51
+ message: string;
52
+ }
53
+ /** Severity levels for SDK logging, from most to least verbose. */
54
+ export type LinkTrailLogLevel = 'debug' | 'info' | 'warning' | 'error' | 'none';
55
+ /** Retry behavior for transient network failures (timeouts, 5xx, 429). */
56
+ export interface LinkTrailRetryPolicy {
57
+ /** Total attempts including the first try (1 = no retry). Default 3. */
58
+ maxAttempts?: number;
59
+ /** Base delay for exponential backoff, in milliseconds. Default 500. */
60
+ baseDelayMillis?: number;
61
+ /** Upper bound on any single backoff delay, in milliseconds. Default 8000. */
62
+ maxDelayMillis?: number;
63
+ }
64
+ /** Configuration for `LinkTrail.configure(...)`. */
65
+ export interface LinkTrailOptions {
66
+ /** Master switch for native SDK logging. Default `false`. */
67
+ logEnabled?: boolean;
68
+ /** Minimum severity to emit when logging is enabled. Default `'info'`. */
69
+ logLevel?: LinkTrailLogLevel;
70
+ /** Per-request network timeout, in milliseconds. Default 15000. */
71
+ requestTimeoutMillis?: number;
72
+ /** Retry policy applied to transient network failures. */
73
+ retryPolicy?: LinkTrailRetryPolicy;
74
+ /**
75
+ * Link hosts the SDK should treat as its own (e.g. `['go.acme.com']`).
76
+ * When non-empty, `handleDeepLink` ignores URLs on other hosts. Empty =
77
+ * handle every parseable link.
78
+ */
79
+ linkDomains?: string[];
80
+ /**
81
+ * Whether `configure` automatically sends the install event. Default `true`.
82
+ * Set `false` to defer until consent, then call `trackInstall()` manually.
83
+ */
84
+ autoTrackInstall?: boolean;
85
+ /**
86
+ * React Native-only convenience: when `true` (the default), the wrapper
87
+ * listens to the RN `Linking` API and forwards incoming URLs (including the
88
+ * initial launch URL) to the native SDK, so you don't have to call
89
+ * `handleDeepLink` yourself. Set `false` to forward URLs manually.
90
+ */
91
+ autoHandleLinks?: boolean;
92
+ }
93
+ /** SKAdNetwork 4.0+ coarse conversion value bucket (iOS only). */
94
+ export type LinkTrailCoarseConversionValue = 'low' | 'medium' | 'high';
95
+ /** A subscription returned by the event-listener APIs. */
96
+ export interface LinkTrailSubscription {
97
+ remove(): void;
98
+ }
99
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED,6CAA6C;AAC7C,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,cAAc,CAAC;AAE9D,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,sEAAsE;AACtE,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mEAAmE;AACnE,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhF,0EAA0E;AAC1E,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,mEAAmE;IACnE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0DAA0D;IAC1D,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,kEAAkE;AAClE,MAAM,MAAM,8BAA8B,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvE,0DAA0D;AAC1D,MAAM,WAAW,qBAAqB;IACpC,MAAM,IAAI,IAAI,CAAC;CAChB"}