diff --git a/Samples/iOS-Swift/iOS-Swift/Tools/iOS-Swift-Bridging-Header.h b/Samples/iOS-Swift/iOS-Swift/Tools/iOS-Swift-Bridging-Header.h index 23bb4e828bc..4c789fb0d3b 100644 --- a/Samples/iOS-Swift/iOS-Swift/Tools/iOS-Swift-Bridging-Header.h +++ b/Samples/iOS-Swift/iOS-Swift/Tools/iOS-Swift-Bridging-Header.h @@ -2,4 +2,3 @@ #import "SentryBenchmarking.h" #import "SentryExposure.h" #import -#import diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 0daf95a05ec..32d998caca0 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -202,8 +202,6 @@ 63AA76991EB9C1C200D153DE /* SentryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 63AA76951EB9C1C200D153DE /* SentryDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; 63AA769D1EB9C57A00D153DE /* SentryError.h in Headers */ = {isa = PBXBuildFile; fileRef = 63AA769B1EB9C57A00D153DE /* SentryError.h */; settings = {ATTRIBUTES = (Public, ); }; }; 63AA769E1EB9C57A00D153DE /* SentryError.mm in Sources */ = {isa = PBXBuildFile; fileRef = 63AA769C1EB9C57A00D153DE /* SentryError.mm */; }; - 63AA76A31EB9CBAA00D153DE /* SentryDsn.m in Sources */ = {isa = PBXBuildFile; fileRef = 63AA76A11EB9CBAA00D153DE /* SentryDsn.m */; }; - 63AA76A51EB9CBC200D153DE /* SentryDsn.h in Headers */ = {isa = PBXBuildFile; fileRef = 63AA76A41EB9CBC200D153DE /* SentryDsn.h */; settings = {ATTRIBUTES = (Public, ); }; }; 63AF656C1ED87B8C00EBCFF7 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6304360D1EC05CEF00C4D3FA /* libz.tbd */; }; 63B818F91EC34639002FDF4C /* SentryDebugMeta.h in Headers */ = {isa = PBXBuildFile; fileRef = 63B818F71EC34639002FDF4C /* SentryDebugMeta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 63B818FA1EC34639002FDF4C /* SentryDebugMeta.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B818F81EC34639002FDF4C /* SentryDebugMeta.m */; }; @@ -734,9 +732,9 @@ A8AFFCD42907E0CA00967CD7 /* SentryRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8AFFCD32907E0CA00967CD7 /* SentryRequestTests.swift */; }; A8F17B2E2901765900990B25 /* SentryRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B2D2901765900990B25 /* SentryRequest.m */; }; A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */; }; + AEA159B02EDDF6AD000D37E2 /* SentryDsn.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEA159AF2EDDF6AD000D37E2 /* SentryDsn.swift */; }; D4009EB22D771BC20007AF30 /* SentryFileIOTrackerSwiftHelpersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4009EB12D771BB90007AF30 /* SentryFileIOTrackerSwiftHelpersTests.swift */; }; D41415A72DEEE532003B14D5 /* SentryRedactViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41415A62DEEE532003B14D5 /* SentryRedactViewHelper.swift */; }; - D4237B3D2EB39D9700FE027C /* SentryDsn+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D4237B3C2EB39D9700FE027C /* SentryDsn+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; D4291A6D2DD62ACE00772088 /* SentryDispatchFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4291A6C2DD62AC800772088 /* SentryDispatchFactoryTests.m */; }; D42ADEEF2E9CF43200753166 /* SentrySessionReplayEnvironmentChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42ADEE92E9CF42800753166 /* SentrySessionReplayEnvironmentChecker.swift */; }; D42ADF372E9CF95700753166 /* SentrySessionReplayEnvironmentCheckerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42ADF362E9CF95500753166 /* SentrySessionReplayEnvironmentCheckerProvider.swift */; }; @@ -1491,8 +1489,6 @@ 63AA76951EB9C1C200D153DE /* SentryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryDefines.h; path = Public/SentryDefines.h; sourceTree = ""; }; 63AA769B1EB9C57A00D153DE /* SentryError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryError.h; path = Public/SentryError.h; sourceTree = ""; }; 63AA769C1EB9C57A00D153DE /* SentryError.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryError.mm; sourceTree = ""; }; - 63AA76A11EB9CBAA00D153DE /* SentryDsn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentryDsn.m; sourceTree = ""; }; - 63AA76A41EB9CBC200D153DE /* SentryDsn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryDsn.h; path = Public/SentryDsn.h; sourceTree = ""; }; 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SentryTests.xcconfig; sourceTree = ""; }; 63B818F71EC34639002FDF4C /* SentryDebugMeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryDebugMeta.h; path = Public/SentryDebugMeta.h; sourceTree = ""; }; 63B818F81EC34639002FDF4C /* SentryDebugMeta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SentryDebugMeta.m; sourceTree = ""; }; @@ -2092,11 +2088,11 @@ A8AFFCD32907E0CA00967CD7 /* SentryRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRequestTests.swift; sourceTree = ""; }; A8F17B2D2901765900990B25 /* SentryRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryRequest.m; sourceTree = ""; }; A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryHttpStatusCodeRange.m; sourceTree = ""; }; + AEA159AF2EDDF6AD000D37E2 /* SentryDsn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryDsn.swift; sourceTree = ""; }; D4009EB12D771BB90007AF30 /* SentryFileIOTrackerSwiftHelpersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryFileIOTrackerSwiftHelpersTests.swift; sourceTree = ""; }; D41415A62DEEE532003B14D5 /* SentryRedactViewHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRedactViewHelper.swift; sourceTree = ""; }; D41909922D48FFF6002B83D0 /* SentryNSDictionarySanitize+Tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryNSDictionarySanitize+Tests.h"; sourceTree = ""; }; D41909942D490006002B83D0 /* SentryNSDictionarySanitize+Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SentryNSDictionarySanitize+Tests.m"; sourceTree = ""; }; - D4237B3C2EB39D9700FE027C /* SentryDsn+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryDsn+Private.h"; path = "include/SentryDsn+Private.h"; sourceTree = ""; }; D4291A6C2DD62AC800772088 /* SentryDispatchFactoryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryDispatchFactoryTests.m; sourceTree = ""; }; D42ADEE92E9CF42800753166 /* SentrySessionReplayEnvironmentChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySessionReplayEnvironmentChecker.swift; sourceTree = ""; }; D42ADF362E9CF95500753166 /* SentrySessionReplayEnvironmentCheckerProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySessionReplayEnvironmentCheckerProvider.swift; sourceTree = ""; }; @@ -2732,8 +2728,6 @@ 7BAF3DCD243DCBFE008A5414 /* SentryTransportFactory.m */, 635B3F361EBC6E2500A6176D /* SentryAsynchronousOperation.h */, 635B3F371EBC6E2500A6176D /* SentryAsynchronousOperation.m */, - 63AA76A41EB9CBC200D153DE /* SentryDsn.h */, - 63AA76A11EB9CBAA00D153DE /* SentryDsn.m */, 7B5CAF7427F5A67C00ED0DB6 /* SentryNSURLRequestBuilder.h */, 7B5CAF7627F5A68C00ED0DB6 /* SentryNSURLRequestBuilder.m */, 7BAF3DD82440AEC8008A5414 /* SentryRequestManager.h */, @@ -3112,7 +3106,6 @@ 63AA76941EB9C1C200D153DE /* SentryClient.h */, 63AA75ED1EB8B3C400D153DE /* SentryClient.m */, 7B85DC1C24EFAFCD007D01D2 /* SentryClient+Private.h */, - D4237B3C2EB39D9700FE027C /* SentryDsn+Private.h */, 7B610D5E2512390E00B0B5D9 /* SentrySDK+Private.h */, FA6555132E30181B009917BC /* SentrySDKInternal.h */, FA6555152E30182B009917BC /* SentrySDKInternal.m */, @@ -4453,6 +4446,7 @@ D800942328F82E8D005D3943 /* Swift */ = { isa = PBXGroup; children = ( + AEA159AF2EDDF6AD000D37E2 /* SentryDsn.swift */, FAAB95CC2EA18B260030A2DB /* SentryDependencyContainer.swift */, FAAB95B92EA1633E0030A2DB /* State */, FA560F5A2E8C876A00F2AF7F /* SentryAppStateManager.swift */, @@ -5336,7 +5330,6 @@ 9286059529A5096600F96038 /* SentryGeo.h in Headers */, 7B98D7BC25FB607300C5A389 /* SentryWatchdogTerminationTracker.h in Headers */, 8E4E7C7D25DAB287006AB9E2 /* SentryTracer.h in Headers */, - D4237B3D2EB39D9700FE027C /* SentryDsn+Private.h in Headers */, 7BC8523724588115005A70F0 /* SentryDataCategory.h in Headers */, FAAB96482EA6843E0030A2DB /* SentryANRTrackerInternalDelegate.h in Headers */, FA8A36182DEAA1EB0058D883 /* SentryThread+Private.h in Headers */, @@ -5357,7 +5350,6 @@ 848A451E2BBF9504006AAAEC /* SentryProfilerTestHelpers.h in Headers */, 639FCF9C1EBC7F9500778193 /* SentryThread.h in Headers */, 63FE716B20DA4C1100CDBAE8 /* SentryCrashJSONCodecObjC.h in Headers */, - 63AA76A51EB9CBC200D153DE /* SentryDsn.h in Headers */, 844EDD6C2949387000C86F34 /* SentryMetricProfiler.h in Headers */, F452438A2DE65968003E8F50 /* ExceptionCatcher.h in Headers */, 636085131ED47BE600E8599E /* SentryFileManagerHelper.h in Headers */, @@ -5756,7 +5748,6 @@ FAAB2F972E4D345800FE8B7E /* SentryUIDeviceWrapper.swift in Sources */, 7B6438AB26A70F24000D0F65 /* UIViewController+Sentry.m in Sources */, 84302A812B5767A50027A629 /* SentryLaunchProfiling.m in Sources */, - 63AA76A31EB9CBAA00D153DE /* SentryDsn.m in Sources */, D490648A2DFAE1F600555785 /* SentryScreenshotOptions.swift in Sources */, FA6FC0AA2E0B6B1100ED2669 /* SentrySdkInfo.swift in Sources */, FA560F602E8C877200F2AF7F /* SentryAppStateManager.swift in Sources */, @@ -6148,6 +6139,7 @@ 620379DD2AFE1432005AC0C1 /* SentryBuildAppStartSpans.m in Sources */, 6292585F2DAFA8290049388F /* SentryCrashMach-O.c in Sources */, 7B77BE3727EC8460003C9020 /* SentryDiscardReasonMapper.m in Sources */, + AEA159B02EDDF6AD000D37E2 /* SentryDsn.swift in Sources */, 63FE712520DA4C1000CDBAE8 /* SentryCrashSignalInfo.c in Sources */, 63FE70F320DA4C1000CDBAE8 /* SentryCrashMonitor_Signal.c in Sources */, D859696F27BECDA20036A46E /* SentryCoreDataTracker.m in Sources */, diff --git a/Sources/Sentry/Public/Sentry.h b/Sources/Sentry/Public/Sentry.h index b9d7865725d..9e054a768ef 100644 --- a/Sources/Sentry/Public/Sentry.h +++ b/Sources/Sentry/Public/Sentry.h @@ -13,7 +13,6 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; # import # import # import -# import # import # import # import diff --git a/Sources/Sentry/Public/SentryDsn.h b/Sources/Sentry/Public/SentryDsn.h deleted file mode 100644 index 758dd269b52..00000000000 --- a/Sources/Sentry/Public/SentryDsn.h +++ /dev/null @@ -1,16 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface SentryDsn : NSObject - -@property (nonatomic, strong, readonly) NSURL *url; - -- (_Nullable instancetype)initWithString:(NSString *_Nullable)dsnString - didFailWithError:(NSError *_Nullable *_Nullable)error; - -- (NSURL *)getEnvelopeEndpoint; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/Public/SentryWithoutUIKit.h b/Sources/Sentry/Public/SentryWithoutUIKit.h index f007ec74633..686803c62fc 100644 --- a/Sources/Sentry/Public/SentryWithoutUIKit.h +++ b/Sources/Sentry/Public/SentryWithoutUIKit.h @@ -14,7 +14,6 @@ FOUNDATION_EXPORT const unsigned char SentryVersionString[]; # import # import # import -# import # import # import # import diff --git a/Sources/Sentry/SentryBaggage.m b/Sources/Sentry/SentryBaggage.m index 6b0615ef7e7..98065af5156 100644 --- a/Sources/Sentry/SentryBaggage.m +++ b/Sources/Sentry/SentryBaggage.m @@ -1,5 +1,4 @@ #import "SentryBaggage.h" -#import "SentryDsn.h" #import "SentryLogC.h" #import "SentryScope+Private.h" #import "SentrySwift.h" diff --git a/Sources/Sentry/SentryClient.m b/Sources/Sentry/SentryClient.m index a578cf25ff2..d04c0892681 100644 --- a/Sources/Sentry/SentryClient.m +++ b/Sources/Sentry/SentryClient.m @@ -7,7 +7,6 @@ #import "SentryCrashStackEntryMapper.h" #import "SentryDefaultThreadInspector.h" #import "SentryDeviceContextKeys.h" -#import "SentryDsn.h" #import "SentryEvent+Private.h" #import "SentryException.h" #import "SentryInstallation.h" diff --git a/Sources/Sentry/SentryDsn.m b/Sources/Sentry/SentryDsn.m deleted file mode 100644 index 1b5e6af6584..00000000000 --- a/Sources/Sentry/SentryDsn.m +++ /dev/null @@ -1,119 +0,0 @@ -#import - -#import "SentryDsn.h" -#import "SentryError.h" -#import "SentryInternalDefines.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface SentryDsn () - -@end - -@implementation SentryDsn { - NSURL *_envelopeEndpoint; -} - -- (_Nullable instancetype)initWithString:(NSString *_Nullable)dsnString - didFailWithError:(NSError *_Nullable *_Nullable)error -{ - self = [super init]; - if (self) { - NSURL *_Nullable nullableUrl = [self convertDsnString:dsnString didFailWithError:error]; - if (nullableUrl == nil) { - return nil; - } - _url = SENTRY_UNWRAP_NULLABLE(NSURL, nullableUrl); - } - return self; -} - -- (NSString *)getHash -{ - NSData *data = [[self.url absoluteString] dataUsingEncoding:NSUTF8StringEncoding]; - uint8_t digest[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(data.bytes, (CC_LONG)data.length, digest); - NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2]; - for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) { - [output appendFormat:@"%02x", digest[i]]; - } - return output; -} - -- (NSURL *)getEnvelopeEndpoint -{ - if (nil == _envelopeEndpoint) { - @synchronized(self) { - if (nil == _envelopeEndpoint) { - _envelopeEndpoint = - [[self getBaseEndpoint] URLByAppendingPathComponent:@"envelope/"]; - } - } - } - return _envelopeEndpoint; -} - -- (NSURL *)getBaseEndpoint -{ - NSURL *url = self.url; - NSString *projectId = url.lastPathComponent; - NSMutableArray *paths = [url.pathComponents mutableCopy]; - // [0] = / - // [1] = projectId - // If there are more than two, that means someone wants to have an - // additional path ref: https://github.com/getsentry/sentry-cocoa/issues/236 - NSString *path = @""; - if ([paths count] > 2) { - [paths removeObjectAtIndex:0]; // We remove the leading / - [paths removeLastObject]; // We remove projectId since we add it later - path = [NSString stringWithFormat:@"/%@", - [paths componentsJoinedByString:@"/"]]; // We put together the path - } - NSURLComponents *components = [NSURLComponents new]; - components.scheme = url.scheme; - components.host = url.host; - components.port = url.port; - components.path = [NSString stringWithFormat:@"%@/api/%@/", path, projectId]; - return SENTRY_UNWRAP_NULLABLE(NSURL, components.URL); -} - -- (NSURL *_Nullable)convertDsnString:(NSString *_Nullable)dsnString - didFailWithError:(NSError *_Nullable *_Nullable)error -{ - NSString *trimmedDsnString = [dsnString - stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - NSSet *allowedSchemes = [NSSet setWithObjects:@"http", @"https", nil]; - NSURL *url = [NSURL URLWithString:trimmedDsnString]; - NSString *errorMessage = nil; - if (url.scheme == nil) { - errorMessage = @"URL scheme of DSN is missing"; - url = nil; - } - if (url != nil && ![allowedSchemes containsObject:SENTRY_UNWRAP_NULLABLE(NSURL, url).scheme]) { - errorMessage = @"Unrecognized URL scheme in DSN"; - url = nil; - } - if (url != nil && (nil == url.host || url.host.length == 0)) { - errorMessage = @"Host component of DSN is missing"; - url = nil; - } - if (url != nil && url.user == nil) { - errorMessage = @"User component of DSN is missing"; - url = nil; - } - if (url != nil && url.pathComponents.count < 2) { - errorMessage = @"Project ID path component of DSN is missing"; - url = nil; - } - if (nil == url) { - if (nil != error) { - *error = NSErrorFromSentryError(kSentryErrorInvalidDsnError, errorMessage); - } - return nil; - } - return url; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/SentryFileManagerHelper.m b/Sources/Sentry/SentryFileManagerHelper.m index 0c680c7ad6c..366b99b7172 100644 --- a/Sources/Sentry/SentryFileManagerHelper.m +++ b/Sources/Sentry/SentryFileManagerHelper.m @@ -1,8 +1,6 @@ #import "SentryFileManagerHelper.h" #import "SentryDataCategoryMapper.h" #import "SentryDateUtils.h" -#import "SentryDsn+Private.h" -#import "SentryDsn.h" #import "SentryEnvelopeItemHeader.h" #import "SentryError.h" #import "SentryEvent.h" diff --git a/Sources/Sentry/SentryHttpTransport.m b/Sources/Sentry/SentryHttpTransport.m index a151cbeaa3d..4e7ae355c08 100644 --- a/Sources/Sentry/SentryHttpTransport.m +++ b/Sources/Sentry/SentryHttpTransport.m @@ -2,7 +2,6 @@ #import "SentryDataCategory.h" #import "SentryDataCategoryMapper.h" #import "SentryDiscardReasonMapper.h" -#import "SentryDsn.h" #import "SentryEnvelopeItemHeader.h" #import "SentryEnvelopeRateLimit.h" #import "SentryEvent.h" diff --git a/Sources/Sentry/SentryNSURLRequestBuilder.m b/Sources/Sentry/SentryNSURLRequestBuilder.m index 5004a854268..d8b29e7f7c7 100644 --- a/Sources/Sentry/SentryNSURLRequestBuilder.m +++ b/Sources/Sentry/SentryNSURLRequestBuilder.m @@ -1,5 +1,4 @@ #import "SentryNSURLRequestBuilder.h" -#import "SentryDsn.h" #import "SentryLogC.h" #import "SentrySerialization.h" #import "SentrySwift.h" diff --git a/Sources/Sentry/SentryNetworkTracker.m b/Sources/Sentry/SentryNetworkTracker.m index fed830306b4..64dfcacb11b 100644 --- a/Sources/Sentry/SentryNetworkTracker.m +++ b/Sources/Sentry/SentryNetworkTracker.m @@ -3,7 +3,6 @@ #import "SentryBreadcrumb.h" #import "SentryClient+Private.h" #import "SentryDefaultThreadInspector.h" -#import "SentryDsn.h" #import "SentryEvent.h" #import "SentryException.h" #import "SentryHttpStatusCodeRange+Private.h" diff --git a/Sources/Sentry/SentryOptionsInternal.m b/Sources/Sentry/SentryOptionsInternal.m index ac6eea451db..5a7bcd03611 100644 --- a/Sources/Sentry/SentryOptionsInternal.m +++ b/Sources/Sentry/SentryOptionsInternal.m @@ -1,5 +1,4 @@ #import "SentryOptionsInternal.h" -#import "SentryDsn.h" #import "SentryInternalDefines.h" #import "SentryLevelMapper.h" #import "SentrySwift.h" diff --git a/Sources/Sentry/SentryTraceContext.m b/Sources/Sentry/SentryTraceContext.m index 0193a79742f..ec2f1a2fe67 100644 --- a/Sources/Sentry/SentryTraceContext.m +++ b/Sources/Sentry/SentryTraceContext.m @@ -1,7 +1,6 @@ #import "SentryTraceContext.h" #import "SentryBaggage.h" #import "SentryDefines.h" -#import "SentryDsn.h" #import "SentryInternalDefines.h" #import "SentryLogC.h" #import "SentrySampleDecision.h" diff --git a/Sources/Sentry/include/SentryDsn+Private.h b/Sources/Sentry/include/SentryDsn+Private.h deleted file mode 100644 index 15fc3a31334..00000000000 --- a/Sources/Sentry/include/SentryDsn+Private.h +++ /dev/null @@ -1,15 +0,0 @@ -#if __has_include() -# import -#else -# import "SentryDsn.h" -#endif - -NS_ASSUME_NONNULL_BEGIN - -@interface SentryDsn (Private) - -- (NSString *)getHash; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/Sentry/include/SentryPrivate.h b/Sources/Sentry/include/SentryPrivate.h index bc0f40f5880..b2cc5069216 100644 --- a/Sources/Sentry/include/SentryPrivate.h +++ b/Sources/Sentry/include/SentryPrivate.h @@ -19,8 +19,8 @@ #import "SentryCrashUUIDConversion.h" #import "SentryDataCategoryMapper.h" #import "SentryDiscardReasonMapper.h" -#import "SentryDsn+Private.h" #import "SentryEnvelopeAttachmentHeader.h" +#import "SentryError.h" #import "SentryEventSwiftHelper.h" #import "SentryHub+Private.h" #import "SentryIntegrationProtocol.h" diff --git a/Sources/Swift/SentryDsn.swift b/Sources/Swift/SentryDsn.swift new file mode 100644 index 00000000000..d12ee3b3a36 --- /dev/null +++ b/Sources/Swift/SentryDsn.swift @@ -0,0 +1,200 @@ +@_implementationOnly import _SentryPrivate +import Foundation + +import CommonCrypto + +/// Represents a Sentry Data Source Name (DSN) which identifies a Sentry project. +@objc(SentryDsn) +public final class SentryDsn: NSObject { + + // Error code constant - must match SentryError.h + // Note: We use the numeric value directly since kSentryErrorInvalidDsnError + // is not accessible from Swift (it's a C enum value) + private static let kSentryErrorInvalidDsnError: Int = 100 + + private static func createError(code: Int, description: String) -> NSError { + // Use the Objective-C constant instead of hardcoding the string + // SentryErrorDomain is accessible because it's in the public header + return NSError( + domain: SentryErrorDomain, + code: code, + userInfo: [NSLocalizedDescriptionKey: description] + ) + } + + /// The parsed URL from the DSN string. + @objc public let url: URL + + private var _envelopeEndpoint: URL? + private let lock = NSLock() + + /// Initializes a SentryDsn from a DSN string. + /// - Parameters: + /// - dsnString: The DSN string to parse. + /// - error: An optional error pointer that will be set if the DSN is invalid. + /// - Returns: A new SentryDsn instance, or nil if the DSN string is invalid. + @objc + public init?(string dsnString: String?, didFailWithError error: NSErrorPointer) { + guard let parsedUrl = SentryDsn.convertDsnString(dsnString, didFailWithError: error) else { + return nil + } + self.url = parsedUrl + super.init() + } + + /// Swift convenience initializer that throws instead of using NSErrorPointer. + /// - Parameter string: The DSN string to parse. + /// - Throws: An error if the DSN string is invalid. + public convenience init(string: String?) throws { + var error: NSError? + guard let parsedUrl = SentryDsn.convertDsnString(string, didFailWithError: &error) else { + throw error ?? SentryDsn.createError(code: SentryDsn.kSentryErrorInvalidDsnError, description: "Invalid DSN") + } + self.init(url: parsedUrl) + } + + /// Internal initializer for use by the throwing convenience initializer. + private init(url: URL) { + self.url = url + super.init() + } + + /// Generates a SHA1 hash of the DSN URL. + /// - Returns: A hexadecimal string representation of the hash. + /// - Note: This is internal SDK API, not for public use. + @_spi(Private) @objc + public func getHash() -> String { + let data: Data + if let encodedData = url.absoluteString.data(using: .utf8) { + data = encodedData + } else { + // This should never happen for a valid URL, but handle it defensively + // to match Objective-C behavior (hash of empty data) + assertionFailure("Failed to encode URL to UTF-8: \(url.absoluteString)") + // Log the error for production builds + #if DEBUG + print("[Sentry] Warning: Failed to encode DSN URL to UTF-8, using empty data for hash") + #endif + data = Data() + } + + var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH)) + data.withUnsafeBytes { bytes in + _ = CC_SHA1(bytes.baseAddress, CC_LONG(data.count), &digest) + } + + return digest.map { String(format: "%02x", $0) }.joined() + } + + /// Returns the envelope endpoint URL for this DSN. + /// - Returns: The envelope endpoint URL. + @objc + public func getEnvelopeEndpoint() -> URL { + if let cached = _envelopeEndpoint { + return cached + } + + lock.lock() + defer { lock.unlock() } + + if let cached = _envelopeEndpoint { + return cached + } + + let endpoint = getBaseEndpoint().appendingPathComponent("envelope/") + _envelopeEndpoint = endpoint + return endpoint + } + + /// Returns the base API endpoint URL for this DSN. + /// - Returns: The base endpoint URL. + private func getBaseEndpoint() -> URL { + let projectId = url.lastPathComponent + var paths = url.pathComponents + + // [0] = / + // [1] = projectId + // If there are more than two, that means someone wants to have an + // additional path ref: https://github.com/getsentry/sentry-cocoa/issues/236 + var path = "" + if paths.count > 2 { + paths.removeFirst() // We remove the leading / + paths.removeLast() // We remove projectId since we add it later + path = "/" + paths.joined(separator: "/") // We put together the path + } + + var components = URLComponents() + components.scheme = url.scheme + components.host = url.host + components.port = url.port + components.path = "\(path)/api/\(projectId)/" + + // This should always be valid since we already validated the URL + return components.url ?? url + } + + /// Converts a DSN string to a URL after validation. + /// - Parameters: + /// - dsnString: The DSN string to convert. + /// - error: An optional error pointer that will be set if the DSN is invalid. + /// - Returns: A valid URL, or nil if the DSN string is invalid. + private static func convertDsnString(_ dsnString: String?, didFailWithError error: NSErrorPointer) -> URL? { + guard let dsnString = dsnString else { + setError(error, message: "DSN string is nil") + return nil + } + + let trimmedDsnString = dsnString.trimmingCharacters(in: .whitespacesAndNewlines) + + guard let url = URL(string: trimmedDsnString) else { + setError(error, message: "Invalid DSN URL") + return nil + } + + if let errorMessage = validateDsnURL(url) { + setError(error, message: errorMessage) + return nil + } + + return url + } + + /// Validates a DSN URL. + /// - Parameter url: The URL to validate. + /// - Returns: An error message if validation fails, or nil if valid. + private static func validateDsnURL(_ url: URL) -> String? { + let allowedSchemes: Set = ["http", "https"] + + if url.scheme == nil { + return "URL scheme of DSN is missing" + } + + if let scheme = url.scheme, !allowedSchemes.contains(scheme) { + return "Unrecognized URL scheme in DSN" + } + + if url.host == nil || url.host?.isEmpty == true { + return "Host component of DSN is missing" + } + + if url.user == nil { + return "User component of DSN is missing" + } + + if url.pathComponents.count < 2 { + return "Project ID path component of DSN is missing" + } + + return nil + } + + /// Sets an error pointer with a Sentry error. + /// - Parameters: + /// - error: The error pointer to set. + /// - message: The error message. + private static func setError(_ error: NSErrorPointer, message: String) { + if let error = error { + error.pointee = createError(code: SentryDsn.kSentryErrorInvalidDsnError, description: message) + } + } +} diff --git a/TestSamples/SwiftUITestSample/SwiftUITestSample-Bridging-Header.h b/TestSamples/SwiftUITestSample/SwiftUITestSample-Bridging-Header.h index f5d5ded043c..e69de29bb2d 100644 --- a/TestSamples/SwiftUITestSample/SwiftUITestSample-Bridging-Header.h +++ b/TestSamples/SwiftUITestSample/SwiftUITestSample-Bridging-Header.h @@ -1 +0,0 @@ -#import diff --git a/TestSamples/SwiftUITestSample/SwiftUITestSample/SwiftUITestSampleApp.swift b/TestSamples/SwiftUITestSample/SwiftUITestSample/SwiftUITestSampleApp.swift index 561904c54b6..58447c5ad70 100644 --- a/TestSamples/SwiftUITestSample/SwiftUITestSample/SwiftUITestSampleApp.swift +++ b/TestSamples/SwiftUITestSample/SwiftUITestSample/SwiftUITestSampleApp.swift @@ -1,4 +1,4 @@ -import Sentry +@_spi(Private) import Sentry import SwiftUI @main diff --git a/Tests/SentryTests/Networking/SentryDsnTests.m b/Tests/SentryTests/Networking/SentryDsnTests.m index 795a5f561de..00636569c07 100644 --- a/Tests/SentryTests/Networking/SentryDsnTests.m +++ b/Tests/SentryTests/Networking/SentryDsnTests.m @@ -1,4 +1,3 @@ -#import "SentryDsn.h" #import "SentryError.h" #import "SentryMeta.h" #import "SentryOptionsInternal.h" diff --git a/Tests/SentryTests/SentryTests-Bridging-Header.h b/Tests/SentryTests/SentryTests-Bridging-Header.h index b667599a588..55131986f99 100644 --- a/Tests/SentryTests/SentryTests-Bridging-Header.h +++ b/Tests/SentryTests/SentryTests-Bridging-Header.h @@ -102,7 +102,6 @@ #import "SentryDefaultThreadInspector.h" #import "SentryDiscardReason.h" #import "SentryDiscardReasonMapper.h" -#import "SentryDsn.h" #import "SentryEnvelopeAttachmentHeader.h" #import "SentryEnvelopeRateLimit.h" #import "SentryEvent+Private.h" diff --git a/sdk_api.json b/sdk_api.json index 8bcb2cfc873..3de45287fa0 100644 --- a/sdk_api.json +++ b/sdk_api.json @@ -74,16 +74,6 @@ "Exported" ] }, - { - "kind": "Import", - "name": "Sentry.SentryDsn", - "printedName": "Sentry.SentryDsn", - "declKind": "Import", - "moduleName": "Sentry", - "declAttributes": [ - "Exported" - ] - }, { "kind": "Import", "name": "Sentry.SentryError", @@ -17011,218 +17001,6 @@ "usr": "c:@T@SentryBeforeSendSpanCallback", "moduleName": "Sentry" }, - { - "kind": "TypeDecl", - "name": "SentryDsn", - "printedName": "SentryDsn", - "children": [ - { - "kind": "Var", - "name": "url", - "printedName": "url", - "children": [ - { - "kind": "TypeNominal", - "name": "URL", - "printedName": "Foundation.URL", - "usr": "s:10Foundation3URLV" - } - ], - "declKind": "Var", - "usr": "c:objc(cs)SentryDsn(py)url", - "moduleName": "Sentry", - "isOpen": true, - "objc_name": "url", - "declAttributes": [ - "ObjC", - "Dynamic" - ], - "accessors": [ - { - "kind": "Accessor", - "name": "Get", - "printedName": "Get()", - "children": [ - { - "kind": "TypeNominal", - "name": "URL", - "printedName": "Foundation.URL", - "usr": "s:10Foundation3URLV" - } - ], - "declKind": "Accessor", - "usr": "c:objc(cs)SentryDsn(im)url", - "moduleName": "Sentry", - "isOpen": true, - "objc_name": "url", - "declAttributes": [ - "DiscardableResult", - "ObjC", - "Dynamic" - ], - "accessorKind": "get" - } - ] - }, - { - "kind": "Constructor", - "name": "init", - "printedName": "init(string:)", - "children": [ - { - "kind": "TypeNominal", - "name": "SentryDsn", - "printedName": "Sentry.SentryDsn", - "usr": "c:objc(cs)SentryDsn" - }, - { - "kind": "TypeNominal", - "name": "Optional", - "printedName": "Swift.String?", - "children": [ - { - "kind": "TypeNominal", - "name": "String", - "printedName": "Swift.String", - "usr": "s:SS" - } - ], - "usr": "s:Sq" - } - ], - "declKind": "Constructor", - "usr": "c:objc(cs)SentryDsn(im)initWithString:didFailWithError:", - "moduleName": "Sentry", - "objc_name": "initWithString:didFailWithError:", - "declAttributes": [ - "ObjC", - "Dynamic" - ], - "throwing": true, - "init_kind": "Designated" - }, - { - "kind": "Function", - "name": "getEnvelopeEndpoint", - "printedName": "getEnvelopeEndpoint()", - "children": [ - { - "kind": "TypeNominal", - "name": "URL", - "printedName": "Foundation.URL", - "usr": "s:10Foundation3URLV" - } - ], - "declKind": "Func", - "usr": "c:objc(cs)SentryDsn(im)getEnvelopeEndpoint", - "moduleName": "Sentry", - "isOpen": true, - "objc_name": "getEnvelopeEndpoint", - "declAttributes": [ - "DiscardableResult", - "ObjC", - "Dynamic" - ], - "funcSelfKind": "NonMutating" - }, - { - "kind": "Constructor", - "name": "init", - "printedName": "init()", - "children": [ - { - "kind": "TypeNominal", - "name": "SentryDsn", - "printedName": "Sentry.SentryDsn", - "usr": "c:objc(cs)SentryDsn" - } - ], - "declKind": "Constructor", - "usr": "c:objc(cs)NSObject(im)init", - "moduleName": "Sentry", - "overriding": true, - "implicit": true, - "objc_name": "init", - "declAttributes": [ - "Override", - "ObjC", - "Dynamic" - ], - "init_kind": "Designated" - } - ], - "declKind": "Class", - "usr": "c:objc(cs)SentryDsn", - "moduleName": "Sentry", - "isOpen": true, - "objc_name": "SentryDsn", - "declAttributes": [ - "ObjC", - "Dynamic" - ], - "superclassUsr": "c:objc(cs)NSObject", - "inheritsConvenienceInitializers": true, - "superclassNames": [ - "ObjectiveC.NSObject" - ], - "conformances": [ - { - "kind": "Conformance", - "name": "Copyable", - "printedName": "Copyable", - "usr": "s:s8CopyableP", - "mangledName": "$ss8CopyableP" - }, - { - "kind": "Conformance", - "name": "Escapable", - "printedName": "Escapable", - "usr": "s:s9EscapableP", - "mangledName": "$ss9EscapableP" - }, - { - "kind": "Conformance", - "name": "NSObjectProtocol", - "printedName": "NSObjectProtocol", - "usr": "c:objc(pl)NSObject" - }, - { - "kind": "Conformance", - "name": "Equatable", - "printedName": "Equatable", - "usr": "s:SQ", - "mangledName": "$sSQ" - }, - { - "kind": "Conformance", - "name": "Hashable", - "printedName": "Hashable", - "usr": "s:SH", - "mangledName": "$sSH" - }, - { - "kind": "Conformance", - "name": "CVarArg", - "printedName": "CVarArg", - "usr": "s:s7CVarArgP", - "mangledName": "$ss7CVarArgP" - }, - { - "kind": "Conformance", - "name": "CustomStringConvertible", - "printedName": "CustomStringConvertible", - "usr": "s:s23CustomStringConvertibleP", - "mangledName": "$ss23CustomStringConvertibleP" - }, - { - "kind": "Conformance", - "name": "CustomDebugStringConvertible", - "printedName": "CustomDebugStringConvertible", - "usr": "s:s28CustomDebugStringConvertibleP", - "mangledName": "$ss28CustomDebugStringConvertibleP" - } - ] - }, { "kind": "TypeDecl", "name": "SentryError", @@ -30975,6 +30753,13 @@ "declKind": "Import", "moduleName": "Sentry" }, + { + "kind": "Import", + "name": "CommonCrypto", + "printedName": "CommonCrypto", + "declKind": "Import", + "moduleName": "Sentry" + }, { "kind": "Import", "name": "CoreGraphics", @@ -44725,7 +44510,7 @@ "kind": "TypeNominal", "name": "SentryDsn", "printedName": "Sentry.SentryDsn", - "usr": "c:objc(cs)SentryDsn" + "usr": "c:@M@Sentry@objc(cs)SentryDsn" } ], "usr": "s:Sq" @@ -44733,7 +44518,7 @@ ], "declKind": "Var", "usr": "c:@M@Sentry@objc(cs)SentryOptions(py)parsedDsn", - "mangledName": "$s6Sentry7OptionsC9parsedDsnSo0aD0CSgvp", + "mangledName": "$s6Sentry7OptionsC9parsedDsnAA0aD0CSgvp", "moduleName": "Sentry", "declAttributes": [ "HasInitialValue", @@ -44757,7 +44542,7 @@ "kind": "TypeNominal", "name": "SentryDsn", "printedName": "Sentry.SentryDsn", - "usr": "c:objc(cs)SentryDsn" + "usr": "c:@M@Sentry@objc(cs)SentryDsn" } ], "usr": "s:Sq" @@ -44765,7 +44550,7 @@ ], "declKind": "Accessor", "usr": "c:@M@Sentry@objc(cs)SentryOptions(im)parsedDsn", - "mangledName": "$s6Sentry7OptionsC9parsedDsnSo0aD0CSgvg", + "mangledName": "$s6Sentry7OptionsC9parsedDsnAA0aD0CSgvg", "moduleName": "Sentry", "implicit": true, "declAttributes": [ @@ -44793,7 +44578,7 @@ "kind": "TypeNominal", "name": "SentryDsn", "printedName": "Sentry.SentryDsn", - "usr": "c:objc(cs)SentryDsn" + "usr": "c:@M@Sentry@objc(cs)SentryDsn" } ], "usr": "s:Sq" @@ -44801,7 +44586,7 @@ ], "declKind": "Accessor", "usr": "c:@M@Sentry@objc(cs)SentryOptions(im)setParsedDsn:", - "mangledName": "$s6Sentry7OptionsC9parsedDsnSo0aD0CSgvs", + "mangledName": "$s6Sentry7OptionsC9parsedDsnAA0aD0CSgvs", "moduleName": "Sentry", "implicit": true, "declAttributes": [ @@ -56592,6 +56377,269 @@ } ] }, + { + "kind": "TypeDecl", + "name": "SentryDsn", + "printedName": "SentryDsn", + "children": [ + { + "kind": "Var", + "name": "url", + "printedName": "url", + "children": [ + { + "kind": "TypeNominal", + "name": "URL", + "printedName": "Foundation.URL", + "usr": "s:10Foundation3URLV" + } + ], + "declKind": "Var", + "usr": "c:@M@Sentry@objc(cs)SentryDsn(py)url", + "mangledName": "$s6Sentry0A3DsnC3url10Foundation3URLVvp", + "moduleName": "Sentry", + "declAttributes": [ + "Final", + "ObjC", + "HasStorage" + ], + "isLet": true, + "hasStorage": true, + "accessors": [ + { + "kind": "Accessor", + "name": "Get", + "printedName": "Get()", + "children": [ + { + "kind": "TypeNominal", + "name": "URL", + "printedName": "Foundation.URL", + "usr": "s:10Foundation3URLV" + } + ], + "declKind": "Accessor", + "usr": "c:@M@Sentry@objc(cs)SentryDsn(im)url", + "mangledName": "$s6Sentry0A3DsnC3url10Foundation3URLVvg", + "moduleName": "Sentry", + "implicit": true, + "declAttributes": [ + "Final", + "ObjC" + ], + "accessorKind": "get" + } + ] + }, + { + "kind": "Constructor", + "name": "init", + "printedName": "init(string:didFailWithError:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Sentry.SentryDsn?", + "children": [ + { + "kind": "TypeNominal", + "name": "SentryDsn", + "printedName": "Sentry.SentryDsn", + "usr": "c:@M@Sentry@objc(cs)SentryDsn" + } + ], + "usr": "s:Sq" + }, + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Swift.String?", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "usr": "s:Sq" + }, + { + "kind": "TypeNameAlias", + "name": "NSErrorPointer", + "printedName": "Foundation.NSErrorPointer", + "children": [ + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Swift.AutoreleasingUnsafeMutablePointer?", + "children": [ + { + "kind": "TypeNominal", + "name": "AutoreleasingUnsafeMutablePointer", + "printedName": "Swift.AutoreleasingUnsafeMutablePointer", + "children": [ + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Foundation.NSError?", + "children": [ + { + "kind": "TypeNominal", + "name": "NSError", + "printedName": "Foundation.NSError", + "usr": "c:objc(cs)NSError" + } + ], + "usr": "s:Sq" + } + ], + "usr": "s:SA" + } + ], + "usr": "s:Sq" + } + ] + } + ], + "declKind": "Constructor", + "usr": "c:@M@Sentry@objc(cs)SentryDsn(im)initWithString:didFailWithError:", + "mangledName": "$s6Sentry0A3DsnC6string16didFailWithErrorACSgSSSg_SAySo7NSErrorCSgGSgtcfc", + "moduleName": "Sentry", + "objc_name": "initWithString:didFailWithError:", + "declAttributes": [ + "ObjC" + ], + "init_kind": "Designated" + }, + { + "kind": "Constructor", + "name": "init", + "printedName": "init(string:)", + "children": [ + { + "kind": "TypeNominal", + "name": "SentryDsn", + "printedName": "Sentry.SentryDsn", + "usr": "c:@M@Sentry@objc(cs)SentryDsn" + }, + { + "kind": "TypeNominal", + "name": "Optional", + "printedName": "Swift.String?", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + } + ], + "usr": "s:Sq" + } + ], + "declKind": "Constructor", + "usr": "s:6Sentry0A3DsnC6stringACSSSg_tKcfc", + "mangledName": "$s6Sentry0A3DsnC6stringACSSSg_tKcfc", + "moduleName": "Sentry", + "throwing": true, + "init_kind": "Convenience" + }, + { + "kind": "Function", + "name": "getEnvelopeEndpoint", + "printedName": "getEnvelopeEndpoint()", + "children": [ + { + "kind": "TypeNominal", + "name": "URL", + "printedName": "Foundation.URL", + "usr": "s:10Foundation3URLV" + } + ], + "declKind": "Func", + "usr": "c:@M@Sentry@objc(cs)SentryDsn(im)getEnvelopeEndpoint", + "mangledName": "$s6Sentry0A3DsnC19getEnvelopeEndpoint10Foundation3URLVyF", + "moduleName": "Sentry", + "declAttributes": [ + "Final", + "ObjC" + ], + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:@M@Sentry@objc(cs)SentryDsn", + "mangledName": "$s6Sentry0A3DsnC", + "moduleName": "Sentry", + "objc_name": "SentryDsn", + "declAttributes": [ + "Final", + "ObjC" + ], + "superclassUsr": "c:objc(cs)NSObject", + "hasMissingDesignatedInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Copyable", + "printedName": "Copyable", + "usr": "s:s8CopyableP", + "mangledName": "$ss8CopyableP" + }, + { + "kind": "Conformance", + "name": "Escapable", + "printedName": "Escapable", + "usr": "s:s9EscapableP", + "mangledName": "$ss9EscapableP" + }, + { + "kind": "Conformance", + "name": "NSObjectProtocol", + "printedName": "NSObjectProtocol", + "usr": "c:objc(pl)NSObject" + }, + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, { "kind": "Var", "name": "SENTRY_HAS_METRIC_KIT",