@npaw/forge-react-native 9.6.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.
- package/LICENSE +10 -0
- package/NPAWForgeReactNative.podspec +44 -0
- package/README.md +51 -0
- package/android/build.gradle +77 -0
- package/android/src/main/AndroidManifest.xml +14 -0
- package/android/src/main/java/com/npaw/forge/reactnative/ForgeDtoMapper.java +295 -0
- package/android/src/main/java/com/npaw/forge/reactnative/ForgeInstanceRegistry.java +61 -0
- package/android/src/main/java/com/npaw/forge/reactnative/NPAWForgeModule.java +735 -0
- package/android/src/main/java/com/npaw/forge/reactnative/NPAWForgePackage.java +53 -0
- package/android/src/test/java/com/npaw/forge/reactnative/ForgeDtoMapperTest.java +133 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/Info.plist +82 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/Headers/ForgeKernelFFI.h +17 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/Headers/forge_kernelFFI.h +873 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/Headers/module.modulemap +7 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/libForgeKernelFFI.a +0 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/Headers/ForgeKernelFFI.h +17 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/Headers/forge_kernelFFI.h +873 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap +7 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/libForgeKernelFFI.a +0 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/Headers/ForgeKernelFFI.h +17 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/Headers/forge_kernelFFI.h +873 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/Headers/module.modulemap +7 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/libForgeKernelFFI.a +0 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/Headers/ForgeKernelFFI.h +17 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/Headers/forge_kernelFFI.h +873 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/Headers/module.modulemap +7 -0
- package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/libForgeKernelFFI.a +0 -0
- package/ios/ForgeApple/Sources/ForgeKernelUniFFI/forge_kernel.swift +3931 -0
- package/ios/ForgeApple/Sources/ForgeKernelUniFFI/forge_kernelFFI.h +873 -0
- package/ios/ForgeApple/Sources/ForgeKernelUniFFI/forge_kernelFFI.modulemap +7 -0
- package/ios/ForgeApple/Sources/NPAWForgeAVPlayerAdapter/AVPlayerAccessLogFacts.swift +152 -0
- package/ios/ForgeApple/Sources/NPAWForgeAVPlayerAdapter/AVPlayerAdapter.swift +877 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/AttributionCapture.swift +158 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/CapturePlanGate.swift +189 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/CrashCapture.swift +120 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/ForgeAutomaticCapture.swift +639 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsCapture.swift +1176 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsEngine.swift +674 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsMarkers.swift +105 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsSwiftUI.swift +284 -0
- package/ios/ForgeApple/Sources/NPAWForgeCapture/SwiftUICapture.swift +44 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/AdAdapter.swift +199 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/AdSemantics.swift +136 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeApple.swift +596 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeCapturePlan.swift +297 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeClock.swift +29 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeLogging.swift +109 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeOutcome.swift +89 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeRuntime.swift +291 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeStorage.swift +70 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ManualAdReporter.swift +180 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/NPAWForge.swift +453 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/NativeUniFFIRuntime.swift +594 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/NetworkRequestRecord.swift +191 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/ObjectiveCWrappers.swift +191 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/PlayerAdapter.swift +299 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/PlayerSemantics.swift +266 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/PrivacySanitizer.swift +59 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/VideoAdapter.swift +478 -0
- package/ios/ForgeApple/Sources/NPAWForgeCore/VideoOptions.swift +431 -0
- package/ios/ForgeApple/Sources/NPAWForgeNetworkCapture/ForgeNetworkCapture.swift +116 -0
- package/ios/ForgeApple/Sources/NPAWForgeNetworkCaptureObjC/NPAWForgeNetworkSwizzler.m +293 -0
- package/ios/ForgeApple/Sources/NPAWForgeNetworkCaptureObjC/include/NPAWForgeNetworkSwizzler.h +33 -0
- package/ios/ForgeModuleImpl.swift +1131 -0
- package/ios/NPAWForgeTurboModule.mm +399 -0
- package/package.json +33 -0
- package/src/ForgeAdReporter.ts +101 -0
- package/src/ForgeVideo.ts +169 -0
- package/src/NPAWForge.ts +177 -0
- package/src/capture.ts +192 -0
- package/src/events.ts +40 -0
- package/src/index.ts +37 -0
- package/src/specs/NativeNPAWForge.ts +168 -0
- package/src/types.ts +114 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) NPAW - All Rights Reserved
|
|
3
|
+
*
|
|
4
|
+
* This source code is protected under international copyright law. All rights
|
|
5
|
+
* reserved and protected by the copyright holders.
|
|
6
|
+
* This file is confidential and only available to authorized individuals with the
|
|
7
|
+
* permission of the copyright holders. If you encounter this file and do not have
|
|
8
|
+
* permission, please contact the copyright holders and delete this file.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @author: Victor Soto <victor.soto@nicepeopleatwork.com>
|
|
12
|
+
* @description: Typed kernel-derived Capture Plan surfaced to Apple observers. The
|
|
13
|
+
* plan tells the binding which capture observer families are worth
|
|
14
|
+
* installing (bitmask), plus the focus/limit knobs and remote behavior
|
|
15
|
+
* hints for adapters. The kernel intake gates remain the semantic
|
|
16
|
+
* authority; the plan is an optimization signal, never the only gate.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import Foundation
|
|
20
|
+
|
|
21
|
+
/// Kernel-computed capture plan delivered whenever the kernel-derived plan
|
|
22
|
+
/// hash changes (first session start onward, and after remote-config
|
|
23
|
+
/// refreshes). Test bits with ``isEnabled(_:)`` and the ``Bits`` constants.
|
|
24
|
+
public struct ForgeCapturePlan: Equatable {
|
|
25
|
+
/// Monotonic emission sequence for the runtime instance.
|
|
26
|
+
public let planSeq: UInt64
|
|
27
|
+
/// Family bitmask; see ``Bits``.
|
|
28
|
+
public let bits: UInt32
|
|
29
|
+
/// Remote config version the plan was derived from, when known.
|
|
30
|
+
public let configVersion: String?
|
|
31
|
+
public let focus: Focus
|
|
32
|
+
public let limits: Limits
|
|
33
|
+
public let behavior: Behavior
|
|
34
|
+
public let sections: Sections
|
|
35
|
+
public let attribution: Attribution
|
|
36
|
+
/// Canonical plan hash as a decimal string (full 64-bit value).
|
|
37
|
+
public let hash: String
|
|
38
|
+
|
|
39
|
+
public init(
|
|
40
|
+
planSeq: UInt64,
|
|
41
|
+
bits: UInt32,
|
|
42
|
+
configVersion: String? = nil,
|
|
43
|
+
focus: Focus,
|
|
44
|
+
limits: Limits,
|
|
45
|
+
behavior: Behavior = Behavior(),
|
|
46
|
+
sections: Sections = Sections(),
|
|
47
|
+
attribution: Attribution = Attribution(),
|
|
48
|
+
hash: String
|
|
49
|
+
) {
|
|
50
|
+
self.planSeq = planSeq
|
|
51
|
+
self.bits = bits
|
|
52
|
+
self.configVersion = configVersion
|
|
53
|
+
self.focus = focus
|
|
54
|
+
self.limits = limits
|
|
55
|
+
self.behavior = behavior
|
|
56
|
+
self.sections = sections
|
|
57
|
+
self.attribution = attribution
|
|
58
|
+
self.hash = hash
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public func isEnabled(_ bit: UInt32) -> Bool {
|
|
62
|
+
bits & bit != 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Focus observer knobs the binding needs to run dwell detection.
|
|
66
|
+
public struct Focus: Equatable {
|
|
67
|
+
public let dwellThresholdMs: Int64
|
|
68
|
+
public let dedupeMs: Int64
|
|
69
|
+
public let repeatUnchangedDwell: Bool
|
|
70
|
+
|
|
71
|
+
public init(dwellThresholdMs: Int64, dedupeMs: Int64, repeatUnchangedDwell: Bool) {
|
|
72
|
+
self.dwellThresholdMs = dwellThresholdMs
|
|
73
|
+
self.dedupeMs = dedupeMs
|
|
74
|
+
self.repeatUnchangedDwell = repeatUnchangedDwell
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Privacy-derived extraction limits applied while building payloads.
|
|
79
|
+
public struct Limits: Equatable {
|
|
80
|
+
public let maxTargetTextLength: Int
|
|
81
|
+
public let maxPayloadFields: Int
|
|
82
|
+
|
|
83
|
+
public init(maxTargetTextLength: Int, maxPayloadFields: Int) {
|
|
84
|
+
self.maxTargetTextLength = maxTargetTextLength
|
|
85
|
+
self.maxPayloadFields = maxPayloadFields
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// Remote behavior hints observed by adapters (`bh.v`); applied at the
|
|
90
|
+
/// next view start, never hot-swapped mid-view. `joinMethod` uses the
|
|
91
|
+
/// canonical tokens `ff`, `ph`, `rd`, or `auto`.
|
|
92
|
+
public struct Behavior: Equatable {
|
|
93
|
+
public let joinMethod: String?
|
|
94
|
+
public let seekHeuristicEnabled: Bool?
|
|
95
|
+
public let seekJumpThresholdMs: Int64?
|
|
96
|
+
public let metadataSamplingMs: Int64?
|
|
97
|
+
|
|
98
|
+
public init(
|
|
99
|
+
joinMethod: String? = nil,
|
|
100
|
+
seekHeuristicEnabled: Bool? = nil,
|
|
101
|
+
seekJumpThresholdMs: Int64? = nil,
|
|
102
|
+
metadataSamplingMs: Int64? = nil
|
|
103
|
+
) {
|
|
104
|
+
self.joinMethod = joinMethod
|
|
105
|
+
self.seekHeuristicEnabled = seekHeuristicEnabled
|
|
106
|
+
self.seekJumpThresholdMs = seekJumpThresholdMs
|
|
107
|
+
self.metadataSamplingMs = metadataSamplingMs
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// F3 sections auto-capture knobs (`raw_section_visible`,
|
|
112
|
+
/// `raw_section_hidden`, `raw_content_impression`, `raw_content_dwell`).
|
|
113
|
+
/// The CSS selectors are Web-only and carried purely for contract parity;
|
|
114
|
+
/// Apple discovers sections through explicit registrations,
|
|
115
|
+
/// `accessibilityIdentifier` markers, and the native-id remote lists.
|
|
116
|
+
public struct Sections: Equatable {
|
|
117
|
+
/// Minimum visible-area ratio (0-100) for a section/item to count as visible.
|
|
118
|
+
public let visibilityThresholdPct: Int
|
|
119
|
+
/// Continuous visible time an item must sustain before an impression fires.
|
|
120
|
+
public let impressionMinVisibleMs: Int64
|
|
121
|
+
/// Focus time on a tracked item before a dwell fires.
|
|
122
|
+
public let dwellMs: Int64
|
|
123
|
+
/// Maximum distinct items tracked per screen; extra targets are ignored.
|
|
124
|
+
public let maxTrackedItems: Int
|
|
125
|
+
/// Maximum distinct sections tracked per screen; extra targets are ignored.
|
|
126
|
+
public let maxSections: Int
|
|
127
|
+
/// Web-only CSS selector; never used on Apple.
|
|
128
|
+
public let sectionSelector: String?
|
|
129
|
+
/// Web-only CSS selector; never used on Apple.
|
|
130
|
+
public let itemSelector: String?
|
|
131
|
+
/// Exact `accessibilityIdentifier` matches adopted as sections.
|
|
132
|
+
public let sectionNativeIds: [String]
|
|
133
|
+
/// Exact `accessibilityIdentifier` matches adopted as items.
|
|
134
|
+
public let itemNativeIds: [String]
|
|
135
|
+
/// Remote naming hint (`auto`, `hd`, ...); Apple names come from
|
|
136
|
+
/// registrations/markers, so this stays a diagnostic passthrough.
|
|
137
|
+
public let nameFrom: String
|
|
138
|
+
|
|
139
|
+
public init(
|
|
140
|
+
visibilityThresholdPct: Int = 50,
|
|
141
|
+
impressionMinVisibleMs: Int64 = 1000,
|
|
142
|
+
dwellMs: Int64 = 1000,
|
|
143
|
+
maxTrackedItems: Int = 200,
|
|
144
|
+
maxSections: Int = 20,
|
|
145
|
+
sectionSelector: String? = nil,
|
|
146
|
+
itemSelector: String? = nil,
|
|
147
|
+
sectionNativeIds: [String] = [],
|
|
148
|
+
itemNativeIds: [String] = [],
|
|
149
|
+
nameFrom: String = "auto"
|
|
150
|
+
) {
|
|
151
|
+
self.visibilityThresholdPct = visibilityThresholdPct
|
|
152
|
+
self.impressionMinVisibleMs = impressionMinVisibleMs
|
|
153
|
+
self.dwellMs = dwellMs
|
|
154
|
+
self.maxTrackedItems = maxTrackedItems
|
|
155
|
+
self.maxSections = maxSections
|
|
156
|
+
self.sectionSelector = sectionSelector
|
|
157
|
+
self.itemSelector = itemSelector
|
|
158
|
+
self.sectionNativeIds = sectionNativeIds
|
|
159
|
+
self.itemNativeIds = itemNativeIds
|
|
160
|
+
self.nameFrom = nameFrom
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// F4 attribution auto-capture knobs (`raw_attribution`, kernel-gated by
|
|
165
|
+
/// `rc.at`). `extraQueryKeys` EXTENDS the built-in click-id list (gclid,
|
|
166
|
+
/// fbclid, ttclid, msclkid, dclid, twclid); `utm_*` handling is always on
|
|
167
|
+
/// while the family bit is enabled. The kernel's Install Referrer knob is
|
|
168
|
+
/// Android-only and intentionally not surfaced on Apple (see
|
|
169
|
+
/// ``fromUniFFIFlat``).
|
|
170
|
+
public struct Attribution: Equatable {
|
|
171
|
+
/// Extra query-parameter keys captured verbatim on top of the
|
|
172
|
+
/// built-in click-id list; never replaces `utm_*` handling.
|
|
173
|
+
public let extraQueryKeys: [String]
|
|
174
|
+
/// Whether the redacted landing/deep-link URL rides along as `utmUrl`.
|
|
175
|
+
public let includeLandingUrl: Bool
|
|
176
|
+
/// Whether incoming deep links are parsed into `raw_attribution`.
|
|
177
|
+
public let deriveFromDeepLinks: Bool
|
|
178
|
+
|
|
179
|
+
public init(
|
|
180
|
+
extraQueryKeys: [String] = [],
|
|
181
|
+
includeLandingUrl: Bool = true,
|
|
182
|
+
deriveFromDeepLinks: Bool = true
|
|
183
|
+
) {
|
|
184
|
+
self.extraQueryKeys = extraQueryKeys
|
|
185
|
+
self.includeLandingUrl = includeLandingUrl
|
|
186
|
+
self.deriveFromDeepLinks = deriveFromDeepLinks
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Frozen wire contract mirroring `forge_kernel::capture_plan::bits`;
|
|
191
|
+
/// values must never be reassigned.
|
|
192
|
+
public enum Bits {
|
|
193
|
+
public static let navigation: UInt32 = 1 << 0
|
|
194
|
+
public static let pageView: UInt32 = 1 << 1
|
|
195
|
+
public static let clicks: UInt32 = 1 << 2
|
|
196
|
+
public static let scrolls: UInt32 = 1 << 3
|
|
197
|
+
public static let lifecycle: UInt32 = 1 << 4
|
|
198
|
+
public static let deepLink: UInt32 = 1 << 5
|
|
199
|
+
public static let focus: UInt32 = 1 << 6
|
|
200
|
+
public static let remoteKey: UInt32 = 1 << 7
|
|
201
|
+
public static let errors: UInt32 = 1 << 8
|
|
202
|
+
public static let webVitals: UInt32 = 1 << 9
|
|
203
|
+
public static let network: UInt32 = 1 << 10
|
|
204
|
+
// Bit positions `1 << 11` and `1 << 12` are permanently RESERVED. They
|
|
205
|
+
// carried the removed request/response body-content capture flags. The
|
|
206
|
+
// kernel never sets them and this binding must ignore them; the
|
|
207
|
+
// positions stay unassigned so existing bits never renumber.
|
|
208
|
+
public static let sections: UInt32 = 1 << 13
|
|
209
|
+
public static let attribution: UInt32 = 1 << 14
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
extension ForgeCapturePlan {
|
|
214
|
+
/// Flat-field factory mirroring the UniFFI `AppleCapturePlan` dictionary
|
|
215
|
+
/// shape. The native runtime mapping and the plan-gating tests share it so
|
|
216
|
+
/// the typed plan and the wire dictionary cannot drift silently.
|
|
217
|
+
/// `targetDataAttributes` is a Web-only knob and is intentionally dropped
|
|
218
|
+
/// on Apple; the sections CSS selectors are carried for contract parity
|
|
219
|
+
/// but never drive Apple capture. `attributionInstallReferrerEnabled` is
|
|
220
|
+
/// accepted for the one-to-one passthrough but dropped: the Install
|
|
221
|
+
/// Referrer source is the Android Play Store API and has no Apple
|
|
222
|
+
/// counterpart, so no Apple observer can ever consume the knob.
|
|
223
|
+
static func fromUniFFIFlat(
|
|
224
|
+
planSeq: UInt64,
|
|
225
|
+
bits: UInt32,
|
|
226
|
+
configVersion: String?,
|
|
227
|
+
focusDwellThresholdMs: UInt64,
|
|
228
|
+
focusDedupeMs: UInt64,
|
|
229
|
+
focusRepeatUnchangedDwell: Bool,
|
|
230
|
+
maxTargetTextLength: UInt32,
|
|
231
|
+
maxPayloadFields: UInt32,
|
|
232
|
+
joinMethod: String?,
|
|
233
|
+
seekHeuristicEnabled: Bool?,
|
|
234
|
+
seekJumpThresholdMs: UInt64?,
|
|
235
|
+
metadataSamplingMs: UInt64?,
|
|
236
|
+
sectionsVisibilityThresholdPct: UInt32,
|
|
237
|
+
sectionsImpressionMinVisibleMs: UInt64,
|
|
238
|
+
sectionsDwellMs: UInt64,
|
|
239
|
+
sectionsMaxTrackedItems: UInt32,
|
|
240
|
+
sectionsMaxSections: UInt32,
|
|
241
|
+
sectionsSectionSelector: String?,
|
|
242
|
+
sectionsItemSelector: String?,
|
|
243
|
+
sectionsSectionNativeIds: [String],
|
|
244
|
+
sectionsItemNativeIds: [String],
|
|
245
|
+
sectionsNameFrom: String,
|
|
246
|
+
targetDataAttributes: [String],
|
|
247
|
+
attributionExtraQueryKeys: [String],
|
|
248
|
+
attributionIncludeLandingUrl: Bool,
|
|
249
|
+
attributionDeriveFromDeepLinks: Bool,
|
|
250
|
+
attributionInstallReferrerEnabled: Bool,
|
|
251
|
+
hash: String
|
|
252
|
+
) -> ForgeCapturePlan {
|
|
253
|
+
func i64(_ value: UInt64) -> Int64 {
|
|
254
|
+
value > UInt64(Int64.max) ? Int64.max : Int64(value)
|
|
255
|
+
}
|
|
256
|
+
return ForgeCapturePlan(
|
|
257
|
+
planSeq: planSeq,
|
|
258
|
+
bits: bits,
|
|
259
|
+
configVersion: configVersion,
|
|
260
|
+
focus: Focus(
|
|
261
|
+
dwellThresholdMs: i64(focusDwellThresholdMs),
|
|
262
|
+
dedupeMs: i64(focusDedupeMs),
|
|
263
|
+
repeatUnchangedDwell: focusRepeatUnchangedDwell
|
|
264
|
+
),
|
|
265
|
+
limits: Limits(
|
|
266
|
+
maxTargetTextLength: Int(maxTargetTextLength),
|
|
267
|
+
maxPayloadFields: Int(maxPayloadFields)
|
|
268
|
+
),
|
|
269
|
+
behavior: Behavior(
|
|
270
|
+
joinMethod: joinMethod,
|
|
271
|
+
seekHeuristicEnabled: seekHeuristicEnabled,
|
|
272
|
+
seekJumpThresholdMs: seekJumpThresholdMs.map(i64),
|
|
273
|
+
metadataSamplingMs: metadataSamplingMs.map(i64)
|
|
274
|
+
),
|
|
275
|
+
sections: Sections(
|
|
276
|
+
visibilityThresholdPct: Int(sectionsVisibilityThresholdPct),
|
|
277
|
+
impressionMinVisibleMs: i64(sectionsImpressionMinVisibleMs),
|
|
278
|
+
dwellMs: i64(sectionsDwellMs),
|
|
279
|
+
maxTrackedItems: Int(sectionsMaxTrackedItems),
|
|
280
|
+
maxSections: Int(sectionsMaxSections),
|
|
281
|
+
sectionSelector: sectionsSectionSelector,
|
|
282
|
+
itemSelector: sectionsItemSelector,
|
|
283
|
+
sectionNativeIds: sectionsSectionNativeIds,
|
|
284
|
+
itemNativeIds: sectionsItemNativeIds,
|
|
285
|
+
nameFrom: sectionsNameFrom
|
|
286
|
+
),
|
|
287
|
+
// attributionInstallReferrerEnabled is dropped here: Android-only
|
|
288
|
+
// (Play Install Referrer); Apple has no equivalent source.
|
|
289
|
+
attribution: Attribution(
|
|
290
|
+
extraQueryKeys: attributionExtraQueryKeys,
|
|
291
|
+
includeLandingUrl: attributionIncludeLandingUrl,
|
|
292
|
+
deriveFromDeepLinks: attributionDeriveFromDeepLinks
|
|
293
|
+
),
|
|
294
|
+
hash: hash
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) NPAW - All Rights Reserved
|
|
3
|
+
*
|
|
4
|
+
* This source code is protected under international copyright law. All rights
|
|
5
|
+
* reserved and protected by the copyright holders.
|
|
6
|
+
* This file is confidential and only available to authorized individuals with the
|
|
7
|
+
* permission of the copyright holders. If you encounter this file and do not have
|
|
8
|
+
* permission, please contact the copyright holders and delete this file.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @author: Victor Soto <victor.soto@nicepeopleatwork.com>
|
|
12
|
+
* @description: Wall-clock and monotonic timing helpers for Apple binding events.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
public enum ForgeClock {
|
|
18
|
+
public static func nowMs() -> Int64 {
|
|
19
|
+
Int64(Date().timeIntervalSince1970 * 1000)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public static func elapsedRealtimeMs() -> Int64 {
|
|
23
|
+
Int64(ProcessInfo.processInfo.systemUptime * 1000)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static func elapsedRealtimeMs(anchorTimestampMs: Int64) -> Int64 {
|
|
27
|
+
elapsedRealtimeMs()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) NPAW - All Rights Reserved
|
|
3
|
+
*
|
|
4
|
+
* This source code is protected under international copyright law. All rights
|
|
5
|
+
* reserved and protected by the copyright holders.
|
|
6
|
+
* This file is confidential and only available to authorized individuals with the
|
|
7
|
+
* permission of the copyright holders. If you encounter this file and do not have
|
|
8
|
+
* permission, please contact the copyright holders and delete this file.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @author: Victor Soto <victor.soto@nicepeopleatwork.com>
|
|
12
|
+
* @description: Apple binding log levels, families, and default platform sink.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
@objc(NPAWForgeLogLevel)
|
|
18
|
+
public enum ForgeLogLevel: Int {
|
|
19
|
+
case off
|
|
20
|
+
case error
|
|
21
|
+
case warning
|
|
22
|
+
case info
|
|
23
|
+
case debug
|
|
24
|
+
case trace
|
|
25
|
+
|
|
26
|
+
public var wireName: String {
|
|
27
|
+
switch self {
|
|
28
|
+
case .off: return "off"
|
|
29
|
+
case .error: return "error"
|
|
30
|
+
case .warning: return "warning"
|
|
31
|
+
case .info: return "info"
|
|
32
|
+
case .debug: return "debug"
|
|
33
|
+
case .trace: return "trace"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public static func from(_ value: Any?, default defaultLevel: ForgeLogLevel = .warning) -> ForgeLogLevel {
|
|
38
|
+
if let level = value as? ForgeLogLevel {
|
|
39
|
+
return level
|
|
40
|
+
}
|
|
41
|
+
guard let raw = value.map({ String(describing: $0).lowercased() }) else {
|
|
42
|
+
return defaultLevel
|
|
43
|
+
}
|
|
44
|
+
switch raw {
|
|
45
|
+
case "off": return .off
|
|
46
|
+
case "error": return .error
|
|
47
|
+
case "warn", "warning": return .warning
|
|
48
|
+
case "info": return .info
|
|
49
|
+
case "debug": return .debug
|
|
50
|
+
case "trace": return .trace
|
|
51
|
+
default: return defaultLevel
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public enum ForgeLogFamily: String {
|
|
57
|
+
case video = "Video"
|
|
58
|
+
case ad = "Ad"
|
|
59
|
+
case session = "Session"
|
|
60
|
+
case capture = "Capture"
|
|
61
|
+
case network = "Network"
|
|
62
|
+
case config = "Config"
|
|
63
|
+
case lifecycle = "Lifecycle"
|
|
64
|
+
case transport = "Transport"
|
|
65
|
+
case storage = "Storage"
|
|
66
|
+
case diagnostics = "Diagnostics"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public protocol ForgeLogSink: AnyObject {
|
|
70
|
+
func log(level: ForgeLogLevel, family: ForgeLogFamily, message: String, attributes: [String: String])
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public final class OSLogForgeLogSink: ForgeLogSink {
|
|
74
|
+
public init() {}
|
|
75
|
+
|
|
76
|
+
public func log(level: ForgeLogLevel, family: ForgeLogFamily, message: String, attributes: [String: String]) {
|
|
77
|
+
let rendered = "[\(family.rawValue)] \(message) \(attributes)"
|
|
78
|
+
guard level != .off else { return }
|
|
79
|
+
NSLog("[NPAW-Forge-Apple] %@", rendered)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public final class ForgeLogger {
|
|
84
|
+
private var level: ForgeLogLevel
|
|
85
|
+
private let sink: ForgeLogSink?
|
|
86
|
+
|
|
87
|
+
public init(level: ForgeLogLevel = .warning, sink: ForgeLogSink? = OSLogForgeLogSink()) {
|
|
88
|
+
self.level = level
|
|
89
|
+
self.sink = sink
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public func setLevel(_ level: ForgeLogLevel) {
|
|
93
|
+
self.level = level
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public func effectiveLevel() -> ForgeLogLevel {
|
|
97
|
+
level
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public func warning(family: ForgeLogFamily, action: String, details: [String: String] = [:]) {
|
|
101
|
+
guard level.rawValue >= ForgeLogLevel.warning.rawValue else { return }
|
|
102
|
+
sink?.log(level: .warning, family: family, message: action, attributes: details)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public func error(family: ForgeLogFamily, action: String, details: [String: String] = [:]) {
|
|
106
|
+
guard level.rawValue >= ForgeLogLevel.error.rawValue else { return }
|
|
107
|
+
sink?.log(level: .error, family: family, message: action, attributes: details)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) NPAW - All Rights Reserved
|
|
3
|
+
*
|
|
4
|
+
* This source code is protected under international copyright law. All rights
|
|
5
|
+
* reserved and protected by the copyright holders.
|
|
6
|
+
* This file is confidential and only available to authorized individuals with the
|
|
7
|
+
* permission of the copyright holders. If you encounter this file and do not have
|
|
8
|
+
* permission, please contact the copyright holders and delete this file.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @author: Victor Soto <victor.soto@nicepeopleatwork.com>
|
|
12
|
+
* @description: Public outcome and diagnostic types returned by the Forge Apple binding.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
@objc(NPAWForgeOutcomeCode)
|
|
18
|
+
public enum ForgeOutcomeCode: Int, Equatable {
|
|
19
|
+
case accepted
|
|
20
|
+
case deferred
|
|
21
|
+
case dropped
|
|
22
|
+
case ignoredDuplicate
|
|
23
|
+
case ignoredInvalidState
|
|
24
|
+
case blockedDependency
|
|
25
|
+
case unsupportedCapability
|
|
26
|
+
case failedWithDiagnostic
|
|
27
|
+
case ignoredBeforeSessionStart
|
|
28
|
+
|
|
29
|
+
public var wireName: String {
|
|
30
|
+
switch self {
|
|
31
|
+
case .accepted: return "accepted"
|
|
32
|
+
case .deferred: return "deferred"
|
|
33
|
+
case .dropped: return "dropped"
|
|
34
|
+
case .ignoredDuplicate: return "ignored_duplicate"
|
|
35
|
+
case .ignoredBeforeSessionStart: return "ignored_before_session_start"
|
|
36
|
+
case .ignoredInvalidState: return "ignored_invalid_state"
|
|
37
|
+
case .blockedDependency: return "blocked_dependency"
|
|
38
|
+
case .unsupportedCapability: return "unsupported_capability"
|
|
39
|
+
case .failedWithDiagnostic: return "failed_with_diagnostic"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@objc(NPAWForgeOutcome)
|
|
45
|
+
public final class ForgeOutcome: NSObject {
|
|
46
|
+
@objc public let code: ForgeOutcomeCode
|
|
47
|
+
@objc public let reason: String?
|
|
48
|
+
public let details: [String: String]
|
|
49
|
+
|
|
50
|
+
public var isAccepted: Bool { code == .accepted }
|
|
51
|
+
|
|
52
|
+
public init(code: ForgeOutcomeCode, reason: String? = nil, details: [String: String] = [:]) {
|
|
53
|
+
self.code = code
|
|
54
|
+
self.reason = reason
|
|
55
|
+
self.details = details
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@objc public static let accepted = ForgeOutcome(code: .accepted)
|
|
59
|
+
@objc public static let deferred = ForgeOutcome(code: .deferred)
|
|
60
|
+
@objc public static let dropped = ForgeOutcome(code: .dropped)
|
|
61
|
+
@objc public static let ignoredDuplicate = ForgeOutcome(code: .ignoredDuplicate)
|
|
62
|
+
@objc public static let ignoredBeforeSessionStart = ForgeOutcome(code: .ignoredBeforeSessionStart)
|
|
63
|
+
@objc public static let ignoredInvalidState = ForgeOutcome(code: .ignoredInvalidState)
|
|
64
|
+
@objc public static let blockedDependency = ForgeOutcome(code: .blockedDependency)
|
|
65
|
+
@objc public static let unsupportedCapability = ForgeOutcome(code: .unsupportedCapability)
|
|
66
|
+
|
|
67
|
+
@objc public static func failedWithDiagnostic(_ reason: String) -> ForgeOutcome {
|
|
68
|
+
ForgeOutcome(code: .failedWithDiagnostic, reason: reason)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public override var description: String {
|
|
72
|
+
if let reason {
|
|
73
|
+
return "\(code.wireName):\(reason)"
|
|
74
|
+
}
|
|
75
|
+
return code.wireName
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public struct ForgeDiagnostic: Equatable {
|
|
80
|
+
public let code: String
|
|
81
|
+
public let message: String
|
|
82
|
+
public let attributes: [String: String]
|
|
83
|
+
|
|
84
|
+
public init(code: String, message: String, attributes: [String: String] = [:]) {
|
|
85
|
+
self.code = code
|
|
86
|
+
self.message = message
|
|
87
|
+
self.attributes = attributes
|
|
88
|
+
}
|
|
89
|
+
}
|