• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supabase-swift / 17238365990

26 Aug 2025 12:38PM UTC coverage: 48.936% (-28.5%) from 77.386%
17238365990

Pull #781

github

web-flow
Merge 95ac7642e into e4d8c3718
Pull Request #781: RFC: Migrate HTTP networking from URLSession to Alamofire

287 of 986 new or added lines in 26 files covered. (29.11%)

1397 existing lines in 30 files now uncovered.

3448 of 7046 relevant lines covered (48.94%)

5.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.95
/Sources/Auth/Internal/SessionStorage.swift
1
//
2
//  SessionStorage.swift
3
//
4
//
5
//  Created by Guilherme Souza on 24/10/23.
6
//
7

8
import Foundation
9

10
struct SessionStorage {
11
  var get: @Sendable () -> Session?
12
  var store: @Sendable (_ session: Session) -> Void
13
  var delete: @Sendable () -> Void
14
}
15

16
extension SessionStorage {
17
  /// Key used to store session on ``AuthLocalStorage``.
18
  ///
19
  /// It uses value from ``AuthClient/Configuration/storageKey`` or default to `supabase.auth.token` if not provided.
20
  static func key(_ clientID: AuthClientID) -> String {
18✔
21
    Dependencies[clientID].configuration.storageKey ?? defaultStorageKey
18✔
22
  }
18✔
23

24
  static func live(clientID: AuthClientID) -> SessionStorage {
6✔
25
    var storage: any AuthLocalStorage {
6✔
26
      Dependencies[clientID].configuration.localStorage
5✔
27
    }
5✔
28

6✔
29
    var logger: (any SupabaseLogger)? {
6✔
UNCOV
30
      Dependencies[clientID].configuration.logger
×
UNCOV
31
    }
×
32

6✔
33
    let migrations: [StorageMigration] = [
6✔
34
      .sessionNewKey(clientID: clientID),
6✔
35
      .storeSessionDirectly(clientID: clientID),
6✔
36
      .useDefaultEncoder(clientID: clientID),
6✔
37
    ]
6✔
38

6✔
39
    var key: String {
6✔
40
      SessionStorage.key(clientID)
5✔
41
    }
5✔
42

6✔
43
    return SessionStorage(
6✔
44
      get: {
6✔
45
        for migration in migrations {
13✔
46
          do {
13✔
47
            try migration.run()
13✔
48
          } catch {
13✔
49
            logger?.error(
×
50
              "Storage migration '\(migration.name)' failed: \(error.localizedDescription)"
×
51
            )
×
52
          }
13✔
53
        }
13✔
54

5✔
55
        do {
5✔
56
          let storedData = try storage.retrieve(key: key)
5✔
57
          return try storedData.flatMap {
5✔
58
            try JSONDecoder().decode(Session.self, from: $0)
2✔
59
          }
2✔
60
        } catch {
5✔
UNCOV
61
          logger?.error("Failed to retrieve session: \(error.localizedDescription)")
×
UNCOV
62
          return nil
×
UNCOV
63
        }
×
64
      },
5✔
65
      store: { session in
6✔
66
        do {
1✔
67
          try storage.store(
1✔
68
            key: key,
1✔
69
            value: JSONEncoder().encode(session)
1✔
70
          )
1✔
71
        } catch {
1✔
72
          logger?.error("Failed to store session: \(error.localizedDescription)")
×
73
        }
1✔
74
      },
1✔
75
      delete: {
6✔
UNCOV
76
        do {
×
UNCOV
77
          try storage.remove(key: key)
×
UNCOV
78
        } catch {
×
79
          logger?.error("Failed to delete session: \(error.localizedDescription)")
×
UNCOV
80
        }
×
UNCOV
81
      }
×
82
    )
6✔
83
  }
6✔
84
}
85

86
struct StorageMigration {
87
  var name: String
88
  var run: @Sendable () throws -> Void
89
}
90

91
extension StorageMigration {
92
  /// Migrate stored session from `supabase.session` key to the custom provided storage key
93
  /// or the default `supabase.auth.token` key.
94
  static func sessionNewKey(clientID: AuthClientID) -> StorageMigration {
6✔
95
    StorageMigration(name: "sessionNewKey") {
6✔
96
      let storage = Dependencies[clientID].configuration.localStorage
5✔
97
      let newKey = SessionStorage.key(clientID)
5✔
98

5✔
99
      if let storedData = try? storage.retrieve(key: "supabase.session") {
5✔
100
        // migrate to new key.
×
101
        try storage.store(key: newKey, value: storedData)
×
102
        try? storage.remove(key: "supabase.session")
×
103
      }
5✔
104
    }
5✔
105
  }
6✔
106

107
  /// Migrate the stored session.
108
  ///
109
  /// Migrate the stored session which used to be stored as:
110
  /// ```json
111
  /// {
112
  ///   "session": <Session>,
113
  ///   "expiration_date": <Date>
114
  /// }
115
  /// ```
116
  /// To directly store the `Session` object.
117
  static func storeSessionDirectly(clientID: AuthClientID) -> StorageMigration {
6✔
118
    struct StoredSession: Codable {
6✔
119
      var session: Session
6✔
120
      var expirationDate: Date
6✔
121
    }
6✔
122

6✔
123
    return StorageMigration(name: "storeSessionDirectly") {
6✔
124
      let storage = Dependencies[clientID].configuration.localStorage
4✔
125
      let key = SessionStorage.key(clientID)
4✔
126

4✔
127
      if let data = try? storage.retrieve(key: key),
4✔
128
        let storedSession = try? AuthClient.Configuration.jsonDecoder.decode(
4✔
129
          StoredSession.self,
4✔
130
          from: data
4✔
131
        )
4✔
132
      {
4✔
133
        let session = try AuthClient.Configuration.jsonEncoder.encode(storedSession.session)
×
134
        try storage.store(key: key, value: session)
×
135
      }
4✔
136
    }
4✔
137
  }
6✔
138

139
  static func useDefaultEncoder(clientID: AuthClientID) -> StorageMigration {
6✔
140
    StorageMigration(name: "useDefaultEncoder") {
6✔
141
      let storage = Dependencies[clientID].configuration.localStorage
4✔
142
      let key = SessionStorage.key(clientID)
4✔
143

4✔
144
      let storedData = try? storage.retrieve(key: key)
4✔
145
      let sessionUsingOldDecoder = storedData.flatMap {
4✔
146
        try? AuthClient.Configuration.jsonDecoder.decode(Session.self, from: $0)
2✔
147
      }
2✔
148

4✔
149
      if let sessionUsingOldDecoder {
4✔
150
        try storage.store(
×
151
          key: key,
×
152
          value: JSONEncoder().encode(sessionUsingOldDecoder)
×
153
        )
×
154
      }
4✔
155
    }
4✔
156
  }
6✔
157
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc