@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.
Files changed (74) hide show
  1. package/LICENSE +10 -0
  2. package/NPAWForgeReactNative.podspec +44 -0
  3. package/README.md +51 -0
  4. package/android/build.gradle +77 -0
  5. package/android/src/main/AndroidManifest.xml +14 -0
  6. package/android/src/main/java/com/npaw/forge/reactnative/ForgeDtoMapper.java +295 -0
  7. package/android/src/main/java/com/npaw/forge/reactnative/ForgeInstanceRegistry.java +61 -0
  8. package/android/src/main/java/com/npaw/forge/reactnative/NPAWForgeModule.java +735 -0
  9. package/android/src/main/java/com/npaw/forge/reactnative/NPAWForgePackage.java +53 -0
  10. package/android/src/test/java/com/npaw/forge/reactnative/ForgeDtoMapperTest.java +133 -0
  11. package/ios/ForgeApple/ForgeKernelFFI.xcframework/Info.plist +82 -0
  12. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/Headers/ForgeKernelFFI.h +17 -0
  13. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/Headers/forge_kernelFFI.h +873 -0
  14. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/Headers/module.modulemap +7 -0
  15. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64/libForgeKernelFFI.a +0 -0
  16. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/Headers/ForgeKernelFFI.h +17 -0
  17. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/Headers/forge_kernelFFI.h +873 -0
  18. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap +7 -0
  19. package/ios/ForgeApple/ForgeKernelFFI.xcframework/ios-arm64_x86_64-simulator/libForgeKernelFFI.a +0 -0
  20. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/Headers/ForgeKernelFFI.h +17 -0
  21. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/Headers/forge_kernelFFI.h +873 -0
  22. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/Headers/module.modulemap +7 -0
  23. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64/libForgeKernelFFI.a +0 -0
  24. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/Headers/ForgeKernelFFI.h +17 -0
  25. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/Headers/forge_kernelFFI.h +873 -0
  26. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/Headers/module.modulemap +7 -0
  27. package/ios/ForgeApple/ForgeKernelFFI.xcframework/tvos-arm64-simulator/libForgeKernelFFI.a +0 -0
  28. package/ios/ForgeApple/Sources/ForgeKernelUniFFI/forge_kernel.swift +3931 -0
  29. package/ios/ForgeApple/Sources/ForgeKernelUniFFI/forge_kernelFFI.h +873 -0
  30. package/ios/ForgeApple/Sources/ForgeKernelUniFFI/forge_kernelFFI.modulemap +7 -0
  31. package/ios/ForgeApple/Sources/NPAWForgeAVPlayerAdapter/AVPlayerAccessLogFacts.swift +152 -0
  32. package/ios/ForgeApple/Sources/NPAWForgeAVPlayerAdapter/AVPlayerAdapter.swift +877 -0
  33. package/ios/ForgeApple/Sources/NPAWForgeCapture/AttributionCapture.swift +158 -0
  34. package/ios/ForgeApple/Sources/NPAWForgeCapture/CapturePlanGate.swift +189 -0
  35. package/ios/ForgeApple/Sources/NPAWForgeCapture/CrashCapture.swift +120 -0
  36. package/ios/ForgeApple/Sources/NPAWForgeCapture/ForgeAutomaticCapture.swift +639 -0
  37. package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsCapture.swift +1176 -0
  38. package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsEngine.swift +674 -0
  39. package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsMarkers.swift +105 -0
  40. package/ios/ForgeApple/Sources/NPAWForgeCapture/SectionsSwiftUI.swift +284 -0
  41. package/ios/ForgeApple/Sources/NPAWForgeCapture/SwiftUICapture.swift +44 -0
  42. package/ios/ForgeApple/Sources/NPAWForgeCore/AdAdapter.swift +199 -0
  43. package/ios/ForgeApple/Sources/NPAWForgeCore/AdSemantics.swift +136 -0
  44. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeApple.swift +596 -0
  45. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeCapturePlan.swift +297 -0
  46. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeClock.swift +29 -0
  47. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeLogging.swift +109 -0
  48. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeOutcome.swift +89 -0
  49. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeRuntime.swift +291 -0
  50. package/ios/ForgeApple/Sources/NPAWForgeCore/ForgeStorage.swift +70 -0
  51. package/ios/ForgeApple/Sources/NPAWForgeCore/ManualAdReporter.swift +180 -0
  52. package/ios/ForgeApple/Sources/NPAWForgeCore/NPAWForge.swift +453 -0
  53. package/ios/ForgeApple/Sources/NPAWForgeCore/NativeUniFFIRuntime.swift +594 -0
  54. package/ios/ForgeApple/Sources/NPAWForgeCore/NetworkRequestRecord.swift +191 -0
  55. package/ios/ForgeApple/Sources/NPAWForgeCore/ObjectiveCWrappers.swift +191 -0
  56. package/ios/ForgeApple/Sources/NPAWForgeCore/PlayerAdapter.swift +299 -0
  57. package/ios/ForgeApple/Sources/NPAWForgeCore/PlayerSemantics.swift +266 -0
  58. package/ios/ForgeApple/Sources/NPAWForgeCore/PrivacySanitizer.swift +59 -0
  59. package/ios/ForgeApple/Sources/NPAWForgeCore/VideoAdapter.swift +478 -0
  60. package/ios/ForgeApple/Sources/NPAWForgeCore/VideoOptions.swift +431 -0
  61. package/ios/ForgeApple/Sources/NPAWForgeNetworkCapture/ForgeNetworkCapture.swift +116 -0
  62. package/ios/ForgeApple/Sources/NPAWForgeNetworkCaptureObjC/NPAWForgeNetworkSwizzler.m +293 -0
  63. package/ios/ForgeApple/Sources/NPAWForgeNetworkCaptureObjC/include/NPAWForgeNetworkSwizzler.h +33 -0
  64. package/ios/ForgeModuleImpl.swift +1131 -0
  65. package/ios/NPAWForgeTurboModule.mm +399 -0
  66. package/package.json +33 -0
  67. package/src/ForgeAdReporter.ts +101 -0
  68. package/src/ForgeVideo.ts +169 -0
  69. package/src/NPAWForge.ts +177 -0
  70. package/src/capture.ts +192 -0
  71. package/src/events.ts +40 -0
  72. package/src/index.ts +37 -0
  73. package/src/specs/NativeNPAWForge.ts +168 -0
  74. package/src/types.ts +114 -0
package/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ Copyright (C) NPAW - All Rights Reserved
2
+
3
+ This software is protected under international copyright law. All rights
4
+ reserved and protected by the copyright holders. This software is confidential
5
+ and only available to authorized individuals with the permission of the
6
+ copyright holders. If you obtained this software and do not have permission,
7
+ please contact the copyright holders and delete it.
8
+
9
+ Use of this software requires an active NPAW commercial agreement. See
10
+ https://npaw.com for licensing and support.
@@ -0,0 +1,44 @@
1
+ # Copyright (C) NPAW - All Rights Reserved
2
+ #
3
+ # This source code is protected under international copyright law. All rights
4
+ # reserved and protected by the copyright holders. This file is confidential and
5
+ # only available to authorized individuals with the permission of the copyright
6
+ # holders. If you encounter this file and do not have permission, please contact
7
+ # the copyright holders and delete this file.
8
+ #
9
+ #
10
+ # @author: Victor Soto <victor.soto@nicepeopleatwork.com>
11
+ # @description: CocoaPods spec for the @npaw/forge-react-native core TurboModule over the Forge Apple SDK.
12
+
13
+ require "json"
14
+
15
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
16
+
17
+ Pod::Spec.new do |s|
18
+ s.name = "NPAWForgeReactNative"
19
+ s.version = package["version"]
20
+ s.summary = package["description"]
21
+ s.homepage = "https://npaw.com"
22
+ s.license = { :type => "Commercial", :text => "Copyright (C) NPAW - All Rights Reserved" }
23
+ s.authors = { "Victor Soto" => "victor.soto@nicepeopleatwork.com" }
24
+ s.platforms = { :ios => "13.0" }
25
+ s.source = { :path => "." }
26
+
27
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
28
+ s.swift_version = "5.9"
29
+
30
+ # FORGE_APPLE_CONSUMPTION BEGIN (staged: hydrated self-contained variant)
31
+ s.vendored_frameworks = "ios/ForgeApple/ForgeKernelFFI.xcframework"
32
+ s.preserve_paths = "ios/ForgeApple/**"
33
+ s.pod_target_xcconfig = {
34
+ "DEFINES_MODULE" => "YES",
35
+ "OTHER_SWIFT_FLAGS" => "$(inherited) -DFORGE_HAS_UNIFFI -DFORGE_RN_HYDRATED",
36
+ }
37
+ # FORGE_APPLE_CONSUMPTION END
38
+
39
+ if respond_to?(:install_modules_dependencies, true)
40
+ install_modules_dependencies(s)
41
+ else
42
+ s.dependency "React-Core"
43
+ end
44
+ end
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @npaw/forge-react-native
2
+
3
+ NPAW Forge analytics for React Native: application sessions, user identity,
4
+ video and ad analytics, capture, and network observation, powered by the shared
5
+ Forge analytics core through the native Android and Apple SDKs.
6
+
7
+ Use of this package requires an active NPAW commercial agreement. See
8
+ [LICENSE](./LICENSE).
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ npm install @npaw/forge-react-native
14
+ ```
15
+
16
+ Requires React Native 0.75+ with the New Architecture enabled (TurboModules).
17
+
18
+ ### iOS
19
+
20
+ ```sh
21
+ cd ios && pod install
22
+ ```
23
+
24
+ ### Android
25
+
26
+ No extra steps: the module resolves the published Forge Android coordinates.
27
+
28
+ ## Usage
29
+
30
+ ```js
31
+ import { NPAWForge } from '@npaw/forge-react-native';
32
+
33
+ const forge = await NPAWForge.create({
34
+ accountCode: '<account-code>',
35
+ appName: 'My App',
36
+ appReleaseVersion: '1.0.0',
37
+ });
38
+
39
+ await forge.startSession({ screen: 'Home' });
40
+ ```
41
+
42
+ ## Player adapters
43
+
44
+ This package reports application sessions and manual video/ad events. For
45
+ automatic playback reporting with `react-native-video`, add
46
+ [`@npaw/forge-react-native-video`](https://www.npmjs.com/package/@npaw/forge-react-native-video).
47
+
48
+ ## Documentation
49
+
50
+ Integration guides and the API reference are published at
51
+ [npaw.com](https://npaw.com).
@@ -0,0 +1,77 @@
1
+ // Copyright (C) NPAW - All Rights Reserved
2
+ //
3
+ // This source code is protected under international copyright law. All rights
4
+ // reserved and protected by the copyright holders. This file is confidential and
5
+ // only available to authorized individuals with the permission of the copyright
6
+ // holders. If you encounter this file and do not have permission, please contact
7
+ // the copyright holders and delete this file.
8
+ //
9
+ //
10
+ // @author: Victor Soto <victor.soto@nicepeopleatwork.com>
11
+ // @description: Android library build for the @npaw/forge-react-native TurboModule wrapping the published Forge Android SDK. Pure-Java module so the Kotlin-2.3-built Forge AAR imposes no Kotlin floor on host apps.
12
+
13
+ def isNewArchitectureEnabled() {
14
+ return project.hasProperty('newArchEnabled') && project.newArchEnabled == 'true'
15
+ }
16
+
17
+ apply plugin: 'com.android.library'
18
+ if (isNewArchitectureEnabled()) {
19
+ apply plugin: 'com.facebook.react'
20
+ }
21
+
22
+ def safeExtGet(prop, fallback) {
23
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
24
+ }
25
+
26
+ // Committed default stays 0.0.0; release staging rewrites it and the dev loop
27
+ // injects the locally published version via NpawForge_forgeCoreVersion or
28
+ // FORGE_CORE_VERSION (see scripts/react-native/hydrate-natives.sh).
29
+ def forgeCoreVersion = project.hasProperty('NpawForge_forgeCoreVersion')
30
+ ? project.property('NpawForge_forgeCoreVersion')
31
+ : (System.getenv('FORGE_CORE_VERSION') ?: '9.6.1')
32
+
33
+ android {
34
+ namespace 'com.npaw.forge.reactnative'
35
+ compileSdkVersion safeExtGet('compileSdkVersion', 35)
36
+
37
+ defaultConfig {
38
+ minSdkVersion safeExtGet('minSdkVersion', 23)
39
+ targetSdkVersion safeExtGet('targetSdkVersion', 34)
40
+ }
41
+
42
+ compileOptions {
43
+ sourceCompatibility JavaVersion.VERSION_17
44
+ targetCompatibility JavaVersion.VERSION_17
45
+ }
46
+
47
+ testOptions {
48
+ // android.util.Log in JVM unit tests (warn-and-ignore config paths).
49
+ unitTests.returnDefaultValues = true
50
+ }
51
+ }
52
+
53
+ repositories {
54
+ mavenCentral()
55
+ google()
56
+ def localMavenRepo = System.getenv('FORGE_LOCAL_MAVEN_REPO')
57
+ if (localMavenRepo != null && !localMavenRepo.isEmpty()) {
58
+ maven { url uri(localMavenRepo) }
59
+ }
60
+ maven { url 'https://artifact.plugin.npaw.com/artifactory/plugins/android' }
61
+ }
62
+
63
+ dependencies {
64
+ implementation 'com.facebook.react:react-native:+'
65
+ // compileOnly + runtimeOnly split: this module's javac compiles against
66
+ // the Forge classes (javac ignores Kotlin metadata), while nothing from
67
+ // the Kotlin-2.3-built Forge graph — including its kotlin-stdlib —
68
+ // reaches the host app's Kotlin COMPILE classpath. The full graph still
69
+ // flows to every runtime classpath, where newer stdlib is binary-safe.
70
+ compileOnly "com.npaw.forge:forge-android-core:${forgeCoreVersion}"
71
+ runtimeOnly "com.npaw.forge:forge-android-core:${forgeCoreVersion}"
72
+ compileOnly "com.npaw.forge:forge-android-network-capture:${forgeCoreVersion}"
73
+ runtimeOnly "com.npaw.forge:forge-android-network-capture:${forgeCoreVersion}"
74
+
75
+ testImplementation 'junit:junit:4.13.2'
76
+ testImplementation "com.npaw.forge:forge-android-core:${forgeCoreVersion}"
77
+ }
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (C) NPAW - All Rights Reserved
4
+
5
+ This source code is protected under international copyright law. All rights
6
+ reserved and protected by the copyright holders. This file is confidential and
7
+ only available to authorized individuals with the permission of the copyright
8
+ holders. If you encounter this file and do not have permission, please contact
9
+ the copyright holders and delete this file.
10
+
11
+ @author: Victor Soto <victor.soto@nicepeopleatwork.com>
12
+ @description: Manifest stub for the @npaw/forge-react-native Android library module.
13
+ -->
14
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
@@ -0,0 +1,295 @@
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: DTO conversions between React Native bridge maps and the Forge Android facade types (configs, params, outcomes, recorded events, network records).
13
+ */
14
+
15
+ package com.npaw.forge.reactnative;
16
+
17
+ import androidx.annotation.Nullable;
18
+ import com.facebook.react.bridge.Arguments;
19
+ import com.facebook.react.bridge.ReadableMap;
20
+ import com.facebook.react.bridge.WritableArray;
21
+ import com.facebook.react.bridge.WritableMap;
22
+ import com.npaw.forge.android.NPAWForge;
23
+ import com.npaw.forge.android.core.ForgeOutcome;
24
+ import com.npaw.forge.android.core.ForgeRecordedEvent;
25
+ import com.npaw.forge.android.network.NetworkRequestOutcome;
26
+ import com.npaw.forge.android.network.NetworkRequestRecord;
27
+ import com.npaw.forge.android.network.NetworkRequestSource;
28
+ import java.util.Collections;
29
+ import java.util.HashMap;
30
+ import java.util.List;
31
+ import java.util.Map;
32
+ import java.util.UUID;
33
+
34
+ public final class ForgeDtoMapper {
35
+
36
+ private ForgeDtoMapper() {}
37
+
38
+ // ---- inputs ----
39
+
40
+ public static Map<String, Object> toObjectMap(@Nullable ReadableMap map) {
41
+ if (map == null) {
42
+ return Collections.emptyMap();
43
+ }
44
+ return new HashMap<>(map.toHashMap());
45
+ }
46
+
47
+ /** Stringifies every value; the Forge params surfaces are string maps. */
48
+ public static HashMap<String, String> toStringMap(@Nullable ReadableMap map) {
49
+ HashMap<String, String> result = new HashMap<>();
50
+ if (map == null) {
51
+ return result;
52
+ }
53
+ for (Map.Entry<String, Object> entry : map.toHashMap().entrySet()) {
54
+ Object value = entry.getValue();
55
+ if (value == null) {
56
+ continue;
57
+ }
58
+ if (value instanceof Double) {
59
+ double d = (Double) value;
60
+ if (d == Math.rint(d) && !Double.isInfinite(d) && Math.abs(d) < 9.007199254740992E15) {
61
+ long asLong = (long) d;
62
+ result.put(entry.getKey(), String.valueOf(asLong));
63
+ continue;
64
+ }
65
+ }
66
+ if (value instanceof Boolean) {
67
+ result.put(entry.getKey(), ((Boolean) value) ? "true" : "false");
68
+ continue;
69
+ }
70
+ result.put(entry.getKey(), String.valueOf(value));
71
+ }
72
+ return result;
73
+ }
74
+
75
+ public static HashMap<String, Double> toDoubleMap(@Nullable ReadableMap map) {
76
+ HashMap<String, Double> result = new HashMap<>();
77
+ if (map == null) {
78
+ return result;
79
+ }
80
+ for (Map.Entry<String, Object> entry : map.toHashMap().entrySet()) {
81
+ Object value = entry.getValue();
82
+ if (value instanceof Number) {
83
+ result.put(entry.getKey(), ((Number) value).doubleValue());
84
+ }
85
+ }
86
+ return result;
87
+ }
88
+
89
+ @Nullable
90
+ public static String emptyToNull(@Nullable String value) {
91
+ return value == null || value.isEmpty() ? null : value;
92
+ }
93
+
94
+ public static void applyConfig(NPAWForge.Builder builder, @Nullable ReadableMap config) {
95
+ if (config == null) {
96
+ return;
97
+ }
98
+ for (Map.Entry<String, Object> entry : config.toHashMap().entrySet()) {
99
+ String key = entry.getKey();
100
+ Object value = entry.getValue();
101
+ if (value == null) {
102
+ continue;
103
+ }
104
+ switch (key) {
105
+ case "appName":
106
+ builder.setAppName(String.valueOf(value));
107
+ break;
108
+ case "appReleaseVersion":
109
+ builder.setAppReleaseVersion(String.valueOf(value));
110
+ break;
111
+ case "buildVariant":
112
+ builder.setBuildVariant(String.valueOf(value));
113
+ break;
114
+ case "lmaEndpoint":
115
+ builder.setLmaEndpoint(String.valueOf(value));
116
+ break;
117
+ case "analyticsUserAgent":
118
+ builder.setAnalyticsUserAgent(String.valueOf(value));
119
+ break;
120
+ case "logLevel":
121
+ builder.setLogLevel(value);
122
+ break;
123
+ case "startSessionOnInitialize":
124
+ builder.setStartSessionOnInitialize(asBoolean(value));
125
+ break;
126
+ case "processEventsBeforeSessionStart":
127
+ builder.setProcessEventsBeforeSessionStart(asBoolean(value));
128
+ break;
129
+ case "preSessionEventQueueLimitEvents":
130
+ builder.setPreSessionEventQueueLimitEvents((int) asLong(value));
131
+ break;
132
+ case "preSessionEventQueueMaxAgeMs":
133
+ builder.setPreSessionEventQueueMaxAgeMs(asLong(value));
134
+ break;
135
+ case "allowLocalHttpForTesting":
136
+ builder.setLocalPlaintextTransportForTesting(asBoolean(value));
137
+ break;
138
+ case "deviceUuid":
139
+ builder.setDeviceUuid(String.valueOf(value));
140
+ break;
141
+ case "autoDeviceIdentityEnabled":
142
+ builder.setAutoDeviceIdentityEnabled(asBoolean(value));
143
+ break;
144
+ default:
145
+ android.util.Log.w(
146
+ "NPAWForgeRN", "Unknown ForgeConfig key '" + key + "' ignored (forward compatibility)");
147
+ break;
148
+ }
149
+ }
150
+ }
151
+
152
+ public static NetworkRequestRecord toNetworkRequestRecord(ReadableMap record) {
153
+ Map<String, Object> map = record.toHashMap();
154
+ String targetUrl = stringOr(map, "targetUrl", "");
155
+ String method = stringOr(map, "method", "GET");
156
+ int responseStatusCode = (int) longOr(map, "responseStatusCode", 0L);
157
+ long durationMs = longOr(map, "durationMs", 0L);
158
+ NetworkRequestOutcome outcome = parseOutcome(stringOr(map, "outcome", "unknown"));
159
+ return new NetworkRequestRecord(
160
+ targetUrl,
161
+ method,
162
+ responseStatusCode,
163
+ durationMs,
164
+ outcome,
165
+ 0L,
166
+ UUID.randomUUID().toString(),
167
+ NetworkRequestSource.Manual,
168
+ null,
169
+ null,
170
+ nullableString(map, "responseStatusText"),
171
+ nullableString(map, "errorMessage"),
172
+ nullableString(map, "traceparent"),
173
+ nullableLong(map, "dnsDurationMs"),
174
+ nullableLong(map, "connectDurationMs"),
175
+ nullableLong(map, "sslDurationMs"),
176
+ nullableLong(map, "requestDurationMs"),
177
+ nullableLong(map, "timeToFirstByteMs"),
178
+ nullableLong(map, "responseDownloadDurationMs"),
179
+ nullableLong(map, "redirectDurationMs"),
180
+ nullableInt(map, "redirectCount"),
181
+ nullableString(map, "protocol"),
182
+ nullableLong(map, "requestBytes"),
183
+ nullableLong(map, "responseBytes"),
184
+ Collections.emptyMap(),
185
+ Collections.emptyMap());
186
+ }
187
+
188
+ // ---- outputs ----
189
+
190
+ public static WritableMap outcomeToMap(ForgeOutcome outcome) {
191
+ WritableMap result = Arguments.createMap();
192
+ result.putString("code", outcome.getCode());
193
+ result.putBoolean("isAccepted", outcome.isAccepted());
194
+ if (outcome instanceof ForgeOutcome.FailedWithDiagnostic) {
195
+ ForgeOutcome.FailedWithDiagnostic failed = (ForgeOutcome.FailedWithDiagnostic) outcome;
196
+ result.putString("reason", failed.getReason());
197
+ WritableMap details = Arguments.createMap();
198
+ for (Map.Entry<String, String> entry : failed.getDetails().entrySet()) {
199
+ details.putString(entry.getKey(), entry.getValue());
200
+ }
201
+ result.putMap("details", details);
202
+ }
203
+ return result;
204
+ }
205
+
206
+ public static WritableMap recordedEventToMap(String instanceId, ForgeRecordedEvent event) {
207
+ WritableMap result = Arguments.createMap();
208
+ result.putString("instanceId", instanceId);
209
+ result.putString("eventName", event.getEventName());
210
+ result.putDouble("timestampMs", (double) event.getTimestampMs());
211
+ WritableMap payload = Arguments.createMap();
212
+ for (Map.Entry<String, String> entry : event.getPayload().entrySet()) {
213
+ payload.putString(entry.getKey(), entry.getValue());
214
+ }
215
+ result.putMap("payload", payload);
216
+ result.putBoolean("urgent", event.getUrgent());
217
+ if (event.getViewKey() != null) {
218
+ result.putString("viewKey", event.getViewKey());
219
+ }
220
+ return result;
221
+ }
222
+
223
+ public static WritableMap snapshotToMap(String instanceId, List<ForgeRecordedEvent> events) {
224
+ WritableArray items = Arguments.createArray();
225
+ for (ForgeRecordedEvent event : events) {
226
+ items.pushMap(recordedEventToMap(instanceId, event));
227
+ }
228
+ WritableMap result = Arguments.createMap();
229
+ result.putArray("items", items);
230
+ return result;
231
+ }
232
+
233
+ // ---- helpers ----
234
+
235
+ private static boolean asBoolean(Object value) {
236
+ if (value instanceof Boolean) {
237
+ return (Boolean) value;
238
+ }
239
+ return Boolean.parseBoolean(String.valueOf(value));
240
+ }
241
+
242
+ private static long asLong(Object value) {
243
+ if (value instanceof Number) {
244
+ return ((Number) value).longValue();
245
+ }
246
+ return Long.parseLong(String.valueOf(value));
247
+ }
248
+
249
+ private static String stringOr(Map<String, Object> map, String key, String fallback) {
250
+ Object value = map.get(key);
251
+ return value == null ? fallback : String.valueOf(value);
252
+ }
253
+
254
+ private static long longOr(Map<String, Object> map, String key, long fallback) {
255
+ Object value = map.get(key);
256
+ return value instanceof Number ? ((Number) value).longValue() : fallback;
257
+ }
258
+
259
+ @Nullable
260
+ private static String nullableString(Map<String, Object> map, String key) {
261
+ Object value = map.get(key);
262
+ return value == null ? null : String.valueOf(value);
263
+ }
264
+
265
+ @Nullable
266
+ private static Long nullableLong(Map<String, Object> map, String key) {
267
+ Object value = map.get(key);
268
+ return value instanceof Number ? ((Number) value).longValue() : null;
269
+ }
270
+
271
+ @Nullable
272
+ private static Integer nullableInt(Map<String, Object> map, String key) {
273
+ Object value = map.get(key);
274
+ return value instanceof Number ? ((Number) value).intValue() : null;
275
+ }
276
+
277
+ private static NetworkRequestOutcome parseOutcome(String wireName) {
278
+ switch (wireName) {
279
+ case "success":
280
+ return NetworkRequestOutcome.Success;
281
+ case "http_error":
282
+ return NetworkRequestOutcome.HttpError;
283
+ case "network_error":
284
+ return NetworkRequestOutcome.NetworkError;
285
+ case "cancelled":
286
+ return NetworkRequestOutcome.Cancelled;
287
+ case "timeout":
288
+ return NetworkRequestOutcome.Timeout;
289
+ case "blocked":
290
+ return NetworkRequestOutcome.Blocked;
291
+ default:
292
+ return NetworkRequestOutcome.Unknown;
293
+ }
294
+ }
295
+ }
@@ -0,0 +1,61 @@
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: Process-wide registry mapping React Native instance ids to live NPAWForge facades; the compile-time seam the video package uses to reach core instances. Written in Java so the module compiles under any host-app Kotlin version despite the Kotlin-2.3-built Forge AAR.
13
+ */
14
+
15
+ package com.npaw.forge.reactnative;
16
+
17
+ import com.npaw.forge.android.NPAWForge;
18
+ import com.npaw.forge.android.video.VideoAdapter;
19
+ import java.util.ArrayList;
20
+ import java.util.HashMap;
21
+ import java.util.List;
22
+ import java.util.Map;
23
+ import java.util.concurrent.ConcurrentHashMap;
24
+ import androidx.annotation.Nullable;
25
+
26
+ public final class ForgeInstanceRegistry {
27
+
28
+ private static final ConcurrentHashMap<String, NPAWForge> INSTANCES = new ConcurrentHashMap<>();
29
+
30
+ private ForgeInstanceRegistry() {}
31
+
32
+ public static void register(String instanceId, NPAWForge forge) {
33
+ INSTANCES.put(instanceId, forge);
34
+ }
35
+
36
+ @Nullable
37
+ public static NPAWForge remove(String instanceId) {
38
+ return INSTANCES.remove(instanceId);
39
+ }
40
+
41
+ @Nullable
42
+ public static NPAWForge resolve(String instanceId) {
43
+ return INSTANCES.get(instanceId);
44
+ }
45
+
46
+ @Nullable
47
+ public static VideoAdapter resolveVideoAdapter(String instanceId, @Nullable String identifier) {
48
+ NPAWForge forge = INSTANCES.get(instanceId);
49
+ return forge == null ? null : forge.getVideoAdapter(identifier);
50
+ }
51
+
52
+ public static Map<String, NPAWForge> snapshot() {
53
+ return new HashMap<>(INSTANCES);
54
+ }
55
+
56
+ public static List<NPAWForge> clear() {
57
+ List<NPAWForge> live = new ArrayList<>(INSTANCES.values());
58
+ INSTANCES.clear();
59
+ return live;
60
+ }
61
+ }