From e275e4979592d50108b9fab64859b9881a5b43f4 Mon Sep 17 00:00:00 2001 From: tigerenwork Date: Mon, 29 Jun 2026 00:18:25 +0800 Subject: [PATCH] feat: add comprehensive debug logging to OAuth flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added os.Logger-based logging (subsystem: com.xorbitlab.bugger) covering: - FeishuAuthService.send(): raw HTTP request URL, method, body, auth header, response status code, and raw response body (up to 1000 chars) - exchangeCode(): before/after token exchange with token previews - TokenManager.handleCallback(): each step with success/failure - LocalOAuthServer: server start, connection received, code extracted View logs in: Xcode debug console, or Console.app → filter 'bugger' Also fixed type inference ambiguity in generic send() calls. Co-Authored-By: Claude --- Bugger.xcodeproj/project.pbxproj | 241 +++++++++--------- .../xcshareddata/xcschemes/Bugger.xcscheme | 21 -- .../Services/Feishu/FeishuAuthService.swift | 29 ++- Sources/Services/TokenManager.swift | 4 + Sources/Utils/LocalOAuthServer.swift | 9 +- Sources/Utils/Logger.swift | 20 ++ 6 files changed, 177 insertions(+), 147 deletions(-) create mode 100644 Sources/Utils/Logger.swift diff --git a/Bugger.xcodeproj/project.pbxproj b/Bugger.xcodeproj/project.pbxproj index 7cc92f8..c3e97e4 100644 --- a/Bugger.xcodeproj/project.pbxproj +++ b/Bugger.xcodeproj/project.pbxproj @@ -7,66 +7,68 @@ objects = { /* Begin PBXBuildFile section */ - 15550246A9E8DAF25E690478 /* BuggerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB7AD270E93EA343975AC6 /* BuggerApp.swift */; }; - 1E3C1F40E2FF64A041856909 /* BugListPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEABFC668F7B082847F65D38 /* BugListPopover.swift */; }; - 1FB7E762C0B6568C47B48EF0 /* URL+Feishu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F888AA5F655343B19839B4C2 /* URL+Feishu.swift */; }; - 29AE37B117A1422EA21570CA /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */; }; - 29EE2FE56882F97E14AAF58F /* FeishuService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21AC33F380B7DC34C39B61A6 /* FeishuService.swift */; }; - 3467A50268399ABE9804D4D4 /* BugRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129D6F630904F03D06B5DC4 /* BugRow.swift */; }; - 4309E8C70AE99466545A3E37 /* FeishuAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2C50E47966E8ADB0446A0C /* FeishuAuthService.swift */; }; - 485A69E15EF1D805F50DF364 /* FloatingWidgetWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2FE32B404AB4388A066991 /* FloatingWidgetWindow.swift */; }; - 4EA9BDBA3F98AF4A41712A18 /* Bug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846CA001267896C54A78441A /* Bug.swift */; }; - 56D44DCBAF4FE0E1D9E620FA /* PollerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F4628E7B599B69B499E09E9 /* PollerService.swift */; }; - 58F16D20CC26D8248055CC2C /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBEF4F77A6A2E2D041EF581 /* AppConfig.swift */; }; - 6148104B311B60C79B3B8572 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CC175DE8E9FE3250757D33 /* NotificationService.swift */; }; - 64F1EE978536D1CB02B8F0D3 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */; }; - 7B0EAA6D83D40A593E36EE31 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3693AA93F823859D15256D /* SettingsView.swift */; }; - A33561284CA44A0045902BCC /* BugPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5359156BD70B765D2BF4E718 /* BugPriority.swift */; }; - AECED74595B57A400437B9FD /* BugStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F52FB34B285D91A3E4670 /* BugStore.swift */; }; - B066D78DA6F57A882A61C0B2 /* OAuthSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */; }; - B882D310EB2B5D032375CDDF /* TokenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E3775F77DD36C27160A8C /* TokenManager.swift */; }; - C3F7FEB179B079BDDD2AA212 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09B9A4D84F3F604C49171A89 /* Assets.xcassets */; }; - C5D9B1FACE813CD43236BB77 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */; }; - CAE624453A3F0375D872170A /* FeishuModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE9FBC39502FA635EF1A6A5C /* FeishuModels.swift */; }; - CB529549DB1DBB5F02884300 /* FeishuError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A83E76FBB83849E4B6704D3 /* FeishuError.swift */; }; - D2855F82E68FADA8BEA43086 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */; }; - DDB9EB345FEBB95DD9976364 /* BugChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B24E1E1D32F7B774D12DD85 /* BugChange.swift */; }; - E4CBAE27491AF1C52944FA91 /* BugStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646C676356A4125B8E8D5FA5 /* BugStatus.swift */; }; - EEC5853D00ED565270DC867F /* LocalOAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */; }; - F6750BB1FBEE5BC90DD6BDBC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207CA4381D0CFEC95263A2DE /* AppDelegate.swift */; }; + F6750BB1FBEE5BC90DD6BDBC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207CA4381D0CFEC95263A2DE; }; + 15550246A9E8DAF25E690478 /* BuggerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB7AD270E93EA343975AC6; }; + 58F16D20CC26D8248055CC2C /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBEF4F77A6A2E2D041EF581; }; + 4EA9BDBA3F98AF4A41712A18 /* Bug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846CA001267896C54A78441A; }; + DDB9EB345FEBB95DD9976364 /* BugChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B24E1E1D32F7B774D12DD85; }; + A33561284CA44A0045902BCC /* BugPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5359156BD70B765D2BF4E718; }; + E4CBAE27491AF1C52944FA91 /* BugStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646C676356A4125B8E8D5FA5; }; + D2855F82E68FADA8BEA43086 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1DD178095EFCE7BC121C1C4; }; + 4309E8C70AE99466545A3E37 /* FeishuAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2C50E47966E8ADB0446A0C; }; + CB529549DB1DBB5F02884300 /* FeishuError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A83E76FBB83849E4B6704D3; }; + CAE624453A3F0375D872170A /* FeishuModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE9FBC39502FA635EF1A6A5C; }; + 29EE2FE56882F97E14AAF58F /* FeishuService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21AC33F380B7DC34C39B61A6; }; + 6148104B311B60C79B3B8572 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CC175DE8E9FE3250757D33; }; + 56D44DCBAF4FE0E1D9E620FA /* PollerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F4628E7B599B69B499E09E9; }; + B882D310EB2B5D032375CDDF /* TokenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E3775F77DD36C27160A8C; }; + C5D9B1FACE813CD43236BB77 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F99094B0F609809EBDB5F4A; }; + 29AE37B117A1422EA21570CA /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C935E6B4D1813AB01186A0; }; + 64F1EE978536D1CB02B8F0D3 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF06E1030AA21DA8190169A8; }; + EEC5853D00ED565270DC867F /* LocalOAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D11523ACB81DBB9D412995; }; + 47ED652FA0AC818086F85DF3 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED0A90DFCB8D4968E4E3CA1; }; + 1FB7E762C0B6568C47B48EF0 /* URL+Feishu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F888AA5F655343B19839B4C2; }; + AECED74595B57A400437B9FD /* BugStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F52FB34B285D91A3E4670; }; + 485A69E15EF1D805F50DF364 /* FloatingWidgetWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2FE32B404AB4388A066991; }; + 1E3C1F40E2FF64A041856909 /* BugListPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEABFC668F7B082847F65D38; }; + 3467A50268399ABE9804D4D4 /* BugRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129D6F630904F03D06B5DC4; }; + B066D78DA6F57A882A61C0B2 /* OAuthSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0A744D4F5DB88B1496176B; }; + 7B0EAA6D83D40A593E36EE31 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3693AA93F823859D15256D; }; + C3F7FEB179B079BDDD2AA212 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09B9A4D84F3F604C49171A89; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 09B9A4D84F3F604C49171A89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + EF0182DF85A7CD0319333F24 /* Bugger.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bugger.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 207CA4381D0CFEC95263A2DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + DDDB7AD270E93EA343975AC6 /* BuggerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuggerApp.swift; sourceTree = ""; }; + 9FBEF4F77A6A2E2D041EF581 /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfig.swift; sourceTree = ""; }; + 846CA001267896C54A78441A /* Bug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bug.swift; sourceTree = ""; }; 0B24E1E1D32F7B774D12DD85 /* BugChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugChange.swift; sourceTree = ""; }; + 5359156BD70B765D2BF4E718 /* BugPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugPriority.swift; sourceTree = ""; }; + 646C676356A4125B8E8D5FA5 /* BugStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStatus.swift; sourceTree = ""; }; + F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; + 6A2C50E47966E8ADB0446A0C /* FeishuAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuAuthService.swift; sourceTree = ""; }; + 2A83E76FBB83849E4B6704D3 /* FeishuError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuError.swift; sourceTree = ""; }; + FE9FBC39502FA635EF1A6A5C /* FeishuModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuModels.swift; sourceTree = ""; }; + 21AC33F380B7DC34C39B61A6 /* FeishuService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuService.swift; sourceTree = ""; }; + 59CC175DE8E9FE3250757D33 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; + 4F4628E7B599B69B499E09E9 /* PollerService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollerService.swift; sourceTree = ""; }; 0E7E3775F77DD36C27160A8C /* TokenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenManager.swift; sourceTree = ""; }; 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = ""; }; - 1129D6F630904F03D06B5DC4 /* BugRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugRow.swift; sourceTree = ""; }; - 207CA4381D0CFEC95263A2DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 21AC33F380B7DC34C39B61A6 /* FeishuService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuService.swift; sourceTree = ""; }; - 2A83E76FBB83849E4B6704D3 /* FeishuError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuError.swift; sourceTree = ""; }; - 2D3693AA93F823859D15256D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; - 344F52FB34B285D91A3E4670 /* BugStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStore.swift; sourceTree = ""; }; - 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalOAuthServer.swift; sourceTree = ""; }; - 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthSetupView.swift; sourceTree = ""; }; - 4F4628E7B599B69B499E09E9 /* PollerService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollerService.swift; sourceTree = ""; }; - 5359156BD70B765D2BF4E718 /* BugPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugPriority.swift; sourceTree = ""; }; - 59CC175DE8E9FE3250757D33 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; - 646C676356A4125B8E8D5FA5 /* BugStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStatus.swift; sourceTree = ""; }; - 6A2C50E47966E8ADB0446A0C /* FeishuAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuAuthService.swift; sourceTree = ""; }; - 6E2FE32B404AB4388A066991 /* FloatingWidgetWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingWidgetWindow.swift; sourceTree = ""; }; - 73AB234B54673C838E33AC7F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 846CA001267896C54A78441A /* Bug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bug.swift; sourceTree = ""; }; 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; - 9FBEF4F77A6A2E2D041EF581 /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfig.swift; sourceTree = ""; }; - CEABFC668F7B082847F65D38 /* BugListPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugListPopover.swift; sourceTree = ""; }; - DDDB7AD270E93EA343975AC6 /* BuggerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuggerApp.swift; sourceTree = ""; }; - E9B6FE6E06295095649B24A7 /* Bugger.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Bugger.entitlements; sourceTree = ""; }; - EF0182DF85A7CD0319333F24 /* Bugger.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bugger.app; sourceTree = BUILT_PRODUCTS_DIR; }; EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainHelper.swift; sourceTree = ""; }; - F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; + 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalOAuthServer.swift; sourceTree = ""; }; + 0ED0A90DFCB8D4968E4E3CA1 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; F888AA5F655343B19839B4C2 /* URL+Feishu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Feishu.swift"; sourceTree = ""; }; - FE9FBC39502FA635EF1A6A5C /* FeishuModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuModels.swift; sourceTree = ""; }; + 344F52FB34B285D91A3E4670 /* BugStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStore.swift; sourceTree = ""; }; + 6E2FE32B404AB4388A066991 /* FloatingWidgetWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingWidgetWindow.swift; sourceTree = ""; }; + CEABFC668F7B082847F65D38 /* BugListPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugListPopover.swift; sourceTree = ""; }; + 1129D6F630904F03D06B5DC4 /* BugRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugRow.swift; sourceTree = ""; }; + 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthSetupView.swift; sourceTree = ""; }; + 2D3693AA93F823859D15256D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 09B9A4D84F3F604C49171A89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 73AB234B54673C838E33AC7F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E9B6FE6E06295095649B24A7 /* Bugger.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Bugger.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -80,7 +82,7 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 14ED1DECD6D906F498B9ECB5 = { + 14ED1DECD6D906F498B9ECB5 /* Root */ = { isa = PBXGroup; children = ( 287BE755981C092238309A9A /* Sources */, @@ -103,17 +105,6 @@ path = Sources; sourceTree = ""; }; - 31DF436612EC1C3CD1194AA1 /* Views */ = { - isa = PBXGroup; - children = ( - E7E4AD241EEE594C1EEB9724 /* FloatingWidget */, - EA9ED591BB8A18FEBD1B58A3 /* MenuBar */, - 74AD95EF49A7D01C83865FAC /* OAuth */, - B70D2E54AD6B19DD455A8F82 /* Settings */, - ); - path = Views; - sourceTree = ""; - }; 65997CD9BD6FFEF8851BF59E /* Models */ = { isa = PBXGroup; children = ( @@ -126,44 +117,6 @@ path = Models; sourceTree = ""; }; - 6AB9730AA11690EFC8F21473 /* ViewModels */ = { - isa = PBXGroup; - children = ( - 344F52FB34B285D91A3E4670 /* BugStore.swift */, - ); - path = ViewModels; - sourceTree = ""; - }; - 74AD95EF49A7D01C83865FAC /* OAuth */ = { - isa = PBXGroup; - children = ( - 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */, - ); - path = OAuth; - sourceTree = ""; - }; - 8AD6A16612A2DB7B2F899787 /* Resources */ = { - isa = PBXGroup; - children = ( - 09B9A4D84F3F604C49171A89 /* Assets.xcassets */, - 73AB234B54673C838E33AC7F /* Info.plist */, - E9B6FE6E06295095649B24A7 /* Bugger.entitlements */, - ); - path = Resources; - sourceTree = ""; - }; - A6646A2065F53ED50AD2CCA7 /* Utils */ = { - isa = PBXGroup; - children = ( - 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */, - 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */, - EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */, - 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */, - F888AA5F655343B19839B4C2 /* URL+Feishu.swift */, - ); - path = Utils; - sourceTree = ""; - }; A8C46168E4DFCE29B056A4E2 /* Services */ = { isa = PBXGroup; children = ( @@ -176,20 +129,36 @@ path = Services; sourceTree = ""; }; - B23D89B2D2DF3745A003AEB1 /* Products */ = { + A6646A2065F53ED50AD2CCA7 /* Utils */ = { isa = PBXGroup; children = ( - EF0182DF85A7CD0319333F24 /* Bugger.app */, + 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */, + 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */, + EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */, + 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */, + 0ED0A90DFCB8D4968E4E3CA1 /* Logger.swift */, + F888AA5F655343B19839B4C2 /* URL+Feishu.swift */, ); - name = Products; + path = Utils; sourceTree = ""; }; - B70D2E54AD6B19DD455A8F82 /* Settings */ = { + 6AB9730AA11690EFC8F21473 /* ViewModels */ = { isa = PBXGroup; children = ( - 2D3693AA93F823859D15256D /* SettingsView.swift */, + 344F52FB34B285D91A3E4670 /* BugStore.swift */, ); - path = Settings; + path = ViewModels; + sourceTree = ""; + }; + 31DF436612EC1C3CD1194AA1 /* Views */ = { + isa = PBXGroup; + children = ( + E7E4AD241EEE594C1EEB9724 /* FloatingWidget */, + EA9ED591BB8A18FEBD1B58A3 /* MenuBar */, + 74AD95EF49A7D01C83865FAC /* OAuth */, + B70D2E54AD6B19DD455A8F82 /* Settings */, + ); + path = Views; sourceTree = ""; }; E0E23D3899D89889546FB428 /* Feishu */ = { @@ -220,6 +189,40 @@ path = MenuBar; sourceTree = ""; }; + 74AD95EF49A7D01C83865FAC /* OAuth */ = { + isa = PBXGroup; + children = ( + 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */, + ); + path = OAuth; + sourceTree = ""; + }; + B70D2E54AD6B19DD455A8F82 /* Settings */ = { + isa = PBXGroup; + children = ( + 2D3693AA93F823859D15256D /* SettingsView.swift */, + ); + path = Settings; + sourceTree = ""; + }; + 8AD6A16612A2DB7B2F899787 /* Resources */ = { + isa = PBXGroup; + children = ( + 09B9A4D84F3F604C49171A89 /* Assets.xcassets */, + 73AB234B54673C838E33AC7F /* Info.plist */, + E9B6FE6E06295095649B24A7 /* Bugger.entitlements */, + ); + path = Resources; + sourceTree = ""; + }; + B23D89B2D2DF3745A003AEB1 /* Products */ = { + isa = PBXGroup; + children = ( + EF0182DF85A7CD0319333F24 /* Bugger.app */, + ); + name = Products; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -308,6 +311,7 @@ 29AE37B117A1422EA21570CA /* DateFormatter+Extensions.swift in Sources */, 64F1EE978536D1CB02B8F0D3 /* KeychainHelper.swift in Sources */, EEC5853D00ED565270DC867F /* LocalOAuthServer.swift in Sources */, + 47ED652FA0AC818086F85DF3 /* Logger.swift in Sources */, 1FB7E762C0B6568C47B48EF0 /* URL+Feishu.swift in Sources */, AECED74595B57A400437B9FD /* BugStore.swift in Sources */, 485A69E15EF1D805F50DF364 /* FloatingWidgetWindow.swift in Sources */, @@ -350,15 +354,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - FEISHU_APP_ID = cli_aacb82a1c0b8dcc0; - FEISHU_APP_SECRET = jUkU9ygRuQ0KaZFV2BSPfe33iXCahzNM; - FEISHU_BASE_DOMAIN = mi5p6bgsnf8.feishu.cn; + FEISHU_APP_ID = "$(FEISHU_APP_ID)"; + FEISHU_APP_SECRET = "$(FEISHU_APP_SECRET)"; + FEISHU_BASE_DOMAIN = "xorbitlab.feishu.cn"; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.xorbitlab.bugger; @@ -374,15 +375,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - FEISHU_APP_ID = cli_aacb82a1c0b8dcc0; - FEISHU_APP_SECRET = jUkU9ygRuQ0KaZFV2BSPfe33iXCahzNM; - FEISHU_BASE_DOMAIN = mi5p6bgsnf8.feishu.cn; + FEISHU_APP_ID = "$(FEISHU_APP_ID)"; + FEISHU_APP_SECRET = "$(FEISHU_APP_SECRET)"; + FEISHU_BASE_DOMAIN = "xorbitlab.feishu.cn"; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.xorbitlab.bugger; @@ -414,6 +412,7 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + }; rootObject = 46F86FAA6BBF9AC94A7E4595 /* Project object */; } diff --git a/Bugger.xcodeproj/xcshareddata/xcschemes/Bugger.xcscheme b/Bugger.xcodeproj/xcshareddata/xcschemes/Bugger.xcscheme index ebc307b..7d035da 100644 --- a/Bugger.xcodeproj/xcshareddata/xcschemes/Bugger.xcscheme +++ b/Bugger.xcodeproj/xcshareddata/xcschemes/Bugger.xcscheme @@ -22,13 +22,6 @@ - - - - - - - - diff --git a/Sources/Services/Feishu/FeishuAuthService.swift b/Sources/Services/Feishu/FeishuAuthService.swift index 80aeb4d..06a9288 100644 --- a/Sources/Services/Feishu/FeishuAuthService.swift +++ b/Sources/Services/Feishu/FeishuAuthService.swift @@ -42,6 +42,7 @@ final class FeishuAuthService { } func exchangeCode(_ code: String) async throws -> OAuthTokenData { + BuggerLog.info("Exchanging auth code (len=\(code.count)) for user token...") let tenantToken = try await tenantAccessToken() let url = URL(string: "\(baseURL)/authen/v1/oidc/access_token")! var request = URLRequest(url: url) @@ -52,8 +53,9 @@ final class FeishuAuthService { "grant_type": "authorization_code", "code": code, ] as [String: String]) - // Token endpoints return data at top level, not wrapped in {code, msg, data} - return try await send(request) + let tokenData: OAuthTokenData = try await send(request) + BuggerLog.info("Got token: access=\(tokenData.accessToken.prefix(8))..., refresh=\(tokenData.refreshToken?.prefix(8) ?? "nil")..., expires=\(tokenData.expiresIn)") + return tokenData } func refreshAccessToken(_ refreshToken: String) async throws -> OAuthTokenData { @@ -68,7 +70,8 @@ final class FeishuAuthService { "refresh_token": refreshToken, ] as [String: String]) // Token endpoints return data at top level, not wrapped in {code, msg, data} - return try await send(request) + let tokenData: OAuthTokenData = try await send(request) + return tokenData } func fetchCurrentUserName(accessToken: String) async throws -> String { @@ -114,17 +117,35 @@ final class FeishuAuthService { } private func send(_ request: URLRequest) async throws -> T { + BuggerLog.debug("→ \(request.httpMethod ?? "?") \(request.url?.absoluteString ?? "?")") + if let body = request.httpBody, let bodyStr = String(data: body, encoding: .utf8) { + BuggerLog.debug(" body: \(bodyStr)") + } + if let auth = request.value(forHTTPHeaderField: "Authorization") { + BuggerLog.debug(" auth: \(auth.prefix(20))...") + } + let (data, response) = try await session.data(for: request) guard let httpResponse = response as? HTTPURLResponse else { + BuggerLog.error("← not an HTTP response") throw FeishuError.networkError(nil) } + + let bodyStr = String(data: data, encoding: .utf8) ?? "" + BuggerLog.debug("← \(httpResponse.statusCode) \(bodyStr.prefix(500))") + if httpResponse.statusCode == 401 { + BuggerLog.error("← 401 Unauthorized") throw FeishuError.unauthorized } do { - return try decoder.decode(T.self, from: data) + let decoded = try decoder.decode(T.self, from: data) + BuggerLog.debug(" decoded as \(T.self) ✓") + return decoded } catch { + BuggerLog.error(" decode failed: \(error.localizedDescription)") + BuggerLog.error(" raw body: \(bodyStr.prefix(1000))") throw FeishuError.decodingError(error) } } diff --git a/Sources/Services/TokenManager.swift b/Sources/Services/TokenManager.swift index be73b61..59caa62 100644 --- a/Sources/Services/TokenManager.swift +++ b/Sources/Services/TokenManager.swift @@ -93,16 +93,20 @@ final class TokenManager { func handleCallback(code: String) async throws { guard !code.isEmpty else { + BuggerLog.error("handleCallback: empty code") throw TokenError.invalidCallback } + BuggerLog.info("handleCallback: exchanging code...") state = .authenticating let response = try await authService.exchangeCode(code) + BuggerLog.info("handleCallback: got tokens, storing...") storeTokens( access: response.accessToken, refresh: response.refreshToken ?? "", expiresIn: response.expiresIn ) state = .authenticated + BuggerLog.info("handleCallback: done, authenticated ✓") } func resolveAssigneeName(config: AppConfig, accessToken: String) async throws -> String { diff --git a/Sources/Utils/LocalOAuthServer.swift b/Sources/Utils/LocalOAuthServer.swift index 737a096..f5ca450 100644 --- a/Sources/Utils/LocalOAuthServer.swift +++ b/Sources/Utils/LocalOAuthServer.swift @@ -20,13 +20,15 @@ actor LocalOAuthServer { /// Start listening and return the authorization code when the browser redirects. func receiveCode() async throws -> String { - try await withCheckedThrowingContinuation { continuation in + BuggerLog.info("OAuth server starting on \(self.redirectURI)...") + return try await withCheckedThrowingContinuation { continuation in self.continuation = continuation do { let params = NWParameters.tcp let listener = try NWListener(using: params, on: NWEndpoint.Port(rawValue: port)!) self.listener = listener + BuggerLog.info("OAuth server listening ✓") listener.newConnectionHandler = { [weak self] connection in connection.start(queue: .global()) @@ -60,6 +62,11 @@ actor LocalOAuthServer { // MARK: - Private (actor-isolated) private func didReceive(code: String?, from connection: NWConnection) { + if let code { + BuggerLog.info("OAuth server received code (len=\(code.count))") + } else { + BuggerLog.error("OAuth server received request but no code found") + } guard let code else { Self.sendResponse(to: connection, status: 400, body: errorPage) return diff --git a/Sources/Utils/Logger.swift b/Sources/Utils/Logger.swift new file mode 100644 index 0000000..f990518 --- /dev/null +++ b/Sources/Utils/Logger.swift @@ -0,0 +1,20 @@ +import Foundation +import OSLog + +/// Shared logger for Bugger. View output in Xcode console or Console.app +/// (filter by subsystem: com.xorbitlab.bugger). +enum BuggerLog { + private static let logger = Logger(subsystem: "com.xorbitlab.bugger", category: "general") + + static func info(_ message: String) { + logger.info("\(message, privacy: .public)") + } + + static func error(_ message: String) { + logger.error("\(message, privacy: .public)") + } + + static func debug(_ message: String) { + logger.debug("\(message, privacy: .public)") + } +}