@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,266 @@
|
|
|
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 player semantic event and metadata snapshot model.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
public enum PlayerEvent: String {
|
|
18
|
+
case initEvent = "INIT"
|
|
19
|
+
case start = "START"
|
|
20
|
+
case join = "JOIN"
|
|
21
|
+
case pause = "PAUSE"
|
|
22
|
+
case resume = "RESUME"
|
|
23
|
+
case seekBegin = "SEEK_BEGIN"
|
|
24
|
+
case seekEnd = "SEEK_END"
|
|
25
|
+
case bufferBegin = "BUFFER_BEGIN"
|
|
26
|
+
case bufferEnd = "BUFFER_END"
|
|
27
|
+
case stop = "STOP"
|
|
28
|
+
case error = "ERROR"
|
|
29
|
+
case fatalError = "FATAL_ERROR"
|
|
30
|
+
case destroy = "DESTROY"
|
|
31
|
+
case customVideoEvent = "CUSTOM_VIDEO_EVENT"
|
|
32
|
+
case customVideoEventEnd = "CUSTOM_VIDEO_EVENT_END"
|
|
33
|
+
case metadataUpdate = "METADATA_UPDATE"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public enum ContentType: String {
|
|
37
|
+
case live = "LIVE"
|
|
38
|
+
case vod = "VOD"
|
|
39
|
+
case audio = "AUDIO"
|
|
40
|
+
case unknown = "UNKNOWN"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public struct CustomVideoEventPayload: Equatable {
|
|
44
|
+
public var name: String
|
|
45
|
+
public var dimensions: [String: String]
|
|
46
|
+
public var values: [String: Double]
|
|
47
|
+
public var topLevel: [String: String]
|
|
48
|
+
public var streamKey: String?
|
|
49
|
+
public var hasEndDatetime: Bool
|
|
50
|
+
|
|
51
|
+
public init(
|
|
52
|
+
name: String,
|
|
53
|
+
dimensions: [String: String] = [:],
|
|
54
|
+
values: [String: Double] = [:],
|
|
55
|
+
topLevel: [String: String] = [:],
|
|
56
|
+
streamKey: String? = nil,
|
|
57
|
+
hasEndDatetime: Bool = false
|
|
58
|
+
) {
|
|
59
|
+
self.name = name
|
|
60
|
+
self.dimensions = dimensions
|
|
61
|
+
self.values = values
|
|
62
|
+
self.topLevel = topLevel
|
|
63
|
+
self.streamKey = streamKey
|
|
64
|
+
self.hasEndDatetime = hasEndDatetime
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public struct PlayerMetadataSnapshot: Equatable {
|
|
69
|
+
public var playerName: String
|
|
70
|
+
public var playerVersion: String?
|
|
71
|
+
public var adapterVersion: String?
|
|
72
|
+
public var resourceUrl: String?
|
|
73
|
+
public var parsedResource: String?
|
|
74
|
+
public var title: String?
|
|
75
|
+
public var program: String?
|
|
76
|
+
public var contentType: ContentType
|
|
77
|
+
public var playheadMs: Int64?
|
|
78
|
+
public var durationMs: Int64?
|
|
79
|
+
public var bitrate: Int64?
|
|
80
|
+
public var rendition: String?
|
|
81
|
+
public var videoCodec: String?
|
|
82
|
+
public var audioCodec: String?
|
|
83
|
+
public var codecProfile: String?
|
|
84
|
+
public var containerFormat: String?
|
|
85
|
+
public var errorCode: String?
|
|
86
|
+
public var errorMessage: String?
|
|
87
|
+
public var errorMetadata: String?
|
|
88
|
+
public var errorLevel: String?
|
|
89
|
+
public var forceInit: Bool?
|
|
90
|
+
public var convertFromBuffer: Bool?
|
|
91
|
+
public var convertFromSeek: Bool?
|
|
92
|
+
public var customEvent: CustomVideoEventPayload?
|
|
93
|
+
/// Legacy `param1`..`param20` content dimensions; only indices 1-20 are
|
|
94
|
+
/// transmitted. A non-empty map wins over
|
|
95
|
+
/// `__legacyContentDimension.<name>` extraParams keys entirely.
|
|
96
|
+
public var legacyCustomDimensions: [String: String]
|
|
97
|
+
/// Custom content dimensions. Values that parse as numbers become JSON
|
|
98
|
+
/// numbers core-side (same coercion as the `__contentDimension.<name>`
|
|
99
|
+
/// extraParams contract); a non-empty map wins over those overlay keys.
|
|
100
|
+
public var customDimensions: [String: String]
|
|
101
|
+
/// Numeric custom content metrics (metric surfaces are numeric-only;
|
|
102
|
+
/// non-finite values are dropped). A non-empty map wins over
|
|
103
|
+
/// `__contentMetric.<name>` extraParams keys entirely.
|
|
104
|
+
public var customMetrics: [String: Double]
|
|
105
|
+
/// Additive string-key metadata overlay forwarded to the shared Rust
|
|
106
|
+
/// core. Keys follow the same contract as the Android metadata map
|
|
107
|
+
/// (for example `contentLanguage`, `cdn`, `__contentDimension.<name>`);
|
|
108
|
+
/// typed snapshot fields always win over overlay keys.
|
|
109
|
+
public var extraParams: [String: String]
|
|
110
|
+
|
|
111
|
+
public init(
|
|
112
|
+
playerName: String,
|
|
113
|
+
playerVersion: String? = nil,
|
|
114
|
+
adapterVersion: String? = nil,
|
|
115
|
+
resourceUrl: String? = nil,
|
|
116
|
+
parsedResource: String? = nil,
|
|
117
|
+
title: String? = nil,
|
|
118
|
+
contentType: ContentType = .unknown,
|
|
119
|
+
playheadMs: Int64? = nil,
|
|
120
|
+
durationMs: Int64? = nil,
|
|
121
|
+
bitrate: Int64? = nil,
|
|
122
|
+
rendition: String? = nil,
|
|
123
|
+
videoCodec: String? = nil,
|
|
124
|
+
audioCodec: String? = nil,
|
|
125
|
+
codecProfile: String? = nil,
|
|
126
|
+
containerFormat: String? = nil,
|
|
127
|
+
errorCode: String? = nil,
|
|
128
|
+
errorMessage: String? = nil,
|
|
129
|
+
errorMetadata: String? = nil,
|
|
130
|
+
errorLevel: String? = nil,
|
|
131
|
+
forceInit: Bool? = nil,
|
|
132
|
+
convertFromBuffer: Bool? = nil,
|
|
133
|
+
convertFromSeek: Bool? = nil,
|
|
134
|
+
customEvent: CustomVideoEventPayload? = nil,
|
|
135
|
+
legacyCustomDimensions: [String: String] = [:],
|
|
136
|
+
customDimensions: [String: String] = [:],
|
|
137
|
+
customMetrics: [String: Double] = [:],
|
|
138
|
+
program: String? = nil,
|
|
139
|
+
extraParams: [String: String] = [:]
|
|
140
|
+
) {
|
|
141
|
+
self.playerName = playerName
|
|
142
|
+
self.playerVersion = playerVersion
|
|
143
|
+
self.adapterVersion = adapterVersion
|
|
144
|
+
self.resourceUrl = resourceUrl
|
|
145
|
+
self.parsedResource = parsedResource
|
|
146
|
+
self.title = title
|
|
147
|
+
self.program = program
|
|
148
|
+
self.contentType = contentType
|
|
149
|
+
self.playheadMs = playheadMs
|
|
150
|
+
self.durationMs = durationMs
|
|
151
|
+
self.bitrate = bitrate
|
|
152
|
+
self.rendition = rendition
|
|
153
|
+
self.videoCodec = videoCodec
|
|
154
|
+
self.audioCodec = audioCodec
|
|
155
|
+
self.codecProfile = codecProfile
|
|
156
|
+
self.containerFormat = containerFormat
|
|
157
|
+
self.errorCode = errorCode
|
|
158
|
+
self.errorMessage = errorMessage
|
|
159
|
+
self.errorMetadata = errorMetadata
|
|
160
|
+
self.errorLevel = errorLevel
|
|
161
|
+
self.forceInit = forceInit
|
|
162
|
+
self.convertFromBuffer = convertFromBuffer
|
|
163
|
+
self.convertFromSeek = convertFromSeek
|
|
164
|
+
self.customEvent = customEvent
|
|
165
|
+
self.legacyCustomDimensions = legacyCustomDimensions
|
|
166
|
+
self.customDimensions = customDimensions
|
|
167
|
+
self.customMetrics = customMetrics
|
|
168
|
+
self.extraParams = extraParams
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public init(
|
|
172
|
+
playerName: String,
|
|
173
|
+
playerVersion: String? = nil,
|
|
174
|
+
adapterVersion: String? = nil,
|
|
175
|
+
resourceUrl: String? = nil,
|
|
176
|
+
parsedResource: String? = nil,
|
|
177
|
+
title: String? = nil,
|
|
178
|
+
contentType: ContentType = .unknown,
|
|
179
|
+
playheadMs: Int64? = nil,
|
|
180
|
+
durationMs: Int64? = nil,
|
|
181
|
+
bitrate: Int64? = nil,
|
|
182
|
+
rendition: String? = nil,
|
|
183
|
+
videoCodec: String? = nil,
|
|
184
|
+
audioCodec: String? = nil,
|
|
185
|
+
codecProfile: String? = nil,
|
|
186
|
+
containerFormat: String? = nil,
|
|
187
|
+
errorCode: String? = nil,
|
|
188
|
+
errorMessage: String? = nil,
|
|
189
|
+
errorMetadata: String? = nil,
|
|
190
|
+
errorLevel: String? = nil,
|
|
191
|
+
forceInit: Bool? = nil,
|
|
192
|
+
convertFromBuffer: Bool? = nil,
|
|
193
|
+
convertFromSeek: Bool? = nil,
|
|
194
|
+
customEvent: CustomVideoEventPayload? = nil,
|
|
195
|
+
legacyCustomDimensions: [String: String] = [:],
|
|
196
|
+
customDimensions: [String: String] = [:],
|
|
197
|
+
customMetrics: [String: Double] = [:],
|
|
198
|
+
extraParams: [String: String] = [:]
|
|
199
|
+
) {
|
|
200
|
+
self.init(
|
|
201
|
+
playerName: playerName,
|
|
202
|
+
playerVersion: playerVersion,
|
|
203
|
+
adapterVersion: adapterVersion,
|
|
204
|
+
resourceUrl: resourceUrl,
|
|
205
|
+
parsedResource: parsedResource,
|
|
206
|
+
title: title,
|
|
207
|
+
contentType: contentType,
|
|
208
|
+
playheadMs: playheadMs,
|
|
209
|
+
durationMs: durationMs,
|
|
210
|
+
bitrate: bitrate,
|
|
211
|
+
rendition: rendition,
|
|
212
|
+
videoCodec: videoCodec,
|
|
213
|
+
audioCodec: audioCodec,
|
|
214
|
+
codecProfile: codecProfile,
|
|
215
|
+
containerFormat: containerFormat,
|
|
216
|
+
errorCode: errorCode,
|
|
217
|
+
errorMessage: errorMessage,
|
|
218
|
+
errorMetadata: errorMetadata,
|
|
219
|
+
errorLevel: errorLevel,
|
|
220
|
+
forceInit: forceInit,
|
|
221
|
+
convertFromBuffer: convertFromBuffer,
|
|
222
|
+
convertFromSeek: convertFromSeek,
|
|
223
|
+
customEvent: customEvent,
|
|
224
|
+
legacyCustomDimensions: legacyCustomDimensions,
|
|
225
|
+
customDimensions: customDimensions,
|
|
226
|
+
customMetrics: customMetrics,
|
|
227
|
+
program: nil,
|
|
228
|
+
extraParams: extraParams
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public struct QosSnapshot: Equatable {
|
|
234
|
+
public var throughput: Double?
|
|
235
|
+
public var fps: Double?
|
|
236
|
+
public var latency: Double?
|
|
237
|
+
public var playrate: Double?
|
|
238
|
+
public var droppedFrames: Int64?
|
|
239
|
+
public var totalBytes: Int64?
|
|
240
|
+
|
|
241
|
+
public init(
|
|
242
|
+
throughput: Double? = nil,
|
|
243
|
+
fps: Double? = nil,
|
|
244
|
+
latency: Double? = nil,
|
|
245
|
+
playrate: Double? = nil,
|
|
246
|
+
droppedFrames: Int64? = nil,
|
|
247
|
+
totalBytes: Int64? = nil
|
|
248
|
+
) {
|
|
249
|
+
self.throughput = throughput
|
|
250
|
+
self.fps = fps
|
|
251
|
+
self.latency = latency
|
|
252
|
+
self.playrate = playrate
|
|
253
|
+
self.droppedFrames = droppedFrames
|
|
254
|
+
self.totalBytes = totalBytes
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public struct MetadataSnapshot: Equatable {
|
|
259
|
+
public var content: PlayerMetadataSnapshot
|
|
260
|
+
public var qos: QosSnapshot?
|
|
261
|
+
|
|
262
|
+
public init(content: PlayerMetadataSnapshot, qos: QosSnapshot? = nil) {
|
|
263
|
+
self.content = content
|
|
264
|
+
self.qos = qos
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
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: Shared Apple binding privacy sanitizer for metadata, capture, and network payloads.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
public enum PrivacySanitizer {
|
|
18
|
+
private static let sensitiveFragments = [
|
|
19
|
+
"password",
|
|
20
|
+
"passwd",
|
|
21
|
+
"token",
|
|
22
|
+
"secret",
|
|
23
|
+
"authorization",
|
|
24
|
+
"auth",
|
|
25
|
+
"key",
|
|
26
|
+
"session",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
public static func sanitize(_ payload: [String: String], maxValueLength: Int = 512) -> [String: String] {
|
|
30
|
+
var output: [String: String] = [:]
|
|
31
|
+
output.reserveCapacity(payload.count)
|
|
32
|
+
for (key, value) in payload {
|
|
33
|
+
let normalized = key.lowercased()
|
|
34
|
+
if sensitiveFragments.contains(where: { normalized.contains($0) }) {
|
|
35
|
+
output[key] = "[redacted]"
|
|
36
|
+
} else {
|
|
37
|
+
output[key] = String(value.prefix(max(0, maxValueLength)))
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return output
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static func redactUrl(_ value: String, maxLength: Int = 1024) -> String {
|
|
44
|
+
guard var components = URLComponents(string: value) else {
|
|
45
|
+
return String(value.prefix(maxLength))
|
|
46
|
+
}
|
|
47
|
+
components.user = nil
|
|
48
|
+
components.password = nil
|
|
49
|
+
components.fragment = nil
|
|
50
|
+
components.queryItems = components.queryItems?.map { item in
|
|
51
|
+
let normalized = item.name.lowercased()
|
|
52
|
+
if sensitiveFragments.contains(where: { normalized.contains($0) }) {
|
|
53
|
+
return URLQueryItem(name: item.name, value: "redacted")
|
|
54
|
+
}
|
|
55
|
+
return item
|
|
56
|
+
}
|
|
57
|
+
return String((components.string ?? value).prefix(maxLength))
|
|
58
|
+
}
|
|
59
|
+
}
|