@supabase/auth-js 2.58.1-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/main/AuthAdminApi.d.ts +4 -0
  4. package/dist/main/AuthAdminApi.d.ts.map +1 -0
  5. package/dist/main/AuthAdminApi.js +9 -0
  6. package/dist/main/AuthAdminApi.js.map +1 -0
  7. package/dist/main/AuthClient.d.ts +4 -0
  8. package/dist/main/AuthClient.d.ts.map +1 -0
  9. package/dist/main/AuthClient.js +9 -0
  10. package/dist/main/AuthClient.js.map +1 -0
  11. package/dist/main/GoTrueAdminApi.d.ts +99 -0
  12. package/dist/main/GoTrueAdminApi.d.ts.map +1 -0
  13. package/dist/main/GoTrueAdminApi.js +278 -0
  14. package/dist/main/GoTrueAdminApi.js.map +1 -0
  15. package/dist/main/GoTrueClient.d.ts +531 -0
  16. package/dist/main/GoTrueClient.d.ts.map +1 -0
  17. package/dist/main/GoTrueClient.js +2564 -0
  18. package/dist/main/GoTrueClient.js.map +1 -0
  19. package/dist/main/index.d.ts +9 -0
  20. package/dist/main/index.d.ts.map +1 -0
  21. package/dist/main/index.js +36 -0
  22. package/dist/main/index.js.map +1 -0
  23. package/dist/main/lib/base64url.d.ts +76 -0
  24. package/dist/main/lib/base64url.d.ts.map +1 -0
  25. package/dist/main/lib/base64url.js +269 -0
  26. package/dist/main/lib/base64url.js.map +1 -0
  27. package/dist/main/lib/constants.d.ts +26 -0
  28. package/dist/main/lib/constants.d.ts.map +1 -0
  29. package/dist/main/lib/constants.js +31 -0
  30. package/dist/main/lib/constants.js.map +1 -0
  31. package/dist/main/lib/error-codes.d.ts +7 -0
  32. package/dist/main/lib/error-codes.d.ts.map +1 -0
  33. package/dist/main/lib/error-codes.js +3 -0
  34. package/dist/main/lib/error-codes.js.map +1 -0
  35. package/dist/main/lib/errors.d.ts +100 -0
  36. package/dist/main/lib/errors.d.ts.map +1 -0
  37. package/dist/main/lib/errors.js +137 -0
  38. package/dist/main/lib/errors.js.map +1 -0
  39. package/dist/main/lib/fetch.d.ts +34 -0
  40. package/dist/main/lib/fetch.d.ts.map +1 -0
  41. package/dist/main/lib/fetch.js +194 -0
  42. package/dist/main/lib/fetch.js.map +1 -0
  43. package/dist/main/lib/helpers.d.ts +67 -0
  44. package/dist/main/lib/helpers.d.ts.map +1 -0
  45. package/dist/main/lib/helpers.js +388 -0
  46. package/dist/main/lib/helpers.js.map +1 -0
  47. package/dist/main/lib/local-storage.d.ts +9 -0
  48. package/dist/main/lib/local-storage.d.ts.map +1 -0
  49. package/dist/main/lib/local-storage.js +21 -0
  50. package/dist/main/lib/local-storage.js.map +1 -0
  51. package/dist/main/lib/locks.d.ts +64 -0
  52. package/dist/main/lib/locks.d.ts.map +1 -0
  53. package/dist/main/lib/locks.js +187 -0
  54. package/dist/main/lib/locks.js.map +1 -0
  55. package/dist/main/lib/polyfills.d.ts +5 -0
  56. package/dist/main/lib/polyfills.d.ts.map +1 -0
  57. package/dist/main/lib/polyfills.js +29 -0
  58. package/dist/main/lib/polyfills.js.map +1 -0
  59. package/dist/main/lib/types.d.ts +1130 -0
  60. package/dist/main/lib/types.d.ts.map +1 -0
  61. package/dist/main/lib/types.js +22 -0
  62. package/dist/main/lib/types.js.map +1 -0
  63. package/dist/main/lib/version.d.ts +2 -0
  64. package/dist/main/lib/version.d.ts.map +1 -0
  65. package/dist/main/lib/version.js +11 -0
  66. package/dist/main/lib/version.js.map +1 -0
  67. package/dist/main/lib/web3/ethereum.d.ts +96 -0
  68. package/dist/main/lib/web3/ethereum.d.ts.map +1 -0
  69. package/dist/main/lib/web3/ethereum.js +66 -0
  70. package/dist/main/lib/web3/ethereum.js.map +1 -0
  71. package/dist/main/lib/web3/solana.d.ts +160 -0
  72. package/dist/main/lib/web3/solana.d.ts.map +1 -0
  73. package/dist/main/lib/web3/solana.js +4 -0
  74. package/dist/main/lib/web3/solana.js.map +1 -0
  75. package/dist/main/lib/webauthn.d.ts +274 -0
  76. package/dist/main/lib/webauthn.d.ts.map +1 -0
  77. package/dist/main/lib/webauthn.dom.d.ts +583 -0
  78. package/dist/main/lib/webauthn.dom.d.ts.map +1 -0
  79. package/dist/main/lib/webauthn.dom.js +4 -0
  80. package/dist/main/lib/webauthn.dom.js.map +1 -0
  81. package/dist/main/lib/webauthn.errors.d.ts +80 -0
  82. package/dist/main/lib/webauthn.errors.d.ts.map +1 -0
  83. package/dist/main/lib/webauthn.errors.js +265 -0
  84. package/dist/main/lib/webauthn.errors.js.map +1 -0
  85. package/dist/main/lib/webauthn.js +702 -0
  86. package/dist/main/lib/webauthn.js.map +1 -0
  87. package/dist/module/AuthAdminApi.d.ts +4 -0
  88. package/dist/module/AuthAdminApi.d.ts.map +1 -0
  89. package/dist/module/AuthAdminApi.js +4 -0
  90. package/dist/module/AuthAdminApi.js.map +1 -0
  91. package/dist/module/AuthClient.d.ts +4 -0
  92. package/dist/module/AuthClient.d.ts.map +1 -0
  93. package/dist/module/AuthClient.js +4 -0
  94. package/dist/module/AuthClient.js.map +1 -0
  95. package/dist/module/GoTrueAdminApi.d.ts +99 -0
  96. package/dist/module/GoTrueAdminApi.d.ts.map +1 -0
  97. package/dist/module/GoTrueAdminApi.js +275 -0
  98. package/dist/module/GoTrueAdminApi.js.map +1 -0
  99. package/dist/module/GoTrueClient.d.ts +531 -0
  100. package/dist/module/GoTrueClient.d.ts.map +1 -0
  101. package/dist/module/GoTrueClient.js +2559 -0
  102. package/dist/module/GoTrueClient.js.map +1 -0
  103. package/dist/module/index.d.ts +9 -0
  104. package/dist/module/index.d.ts.map +1 -0
  105. package/dist/module/index.js +9 -0
  106. package/dist/module/index.js.map +1 -0
  107. package/dist/module/lib/base64url.d.ts +76 -0
  108. package/dist/module/lib/base64url.d.ts.map +1 -0
  109. package/dist/module/lib/base64url.js +257 -0
  110. package/dist/module/lib/base64url.js.map +1 -0
  111. package/dist/module/lib/constants.d.ts +26 -0
  112. package/dist/module/lib/constants.d.ts.map +1 -0
  113. package/dist/module/lib/constants.js +28 -0
  114. package/dist/module/lib/constants.js.map +1 -0
  115. package/dist/module/lib/error-codes.d.ts +7 -0
  116. package/dist/module/lib/error-codes.d.ts.map +1 -0
  117. package/dist/module/lib/error-codes.js +2 -0
  118. package/dist/module/lib/error-codes.js.map +1 -0
  119. package/dist/module/lib/errors.d.ts +100 -0
  120. package/dist/module/lib/errors.d.ts.map +1 -0
  121. package/dist/module/lib/errors.js +116 -0
  122. package/dist/module/lib/errors.js.map +1 -0
  123. package/dist/module/lib/fetch.d.ts +34 -0
  124. package/dist/module/lib/fetch.d.ts.map +1 -0
  125. package/dist/module/lib/fetch.js +184 -0
  126. package/dist/module/lib/fetch.js.map +1 -0
  127. package/dist/module/lib/helpers.d.ts +67 -0
  128. package/dist/module/lib/helpers.d.ts.map +1 -0
  129. package/dist/module/lib/helpers.js +329 -0
  130. package/dist/module/lib/helpers.js.map +1 -0
  131. package/dist/module/lib/local-storage.d.ts +9 -0
  132. package/dist/module/lib/local-storage.d.ts.map +1 -0
  133. package/dist/module/lib/local-storage.js +18 -0
  134. package/dist/module/lib/local-storage.js.map +1 -0
  135. package/dist/module/lib/locks.d.ts +64 -0
  136. package/dist/module/lib/locks.d.ts.map +1 -0
  137. package/dist/module/lib/locks.js +179 -0
  138. package/dist/module/lib/locks.js.map +1 -0
  139. package/dist/module/lib/polyfills.d.ts +5 -0
  140. package/dist/module/lib/polyfills.d.ts.map +1 -0
  141. package/dist/module/lib/polyfills.js +26 -0
  142. package/dist/module/lib/polyfills.js.map +1 -0
  143. package/dist/module/lib/types.d.ts +1130 -0
  144. package/dist/module/lib/types.d.ts.map +1 -0
  145. package/dist/module/lib/types.js +19 -0
  146. package/dist/module/lib/types.js.map +1 -0
  147. package/dist/module/lib/version.d.ts +2 -0
  148. package/dist/module/lib/version.d.ts.map +1 -0
  149. package/dist/module/lib/version.js +8 -0
  150. package/dist/module/lib/version.js.map +1 -0
  151. package/dist/module/lib/web3/ethereum.d.ts +96 -0
  152. package/dist/module/lib/web3/ethereum.d.ts.map +1 -0
  153. package/dist/module/lib/web3/ethereum.js +60 -0
  154. package/dist/module/lib/web3/ethereum.js.map +1 -0
  155. package/dist/module/lib/web3/solana.d.ts +160 -0
  156. package/dist/module/lib/web3/solana.d.ts.map +1 -0
  157. package/dist/module/lib/web3/solana.js +3 -0
  158. package/dist/module/lib/web3/solana.js.map +1 -0
  159. package/dist/module/lib/webauthn.d.ts +274 -0
  160. package/dist/module/lib/webauthn.d.ts.map +1 -0
  161. package/dist/module/lib/webauthn.dom.d.ts +583 -0
  162. package/dist/module/lib/webauthn.dom.d.ts.map +1 -0
  163. package/dist/module/lib/webauthn.dom.js +3 -0
  164. package/dist/module/lib/webauthn.dom.js.map +1 -0
  165. package/dist/module/lib/webauthn.errors.d.ts +80 -0
  166. package/dist/module/lib/webauthn.errors.d.ts.map +1 -0
  167. package/dist/module/lib/webauthn.errors.js +257 -0
  168. package/dist/module/lib/webauthn.errors.js.map +1 -0
  169. package/dist/module/lib/webauthn.js +685 -0
  170. package/dist/module/lib/webauthn.js.map +1 -0
  171. package/package.json +49 -0
  172. package/src/AuthAdminApi.ts +5 -0
  173. package/src/AuthClient.ts +5 -0
  174. package/src/GoTrueAdminApi.ts +352 -0
  175. package/src/GoTrueClient.ts +3483 -0
  176. package/src/index.ts +13 -0
  177. package/src/lib/base64url.ts +308 -0
  178. package/src/lib/constants.ts +34 -0
  179. package/src/lib/error-codes.ts +90 -0
  180. package/src/lib/errors.ts +165 -0
  181. package/src/lib/fetch.ts +283 -0
  182. package/src/lib/helpers.ts +416 -0
  183. package/src/lib/local-storage.ts +21 -0
  184. package/src/lib/locks.ts +225 -0
  185. package/src/lib/polyfills.ts +23 -0
  186. package/src/lib/types.ts +1450 -0
  187. package/src/lib/version.ts +7 -0
  188. package/src/lib/web3/ethereum.ts +184 -0
  189. package/src/lib/web3/solana.ts +186 -0
  190. package/src/lib/webauthn.dom.ts +636 -0
  191. package/src/lib/webauthn.errors.ts +317 -0
  192. package/src/lib/webauthn.ts +929 -0
@@ -0,0 +1,283 @@
1
+ import { API_VERSIONS, API_VERSION_HEADER_NAME } from './constants'
2
+ import { expiresAt, looksLikeFetchResponse, parseResponseAPIVersion } from './helpers'
3
+ import {
4
+ AuthResponse,
5
+ AuthResponsePassword,
6
+ SSOResponse,
7
+ GenerateLinkProperties,
8
+ GenerateLinkResponse,
9
+ User,
10
+ UserResponse,
11
+ } from './types'
12
+ import {
13
+ AuthApiError,
14
+ AuthRetryableFetchError,
15
+ AuthWeakPasswordError,
16
+ AuthUnknownError,
17
+ AuthSessionMissingError,
18
+ } from './errors'
19
+
20
+ export type Fetch = typeof fetch
21
+
22
+ export interface FetchOptions {
23
+ headers?: {
24
+ [key: string]: string
25
+ }
26
+ noResolveJson?: boolean
27
+ }
28
+
29
+ export interface FetchParameters {
30
+ signal?: AbortSignal
31
+ }
32
+
33
+ export type RequestMethodType = 'GET' | 'POST' | 'PUT' | 'DELETE'
34
+
35
+ const _getErrorMessage = (err: any): string =>
36
+ err.msg || err.message || err.error_description || err.error || JSON.stringify(err)
37
+
38
+ const NETWORK_ERROR_CODES = [502, 503, 504]
39
+
40
+ export async function handleError(error: unknown) {
41
+ if (!looksLikeFetchResponse(error)) {
42
+ throw new AuthRetryableFetchError(_getErrorMessage(error), 0)
43
+ }
44
+
45
+ if (NETWORK_ERROR_CODES.includes(error.status)) {
46
+ // status in 500...599 range - server had an error, request might be retryed.
47
+ throw new AuthRetryableFetchError(_getErrorMessage(error), error.status)
48
+ }
49
+
50
+ let data: any
51
+ try {
52
+ data = await error.json()
53
+ } catch (e: any) {
54
+ throw new AuthUnknownError(_getErrorMessage(e), e)
55
+ }
56
+
57
+ let errorCode: string | undefined = undefined
58
+
59
+ const responseAPIVersion = parseResponseAPIVersion(error)
60
+ if (
61
+ responseAPIVersion &&
62
+ responseAPIVersion.getTime() >= API_VERSIONS['2024-01-01'].timestamp &&
63
+ typeof data === 'object' &&
64
+ data &&
65
+ typeof data.code === 'string'
66
+ ) {
67
+ errorCode = data.code
68
+ } else if (typeof data === 'object' && data && typeof data.error_code === 'string') {
69
+ errorCode = data.error_code
70
+ }
71
+
72
+ if (!errorCode) {
73
+ // Legacy support for weak password errors, when there were no error codes
74
+ if (
75
+ typeof data === 'object' &&
76
+ data &&
77
+ typeof data.weak_password === 'object' &&
78
+ data.weak_password &&
79
+ Array.isArray(data.weak_password.reasons) &&
80
+ data.weak_password.reasons.length &&
81
+ data.weak_password.reasons.reduce((a: boolean, i: any) => a && typeof i === 'string', true)
82
+ ) {
83
+ throw new AuthWeakPasswordError(
84
+ _getErrorMessage(data),
85
+ error.status,
86
+ data.weak_password.reasons
87
+ )
88
+ }
89
+ } else if (errorCode === 'weak_password') {
90
+ throw new AuthWeakPasswordError(
91
+ _getErrorMessage(data),
92
+ error.status,
93
+ data.weak_password?.reasons || []
94
+ )
95
+ } else if (errorCode === 'session_not_found') {
96
+ // The `session_id` inside the JWT does not correspond to a row in the
97
+ // `sessions` table. This usually means the user has signed out, has been
98
+ // deleted, or their session has somehow been terminated.
99
+ throw new AuthSessionMissingError()
100
+ }
101
+
102
+ throw new AuthApiError(_getErrorMessage(data), error.status || 500, errorCode)
103
+ }
104
+
105
+ const _getRequestParams = (
106
+ method: RequestMethodType,
107
+ options?: FetchOptions,
108
+ parameters?: FetchParameters,
109
+ body?: object
110
+ ) => {
111
+ const params: { [k: string]: any } = { method, headers: options?.headers || {} }
112
+
113
+ if (method === 'GET') {
114
+ return params
115
+ }
116
+
117
+ params.headers = { 'Content-Type': 'application/json;charset=UTF-8', ...options?.headers }
118
+ params.body = JSON.stringify(body)
119
+ return { ...params, ...parameters }
120
+ }
121
+
122
+ interface GotrueRequestOptions extends FetchOptions {
123
+ jwt?: string
124
+ redirectTo?: string
125
+ body?: object
126
+ query?: { [key: string]: string }
127
+ /**
128
+ * Function that transforms api response from gotrue into a desirable / standardised format
129
+ */
130
+ xform?: (data: any) => any
131
+ }
132
+
133
+ export async function _request(
134
+ fetcher: Fetch,
135
+ method: RequestMethodType,
136
+ url: string,
137
+ options?: GotrueRequestOptions
138
+ ) {
139
+ const headers = {
140
+ ...options?.headers,
141
+ }
142
+
143
+ if (!headers[API_VERSION_HEADER_NAME]) {
144
+ headers[API_VERSION_HEADER_NAME] = API_VERSIONS['2024-01-01'].name
145
+ }
146
+
147
+ if (options?.jwt) {
148
+ headers['Authorization'] = `Bearer ${options.jwt}`
149
+ }
150
+
151
+ const qs = options?.query ?? {}
152
+ if (options?.redirectTo) {
153
+ qs['redirect_to'] = options.redirectTo
154
+ }
155
+
156
+ const queryString = Object.keys(qs).length ? '?' + new URLSearchParams(qs).toString() : ''
157
+ const data = await _handleRequest(
158
+ fetcher,
159
+ method,
160
+ url + queryString,
161
+ {
162
+ headers,
163
+ noResolveJson: options?.noResolveJson,
164
+ },
165
+ {},
166
+ options?.body
167
+ )
168
+ return options?.xform ? options?.xform(data) : { data: { ...data }, error: null }
169
+ }
170
+
171
+ async function _handleRequest(
172
+ fetcher: Fetch,
173
+ method: RequestMethodType,
174
+ url: string,
175
+ options?: FetchOptions,
176
+ parameters?: FetchParameters,
177
+ body?: object
178
+ ): Promise<any> {
179
+ const requestParams = _getRequestParams(method, options, parameters, body)
180
+
181
+ let result: any
182
+
183
+ try {
184
+ result = await fetcher(url, {
185
+ ...requestParams,
186
+ })
187
+ } catch (e) {
188
+ console.error(e)
189
+
190
+ // fetch failed, likely due to a network or CORS error
191
+ throw new AuthRetryableFetchError(_getErrorMessage(e), 0)
192
+ }
193
+
194
+ if (!result.ok) {
195
+ await handleError(result)
196
+ }
197
+
198
+ if (options?.noResolveJson) {
199
+ return result
200
+ }
201
+
202
+ try {
203
+ return await result.json()
204
+ } catch (e: any) {
205
+ await handleError(e)
206
+ }
207
+ }
208
+
209
+ export function _sessionResponse(data: any): AuthResponse {
210
+ let session = null
211
+ if (hasSession(data)) {
212
+ session = { ...data }
213
+
214
+ if (!data.expires_at) {
215
+ session.expires_at = expiresAt(data.expires_in)
216
+ }
217
+ }
218
+
219
+ const user: User = data.user ?? (data as User)
220
+ return { data: { session, user }, error: null }
221
+ }
222
+
223
+ export function _sessionResponsePassword(data: any): AuthResponsePassword {
224
+ const response = _sessionResponse(data) as AuthResponsePassword
225
+
226
+ if (
227
+ !response.error &&
228
+ data.weak_password &&
229
+ typeof data.weak_password === 'object' &&
230
+ Array.isArray(data.weak_password.reasons) &&
231
+ data.weak_password.reasons.length &&
232
+ data.weak_password.message &&
233
+ typeof data.weak_password.message === 'string' &&
234
+ data.weak_password.reasons.reduce((a: boolean, i: any) => a && typeof i === 'string', true)
235
+ ) {
236
+ response.data.weak_password = data.weak_password
237
+ }
238
+
239
+ return response
240
+ }
241
+
242
+ export function _userResponse(data: any): UserResponse {
243
+ const user: User = data.user ?? (data as User)
244
+ return { data: { user }, error: null }
245
+ }
246
+
247
+ export function _ssoResponse(data: any): SSOResponse {
248
+ return { data, error: null }
249
+ }
250
+
251
+ export function _generateLinkResponse(data: any): GenerateLinkResponse {
252
+ const { action_link, email_otp, hashed_token, redirect_to, verification_type, ...rest } = data
253
+
254
+ const properties: GenerateLinkProperties = {
255
+ action_link,
256
+ email_otp,
257
+ hashed_token,
258
+ redirect_to,
259
+ verification_type,
260
+ }
261
+
262
+ const user: User = { ...rest }
263
+ return {
264
+ data: {
265
+ properties,
266
+ user,
267
+ },
268
+ error: null,
269
+ }
270
+ }
271
+
272
+ export function _noResolveJsonResponse(data: any): Response {
273
+ return data
274
+ }
275
+
276
+ /**
277
+ * hasSession checks if the response object contains a valid session
278
+ * @param data A response object
279
+ * @returns true if a session is in the response
280
+ */
281
+ function hasSession(data: any): boolean {
282
+ return data.access_token && data.refresh_token && data.expires_in
283
+ }
@@ -0,0 +1,416 @@
1
+ import { API_VERSION_HEADER_NAME, BASE64URL_REGEX } from './constants'
2
+ import { AuthInvalidJwtError } from './errors'
3
+ import { base64UrlToUint8Array, stringFromBase64URL } from './base64url'
4
+ import { JwtHeader, JwtPayload, SupportedStorage, User } from './types'
5
+ import { Uint8Array_ } from './webauthn.dom'
6
+
7
+ export function expiresAt(expiresIn: number) {
8
+ const timeNow = Math.round(Date.now() / 1000)
9
+ return timeNow + expiresIn
10
+ }
11
+
12
+ export function uuid() {
13
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
14
+ const r = (Math.random() * 16) | 0,
15
+ v = c == 'x' ? r : (r & 0x3) | 0x8
16
+ return v.toString(16)
17
+ })
18
+ }
19
+
20
+ export const isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined'
21
+
22
+ const localStorageWriteTests = {
23
+ tested: false,
24
+ writable: false,
25
+ }
26
+
27
+ /**
28
+ * Checks whether localStorage is supported on this browser.
29
+ */
30
+ export const supportsLocalStorage = () => {
31
+ if (!isBrowser()) {
32
+ return false
33
+ }
34
+
35
+ try {
36
+ if (typeof globalThis.localStorage !== 'object') {
37
+ return false
38
+ }
39
+ } catch (e) {
40
+ // DOM exception when accessing `localStorage`
41
+ return false
42
+ }
43
+
44
+ if (localStorageWriteTests.tested) {
45
+ return localStorageWriteTests.writable
46
+ }
47
+
48
+ const randomKey = `lswt-${Math.random()}${Math.random()}`
49
+
50
+ try {
51
+ globalThis.localStorage.setItem(randomKey, randomKey)
52
+ globalThis.localStorage.removeItem(randomKey)
53
+
54
+ localStorageWriteTests.tested = true
55
+ localStorageWriteTests.writable = true
56
+ } catch (e) {
57
+ // localStorage can't be written to
58
+ // https://www.chromium.org/for-testers/bug-reporting-guidelines/uncaught-securityerror-failed-to-read-the-localstorage-property-from-window-access-is-denied-for-this-document
59
+
60
+ localStorageWriteTests.tested = true
61
+ localStorageWriteTests.writable = false
62
+ }
63
+
64
+ return localStorageWriteTests.writable
65
+ }
66
+
67
+ /**
68
+ * Extracts parameters encoded in the URL both in the query and fragment.
69
+ */
70
+ export function parseParametersFromURL(href: string) {
71
+ const result: { [parameter: string]: string } = {}
72
+
73
+ const url = new URL(href)
74
+
75
+ if (url.hash && url.hash[0] === '#') {
76
+ try {
77
+ const hashSearchParams = new URLSearchParams(url.hash.substring(1))
78
+ hashSearchParams.forEach((value, key) => {
79
+ result[key] = value
80
+ })
81
+ } catch (e: any) {
82
+ // hash is not a query string
83
+ }
84
+ }
85
+
86
+ // search parameters take precedence over hash parameters
87
+ url.searchParams.forEach((value, key) => {
88
+ result[key] = value
89
+ })
90
+
91
+ return result
92
+ }
93
+
94
+ type Fetch = typeof fetch
95
+
96
+ export const resolveFetch = (customFetch?: Fetch): Fetch => {
97
+ let _fetch: Fetch
98
+ if (customFetch) {
99
+ _fetch = customFetch
100
+ } else if (typeof fetch === 'undefined') {
101
+ _fetch = (...args) =>
102
+ import('@supabase/node-fetch' as any).then(({ default: fetch }) => fetch(...args))
103
+ } else {
104
+ _fetch = fetch
105
+ }
106
+ return (...args) => _fetch(...args)
107
+ }
108
+
109
+ export const looksLikeFetchResponse = (maybeResponse: unknown): maybeResponse is Response => {
110
+ return (
111
+ typeof maybeResponse === 'object' &&
112
+ maybeResponse !== null &&
113
+ 'status' in maybeResponse &&
114
+ 'ok' in maybeResponse &&
115
+ 'json' in maybeResponse &&
116
+ typeof (maybeResponse as any).json === 'function'
117
+ )
118
+ }
119
+
120
+ // Storage helpers
121
+ export const setItemAsync = async (
122
+ storage: SupportedStorage,
123
+ key: string,
124
+ data: any
125
+ ): Promise<void> => {
126
+ await storage.setItem(key, JSON.stringify(data))
127
+ }
128
+
129
+ export const getItemAsync = async (storage: SupportedStorage, key: string): Promise<unknown> => {
130
+ const value = await storage.getItem(key)
131
+
132
+ if (!value) {
133
+ return null
134
+ }
135
+
136
+ try {
137
+ return JSON.parse(value)
138
+ } catch {
139
+ return value
140
+ }
141
+ }
142
+
143
+ export const removeItemAsync = async (storage: SupportedStorage, key: string): Promise<void> => {
144
+ await storage.removeItem(key)
145
+ }
146
+
147
+ /**
148
+ * A deferred represents some asynchronous work that is not yet finished, which
149
+ * may or may not culminate in a value.
150
+ * Taken from: https://github.com/mike-north/types/blob/master/src/async.ts
151
+ */
152
+ export class Deferred<T = any> {
153
+ public static promiseConstructor: PromiseConstructor = Promise
154
+
155
+ public readonly promise!: PromiseLike<T>
156
+
157
+ public readonly resolve!: (value?: T | PromiseLike<T>) => void
158
+
159
+ public readonly reject!: (reason?: any) => any
160
+
161
+ public constructor() {
162
+ // eslint-disable-next-line @typescript-eslint/no-extra-semi
163
+ ;(this as any).promise = new Deferred.promiseConstructor((res, rej) => {
164
+ // eslint-disable-next-line @typescript-eslint/no-extra-semi
165
+ ;(this as any).resolve = res
166
+ // eslint-disable-next-line @typescript-eslint/no-extra-semi
167
+ ;(this as any).reject = rej
168
+ })
169
+ }
170
+ }
171
+
172
+ export function decodeJWT(token: string): {
173
+ header: JwtHeader
174
+ payload: JwtPayload
175
+ signature: Uint8Array_
176
+ raw: {
177
+ header: string
178
+ payload: string
179
+ }
180
+ } {
181
+ const parts = token.split('.')
182
+
183
+ if (parts.length !== 3) {
184
+ throw new AuthInvalidJwtError('Invalid JWT structure')
185
+ }
186
+
187
+ // Regex checks for base64url format
188
+ for (let i = 0; i < parts.length; i++) {
189
+ if (!BASE64URL_REGEX.test(parts[i] as string)) {
190
+ throw new AuthInvalidJwtError('JWT not in base64url format')
191
+ }
192
+ }
193
+ const data = {
194
+ // using base64url lib
195
+ header: JSON.parse(stringFromBase64URL(parts[0])),
196
+ payload: JSON.parse(stringFromBase64URL(parts[1])),
197
+ signature: base64UrlToUint8Array(parts[2]),
198
+ raw: {
199
+ header: parts[0],
200
+ payload: parts[1],
201
+ },
202
+ }
203
+ return data
204
+ }
205
+
206
+ /**
207
+ * Creates a promise that resolves to null after some time.
208
+ */
209
+ export async function sleep(time: number): Promise<null> {
210
+ return await new Promise((accept) => {
211
+ setTimeout(() => accept(null), time)
212
+ })
213
+ }
214
+
215
+ /**
216
+ * Converts the provided async function into a retryable function. Each result
217
+ * or thrown error is sent to the isRetryable function which should return true
218
+ * if the function should run again.
219
+ */
220
+ export function retryable<T>(
221
+ fn: (attempt: number) => Promise<T>,
222
+ isRetryable: (attempt: number, error: any | null, result?: T) => boolean
223
+ ): Promise<T> {
224
+ const promise = new Promise<T>((accept, reject) => {
225
+ // eslint-disable-next-line @typescript-eslint/no-extra-semi
226
+ ;(async () => {
227
+ for (let attempt = 0; attempt < Infinity; attempt++) {
228
+ try {
229
+ const result = await fn(attempt)
230
+
231
+ if (!isRetryable(attempt, null, result)) {
232
+ accept(result)
233
+ return
234
+ }
235
+ } catch (e: any) {
236
+ if (!isRetryable(attempt, e)) {
237
+ reject(e)
238
+ return
239
+ }
240
+ }
241
+ }
242
+ })()
243
+ })
244
+
245
+ return promise
246
+ }
247
+
248
+ function dec2hex(dec: number) {
249
+ return ('0' + dec.toString(16)).substr(-2)
250
+ }
251
+
252
+ // Functions below taken from: https://stackoverflow.com/questions/63309409/creating-a-code-verifier-and-challenge-for-pkce-auth-on-spotify-api-in-reactjs
253
+ export function generatePKCEVerifier() {
254
+ const verifierLength = 56
255
+ const array = new Uint32Array(verifierLength)
256
+ if (typeof crypto === 'undefined') {
257
+ const charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'
258
+ const charSetLen = charSet.length
259
+ let verifier = ''
260
+ for (let i = 0; i < verifierLength; i++) {
261
+ verifier += charSet.charAt(Math.floor(Math.random() * charSetLen))
262
+ }
263
+ return verifier
264
+ }
265
+ crypto.getRandomValues(array)
266
+ return Array.from(array, dec2hex).join('')
267
+ }
268
+
269
+ async function sha256(randomString: string) {
270
+ const encoder = new TextEncoder()
271
+ const encodedData = encoder.encode(randomString)
272
+ const hash = await crypto.subtle.digest('SHA-256', encodedData)
273
+ const bytes = new Uint8Array(hash)
274
+
275
+ return Array.from(bytes)
276
+ .map((c) => String.fromCharCode(c))
277
+ .join('')
278
+ }
279
+
280
+ export async function generatePKCEChallenge(verifier: string) {
281
+ const hasCryptoSupport =
282
+ typeof crypto !== 'undefined' &&
283
+ typeof crypto.subtle !== 'undefined' &&
284
+ typeof TextEncoder !== 'undefined'
285
+
286
+ if (!hasCryptoSupport) {
287
+ console.warn(
288
+ 'WebCrypto API is not supported. Code challenge method will default to use plain instead of sha256.'
289
+ )
290
+ return verifier
291
+ }
292
+ const hashed = await sha256(verifier)
293
+ return btoa(hashed).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
294
+ }
295
+
296
+ export async function getCodeChallengeAndMethod(
297
+ storage: SupportedStorage,
298
+ storageKey: string,
299
+ isPasswordRecovery = false
300
+ ) {
301
+ const codeVerifier = generatePKCEVerifier()
302
+ let storedCodeVerifier = codeVerifier
303
+ if (isPasswordRecovery) {
304
+ storedCodeVerifier += '/PASSWORD_RECOVERY'
305
+ }
306
+ await setItemAsync(storage, `${storageKey}-code-verifier`, storedCodeVerifier)
307
+ const codeChallenge = await generatePKCEChallenge(codeVerifier)
308
+ const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
309
+ return [codeChallenge, codeChallengeMethod]
310
+ }
311
+
312
+ /** Parses the API version which is 2YYY-MM-DD. */
313
+ const API_VERSION_REGEX = /^2[0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-9]|3[0-1])$/i
314
+
315
+ export function parseResponseAPIVersion(response: Response) {
316
+ const apiVersion = response.headers.get(API_VERSION_HEADER_NAME)
317
+
318
+ if (!apiVersion) {
319
+ return null
320
+ }
321
+
322
+ if (!apiVersion.match(API_VERSION_REGEX)) {
323
+ return null
324
+ }
325
+
326
+ try {
327
+ const date = new Date(`${apiVersion}T00:00:00.0Z`)
328
+ return date
329
+ } catch (e: any) {
330
+ return null
331
+ }
332
+ }
333
+
334
+ export function validateExp(exp: number) {
335
+ if (!exp) {
336
+ throw new Error('Missing exp claim')
337
+ }
338
+ const timeNow = Math.floor(Date.now() / 1000)
339
+ if (exp <= timeNow) {
340
+ throw new Error('JWT has expired')
341
+ }
342
+ }
343
+
344
+ export function getAlgorithm(
345
+ alg: 'HS256' | 'RS256' | 'ES256'
346
+ ): RsaHashedImportParams | EcKeyImportParams {
347
+ switch (alg) {
348
+ case 'RS256':
349
+ return {
350
+ name: 'RSASSA-PKCS1-v1_5',
351
+ hash: { name: 'SHA-256' },
352
+ }
353
+ case 'ES256':
354
+ return {
355
+ name: 'ECDSA',
356
+ namedCurve: 'P-256',
357
+ hash: { name: 'SHA-256' },
358
+ }
359
+ default:
360
+ throw new Error('Invalid alg claim')
361
+ }
362
+ }
363
+
364
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
365
+
366
+ export function validateUUID(str: string) {
367
+ if (!UUID_REGEX.test(str)) {
368
+ throw new Error('@supabase/auth-js: Expected parameter to be UUID but is not')
369
+ }
370
+ }
371
+
372
+ export function userNotAvailableProxy(): User {
373
+ const proxyTarget = {} as User
374
+
375
+ return new Proxy(proxyTarget, {
376
+ get: (target: any, prop: string) => {
377
+ if (prop === '__isUserNotAvailableProxy') {
378
+ return true
379
+ }
380
+ // Preventative check for common problematic symbols during cloning/inspection
381
+ // These symbols might be accessed by structuredClone or other internal mechanisms.
382
+ if (typeof prop === 'symbol') {
383
+ const sProp = (prop as symbol).toString()
384
+ if (
385
+ sProp === 'Symbol(Symbol.toPrimitive)' ||
386
+ sProp === 'Symbol(Symbol.toStringTag)' ||
387
+ sProp === 'Symbol(util.inspect.custom)'
388
+ ) {
389
+ // Node.js util.inspect
390
+ return undefined
391
+ }
392
+ }
393
+ throw new Error(
394
+ `@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Accessing the "${prop}" property of the session object is not supported. Please use getUser() instead.`
395
+ )
396
+ },
397
+ set: (_target: any, prop: string) => {
398
+ throw new Error(
399
+ `@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Setting the "${prop}" property of the session object is not supported. Please use getUser() to fetch a user object you can manipulate.`
400
+ )
401
+ },
402
+ deleteProperty: (_target: any, prop: string) => {
403
+ throw new Error(
404
+ `@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Deleting the "${prop}" property of the session object is not supported. Please use getUser() to fetch a user object you can manipulate.`
405
+ )
406
+ },
407
+ })
408
+ }
409
+
410
+ /**
411
+ * Deep clones a JSON-serializable object using JSON.parse(JSON.stringify(obj)).
412
+ * Note: Only works for JSON-safe data.
413
+ */
414
+ export function deepClone<T>(obj: T): T {
415
+ return JSON.parse(JSON.stringify(obj))
416
+ }
@@ -0,0 +1,21 @@
1
+ import { SupportedStorage } from './types'
2
+
3
+ /**
4
+ * Returns a localStorage-like object that stores the key-value pairs in
5
+ * memory.
6
+ */
7
+ export function memoryLocalStorageAdapter(store: { [key: string]: string } = {}): SupportedStorage {
8
+ return {
9
+ getItem: (key) => {
10
+ return store[key] || null
11
+ },
12
+
13
+ setItem: (key, value) => {
14
+ store[key] = value
15
+ },
16
+
17
+ removeItem: (key) => {
18
+ delete store[key]
19
+ },
20
+ }
21
+ }