@faable/auth-js 1.2.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 (53) hide show
  1. package/README.md +3 -0
  2. package/dist/Base.d.ts +8 -0
  3. package/dist/Base.d.ts.map +1 -0
  4. package/dist/Base.js +16 -0
  5. package/dist/BaseLog.d.ts +11 -0
  6. package/dist/BaseLog.d.ts.map +1 -0
  7. package/dist/BaseLog.js +21 -0
  8. package/dist/FaableAuthApi.d.ts +14 -0
  9. package/dist/FaableAuthApi.d.ts.map +1 -0
  10. package/dist/FaableAuthApi.js +37 -0
  11. package/dist/FaableAuthClient.d.ts +227 -0
  12. package/dist/FaableAuthClient.d.ts.map +1 -0
  13. package/dist/FaableAuthClient.js +1073 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +13 -0
  17. package/dist/lib/constants.d.ts +11 -0
  18. package/dist/lib/constants.d.ts.map +1 -0
  19. package/dist/lib/constants.js +13 -0
  20. package/dist/lib/errors.d.ts +83 -0
  21. package/dist/lib/errors.d.ts.map +1 -0
  22. package/dist/lib/errors.js +100 -0
  23. package/dist/lib/fetch.d.ts +8 -0
  24. package/dist/lib/fetch.d.ts.map +1 -0
  25. package/dist/lib/fetch.js +53 -0
  26. package/dist/lib/helpers.d.ts +42 -0
  27. package/dist/lib/helpers.d.ts.map +1 -0
  28. package/dist/lib/helpers.js +257 -0
  29. package/dist/lib/jwt.d.ts +56 -0
  30. package/dist/lib/jwt.d.ts.map +1 -0
  31. package/dist/lib/jwt.js +139 -0
  32. package/dist/lib/local-storage.d.ts +13 -0
  33. package/dist/lib/local-storage.d.ts.map +1 -0
  34. package/dist/lib/local-storage.js +45 -0
  35. package/dist/lib/storage_helpers.d.ts +5 -0
  36. package/dist/lib/storage_helpers.d.ts.map +1 -0
  37. package/dist/lib/storage_helpers.js +34 -0
  38. package/dist/lib/types.d.ts +384 -0
  39. package/dist/lib/types.d.ts.map +1 -0
  40. package/dist/lib/types.js +6 -0
  41. package/dist/lib/version.d.ts +2 -0
  42. package/dist/lib/version.d.ts.map +1 -0
  43. package/dist/lib/version.js +5 -0
  44. package/dist/lock/Lock.d.ts +20 -0
  45. package/dist/lock/Lock.d.ts.map +1 -0
  46. package/dist/lock/Lock.js +82 -0
  47. package/dist/lock/locks.d.ts +64 -0
  48. package/dist/lock/locks.d.ts.map +1 -0
  49. package/dist/lock/locks.js +137 -0
  50. package/dist/utils.d.ts +18 -0
  51. package/dist/utils.d.ts.map +1 -0
  52. package/dist/utils.js +88 -0
  53. package/package.json +31 -0
@@ -0,0 +1,1073 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.FaableAuthClient = void 0;
16
+ const utils_1 = require("./utils");
17
+ const jwt_1 = require("./lib/jwt");
18
+ const helpers_1 = require("./lib/helpers");
19
+ const constants_1 = require("./lib/constants");
20
+ const local_storage_1 = require("./lib/local-storage");
21
+ const errors_1 = require("./lib/errors");
22
+ const storage_helpers_1 = require("./lib/storage_helpers");
23
+ const FaableAuthApi_1 = __importDefault(require("./FaableAuthApi"));
24
+ const locks_1 = require("./lock/locks");
25
+ const fetch_1 = require("./lib/fetch");
26
+ const Base_1 = require("./Base");
27
+ const Lock_1 = require("./lock/Lock");
28
+ /** Current session will be checked for refresh at this interval. */
29
+ const AUTO_REFRESH_TICK_DURATION = 30 * 1000;
30
+ /**
31
+ * A token refresh will be attempted this many ticks before the current session expires. */
32
+ const AUTO_REFRESH_TICK_THRESHOLD = 3;
33
+ class FaableAuthClient extends Base_1.Base {
34
+ constructor(config) {
35
+ var _a;
36
+ super({ debug: config.debug });
37
+ this.initializePromise = null;
38
+ this.detectSessionInUrl = true;
39
+ this.autoRefreshTicker = null;
40
+ this.visibilityChangedCallback = null;
41
+ this.refreshingDeferred = null;
42
+ /**
43
+ * Used to broadcast state change events to other tabs listening.
44
+ */
45
+ this.broadcastChannel = null;
46
+ this.stateChangeEmitters = new Map();
47
+ this.sessionCheckExpiryDays = 1;
48
+ this.redirect_uri = config.redirect_uri || "";
49
+ this.domainUrl = (0, utils_1.getDomain)(config.domain);
50
+ this.tokenIssuer = (0, utils_1.getTokenIssuer)("", this.domainUrl);
51
+ this.clientId = config.clientId;
52
+ this.api = new FaableAuthApi_1.default(this.domainUrl, { debug: config.debug });
53
+ this.storageKey = config.storageKey || constants_1.STORAGE_KEY;
54
+ this.flowType = config.flowType || "implicit";
55
+ this.storage = config.storage || local_storage_1.localStorageAdapter;
56
+ this.lock = new Lock_1.Lock({
57
+ lock: config.lock,
58
+ storageKey: this.storageKey,
59
+ debug: config.debug,
60
+ });
61
+ if ((0, helpers_1.isBrowser)() &&
62
+ globalThis.BroadcastChannel &&
63
+ // this.persistSession &&
64
+ this.storageKey) {
65
+ try {
66
+ this.broadcastChannel = new globalThis.BroadcastChannel(this.storageKey);
67
+ }
68
+ catch (e) {
69
+ console.error("Failed to create a new BroadcastChannel, multi-tab state changes will not be available", e);
70
+ }
71
+ (_a = this.broadcastChannel) === null || _a === void 0 ? void 0 : _a.addEventListener("message", (event) => __awaiter(this, void 0, void 0, function* () {
72
+ this._debug("received broadcast notification from other tab or client", event);
73
+ yield this._notifyAllSubscribers(event.data.event, event.data.session, false); // broadcast = false so we don't get an endless loop of messages
74
+ }));
75
+ }
76
+ this.autoRefreshToken = true;
77
+ this.initialize();
78
+ }
79
+ /**
80
+ * Initializes the client session either from the url or from storage.
81
+ * This method is automatically called when instantiating the client, but should also be called
82
+ * manually when checking for an error from an auth redirect (oauth, magiclink, password recovery, etc).
83
+ */
84
+ initialize() {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ if (this.initializePromise) {
87
+ return yield this.initializePromise;
88
+ }
89
+ this.initializePromise = (() => __awaiter(this, void 0, void 0, function* () {
90
+ return yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
91
+ return yield this._initialize();
92
+ }));
93
+ }))();
94
+ return yield this.initializePromise;
95
+ });
96
+ }
97
+ /**
98
+ * IMPORTANT:
99
+ * 1. Never throw in this method, as it is called from the constructor
100
+ * 2. Never return a session from this method as it would be cached over
101
+ * the whole lifetime of the client
102
+ */
103
+ _initialize() {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ try {
106
+ const isPKCEFlow = (0, helpers_1.isBrowser)() ? yield this._isPKCEFlow() : false;
107
+ this._debug("#_initialize()", "begin", "is PKCE flow", isPKCEFlow);
108
+ if (isPKCEFlow ||
109
+ (this.detectSessionInUrl && this._isImplicitGrantFlow())) {
110
+ const { data, error } = yield this._getSessionFromURL(isPKCEFlow);
111
+ if (error) {
112
+ this._debug("#_initialize()", "error detecting session from URL", error);
113
+ // hacky workaround to keep the existing session if there's an error returned from identity linking
114
+ // TODO: once error codes are ready, we should match against it instead of the message
115
+ if ((error === null || error === void 0 ? void 0 : error.message) === "Identity is already linked" ||
116
+ (error === null || error === void 0 ? void 0 : error.message) === "Identity is already linked to another user") {
117
+ return { error };
118
+ }
119
+ // failed login attempt via url,
120
+ // remove old session as in verifyOtp, signUp and signInWith*
121
+ yield this._removeSession();
122
+ return { error };
123
+ }
124
+ const { session, redirectType } = data;
125
+ this._debug("#_initialize()", "detected session in URL", session, "redirect type", redirectType);
126
+ yield this._saveSession(session);
127
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
128
+ if (redirectType === "recovery") {
129
+ yield this._notifyAllSubscribers("PASSWORD_RECOVERY", session);
130
+ }
131
+ else {
132
+ yield this._notifyAllSubscribers("SIGNED_IN", session);
133
+ }
134
+ }), 0);
135
+ return { error: null };
136
+ }
137
+ // no login attempt via callback url try to recover session from storage
138
+ yield this._recoverAndRefresh();
139
+ return { error: null };
140
+ }
141
+ catch (error) {
142
+ if ((0, errors_1.isAuthError)(error)) {
143
+ return { error };
144
+ }
145
+ return {
146
+ error: new errors_1.AuthUnknownError("Unexpected error during initialization", error),
147
+ };
148
+ }
149
+ finally {
150
+ yield this._handleVisibilityChange();
151
+ this._debug("#_initialize()", "end");
152
+ }
153
+ });
154
+ }
155
+ /**
156
+ * Gets the session data from a URL string
157
+ */
158
+ _getSessionFromURL(isPKCEFlow) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ try {
161
+ if (!(0, helpers_1.isBrowser)())
162
+ throw new errors_1.AuthImplicitGrantRedirectError("No browser detected.");
163
+ if (this.flowType === "implicit" && !this._isImplicitGrantFlow()) {
164
+ throw new errors_1.AuthImplicitGrantRedirectError("Not a valid implicit grant flow url.");
165
+ }
166
+ else if (this.flowType == "pkce" && !isPKCEFlow) {
167
+ throw new errors_1.AuthPKCEGrantCodeExchangeError("Not a valid PKCE flow url.");
168
+ }
169
+ const params = (0, helpers_1.parseParametersFromURL)(window.location.href);
170
+ if (isPKCEFlow) {
171
+ if (!params.code)
172
+ throw new errors_1.AuthPKCEGrantCodeExchangeError("No code detected.");
173
+ const { data, error } = yield this._exchangeCodeForSession(params.code);
174
+ if (error)
175
+ throw error;
176
+ const url = new URL(window.location.href);
177
+ url.searchParams.delete("code");
178
+ window.history.replaceState(window.history.state, "", url.toString());
179
+ return {
180
+ data: { session: data.session, redirectType: null },
181
+ error: null,
182
+ };
183
+ }
184
+ if (params.error || params.error_description || params.error_code) {
185
+ throw new errors_1.AuthImplicitGrantRedirectError(params.error_description ||
186
+ "Error in URL with unspecified error_description", {
187
+ error: params.error || "unspecified_error",
188
+ code: params.error_code || "unspecified_code",
189
+ });
190
+ }
191
+ const { provider_token, provider_refresh_token, access_token, refresh_token, expires_in, expires_at, token_type, } = params;
192
+ if (!access_token || !expires_in || !refresh_token || !token_type) {
193
+ throw new errors_1.AuthImplicitGrantRedirectError("No session defined in URL");
194
+ }
195
+ const timeNow = Math.round(Date.now() / 1000);
196
+ const expiresIn = parseInt(expires_in);
197
+ let expiresAt = timeNow + expiresIn;
198
+ if (expires_at) {
199
+ expiresAt = parseInt(expires_at);
200
+ }
201
+ const actuallyExpiresIn = expiresAt - timeNow;
202
+ if (actuallyExpiresIn * 1000 <= AUTO_REFRESH_TICK_DURATION) {
203
+ console.warn(`@supabase/gotrue-js: Session as retrieved from URL expires in ${actuallyExpiresIn}s, should have been closer to ${expiresIn}s`);
204
+ }
205
+ const issuedAt = expiresAt - expiresIn;
206
+ if (timeNow - issuedAt >= 120) {
207
+ console.warn("@supabase/gotrue-js: Session as retrieved from URL was issued over 120s ago, URL could be stale", issuedAt, expiresAt, timeNow);
208
+ }
209
+ else if (timeNow - issuedAt < 0) {
210
+ console.warn("@supabase/gotrue-js: Session as retrieved from URL was issued in the future? Check the device clok for skew", issuedAt, expiresAt, timeNow);
211
+ }
212
+ const { data, error } = yield this._getUser(access_token);
213
+ if (error)
214
+ throw error;
215
+ const session = {
216
+ provider_token,
217
+ provider_refresh_token,
218
+ access_token,
219
+ expires_in: expiresIn,
220
+ expires_at: expiresAt,
221
+ refresh_token,
222
+ token_type,
223
+ user: data.user,
224
+ };
225
+ // Remove tokens from URL
226
+ window.location.hash = "";
227
+ this._debug("#_getSessionFromURL()", "clearing window.location.hash");
228
+ return { data: { session, redirectType: params.type }, error: null };
229
+ }
230
+ catch (error) {
231
+ this._debug(error);
232
+ if ((0, errors_1.isAuthError)(error)) {
233
+ return { data: { session: null, redirectType: null }, error };
234
+ }
235
+ throw error;
236
+ }
237
+ });
238
+ }
239
+ _exchangeCodeForSession(authCode) {
240
+ return __awaiter(this, void 0, void 0, function* () {
241
+ const storageItem = yield (0, storage_helpers_1.getItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
242
+ const [codeVerifier, redirectType] = (storageItem !== null && storageItem !== void 0 ? storageItem : "").split("/");
243
+ const { data, error } = yield (0, fetch_1._post)(`${this.domainUrl}/oauth/token`, {
244
+ client_id: this.clientId,
245
+ grant_type: "authorization_code",
246
+ code: authCode,
247
+ code_verifier: codeVerifier,
248
+ }, { transform: helpers_1._sessionResponse });
249
+ yield (0, storage_helpers_1.removeItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
250
+ if (error) {
251
+ return { data: { user: null, session: null, redirectType: null }, error };
252
+ }
253
+ else if (!data || !data.session || !data.user) {
254
+ return {
255
+ data: { user: null, session: null, redirectType: null },
256
+ error: new errors_1.AuthInvalidTokenResponseError(),
257
+ };
258
+ }
259
+ let session = data.session;
260
+ if (session) {
261
+ const { data: userdata, error } = yield this._getUser(session.access_token);
262
+ if (error) {
263
+ throw error;
264
+ }
265
+ session = Object.assign(Object.assign({}, session), { user: userdata.user });
266
+ data.session = session;
267
+ yield this._saveSession(session);
268
+ yield this._notifyAllSubscribers("SIGNED_IN", session);
269
+ }
270
+ return {
271
+ data: Object.assign(Object.assign({}, data), { redirectType: redirectType !== null && redirectType !== void 0 ? redirectType : null }),
272
+ error,
273
+ };
274
+ });
275
+ }
276
+ /**
277
+ * Registers callbacks on the browser / platform, which in-turn run
278
+ * algorithms when the browser window/tab are in foreground. On non-browser
279
+ * platforms it assumes always foreground.
280
+ */
281
+ _handleVisibilityChange() {
282
+ return __awaiter(this, void 0, void 0, function* () {
283
+ this._debug("#_handleVisibilityChange()");
284
+ if (!(0, helpers_1.isBrowser)() || !(window === null || window === void 0 ? void 0 : window.addEventListener)) {
285
+ if (this.autoRefreshToken) {
286
+ // in non-browser environments the refresh token ticker runs always
287
+ this.startAutoRefresh();
288
+ }
289
+ return false;
290
+ }
291
+ try {
292
+ this.visibilityChangedCallback = () => __awaiter(this, void 0, void 0, function* () { return yield this._onVisibilityChanged(false); });
293
+ window === null || window === void 0 ? void 0 : window.addEventListener("visibilitychange", this.visibilityChangedCallback);
294
+ // now immediately call the visbility changed callback to setup with the
295
+ // current visbility state
296
+ yield this._onVisibilityChanged(true); // initial call
297
+ }
298
+ catch (error) {
299
+ console.error("_handleVisibilityChange", error);
300
+ }
301
+ });
302
+ }
303
+ /**
304
+ * Callback registered with `window.addEventListener('visibilitychange')`.
305
+ */
306
+ _onVisibilityChanged(calledFromInitialize) {
307
+ return __awaiter(this, void 0, void 0, function* () {
308
+ const methodName = `#_onVisibilityChanged(${calledFromInitialize})`;
309
+ this._debug(methodName, "visibilityState", document.visibilityState);
310
+ if (document.visibilityState === "visible") {
311
+ if (this.autoRefreshToken) {
312
+ // in browser environments the refresh token ticker runs only on focused tabs
313
+ // which prevents race conditions
314
+ this._startAutoRefresh();
315
+ }
316
+ if (!calledFromInitialize) {
317
+ // called when the visibility has changed, i.e. the browser
318
+ // transitioned from hidden -> visible so we need to see if the session
319
+ // should be recovered immediately... but to do that we need to acquire
320
+ // the lock first asynchronously
321
+ yield this.initializePromise;
322
+ yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
323
+ if (document.visibilityState !== "visible") {
324
+ this._debug(methodName, "acquired the lock to recover the session, but the browser visibilityState is no longer visible, aborting");
325
+ // visibility has changed while waiting for the lock, abort
326
+ return;
327
+ }
328
+ // recover the session
329
+ yield this._recoverAndRefresh();
330
+ }));
331
+ }
332
+ }
333
+ else if (document.visibilityState === "hidden") {
334
+ if (this.autoRefreshToken) {
335
+ this._stopAutoRefresh();
336
+ }
337
+ }
338
+ });
339
+ }
340
+ /**
341
+ * Recovers the session from LocalStorage and refreshes
342
+ * Note: this method is async to accommodate for AsyncStorage e.g. in React native.
343
+ */
344
+ _recoverAndRefresh() {
345
+ return __awaiter(this, void 0, void 0, function* () {
346
+ var _a;
347
+ const debugName = "#_recoverAndRefresh()";
348
+ this._debug(debugName, "begin");
349
+ try {
350
+ const currentSession = yield (0, storage_helpers_1.getItemAsync)(this.storage, this.storageKey);
351
+ this._debug(debugName, "session from storage", currentSession);
352
+ if (!this._isValidSession(currentSession)) {
353
+ this._debug(debugName, "session is not valid");
354
+ if (currentSession !== null) {
355
+ yield this._removeSession();
356
+ }
357
+ return;
358
+ }
359
+ const timeNow = Math.round(Date.now() / 1000);
360
+ const expiresWithMargin = ((_a = currentSession.expires_at) !== null && _a !== void 0 ? _a : Infinity) < timeNow + constants_1.EXPIRY_MARGIN;
361
+ this._debug(debugName, `session has${expiresWithMargin ? "" : " not"} expired with margin of ${constants_1.EXPIRY_MARGIN}s`);
362
+ if (expiresWithMargin) {
363
+ if (this.autoRefreshToken && currentSession.refresh_token) {
364
+ const { error } = yield this._callRefreshToken(currentSession.refresh_token);
365
+ if (error) {
366
+ console.error(error);
367
+ if (!(0, errors_1.isAuthRetryableFetchError)(error)) {
368
+ this._debug(debugName, "refresh failed with a non-retryable error, removing the session", error);
369
+ yield this._removeSession();
370
+ }
371
+ }
372
+ }
373
+ }
374
+ else {
375
+ // no need to persist currentSession again, as we just loaded it from
376
+ // local storage; persisting it again may overwrite a value saved by
377
+ // another client with access to the same local storage
378
+ yield this._notifyAllSubscribers("SIGNED_IN", currentSession);
379
+ }
380
+ }
381
+ catch (err) {
382
+ this._debug(debugName, "error", err);
383
+ console.error(err);
384
+ return;
385
+ }
386
+ finally {
387
+ this._debug(debugName, "end");
388
+ }
389
+ });
390
+ }
391
+ /**
392
+ * Removes any registered visibilitychange callback.
393
+ *
394
+ * {@see #startAutoRefresh}
395
+ * {@see #stopAutoRefresh}
396
+ */
397
+ _removeVisibilityChangedCallback() {
398
+ this._debug("#_removeVisibilityChangedCallback()");
399
+ const callback = this.visibilityChangedCallback;
400
+ this.visibilityChangedCallback = null;
401
+ try {
402
+ if (callback && (0, helpers_1.isBrowser)() && (window === null || window === void 0 ? void 0 : window.removeEventListener)) {
403
+ window.removeEventListener("visibilitychange", callback);
404
+ }
405
+ }
406
+ catch (e) {
407
+ console.error("removing visibilitychange callback failed", e);
408
+ }
409
+ }
410
+ /**
411
+ * Starts an auto-refresh process in the background. The session is checked
412
+ * every few seconds. Close to the time of expiration a process is started to
413
+ * refresh the session. If refreshing fails it will be retried for as long as
414
+ * necessary.
415
+ *
416
+ * If you set the {@link GoTrueClientOptions#autoRefreshToken} you don't need
417
+ * to call this function, it will be called for you.
418
+ *
419
+ * On browsers the refresh process works only when the tab/window is in the
420
+ * foreground to conserve resources as well as prevent race conditions and
421
+ * flooding auth with requests. If you call this method any managed
422
+ * visibility change callback will be removed and you must manage visibility
423
+ * changes on your own.
424
+ *
425
+ * On non-browser platforms the refresh process works *continuously* in the
426
+ * background, which may not be desirable. You should hook into your
427
+ * platform's foreground indication mechanism and call these methods
428
+ * appropriately to conserve resources.
429
+ *
430
+ * {@see #stopAutoRefresh}
431
+ */
432
+ startAutoRefresh() {
433
+ return __awaiter(this, void 0, void 0, function* () {
434
+ this._removeVisibilityChangedCallback();
435
+ yield this._startAutoRefresh();
436
+ });
437
+ }
438
+ /**
439
+ * This is the private implementation of {@link #startAutoRefresh}. Use this
440
+ * within the library.
441
+ */
442
+ _startAutoRefresh() {
443
+ return __awaiter(this, void 0, void 0, function* () {
444
+ yield this._stopAutoRefresh();
445
+ this._debug("#_startAutoRefresh()");
446
+ const ticker = setInterval(() => this._autoRefreshTokenTick(), AUTO_REFRESH_TICK_DURATION);
447
+ this.autoRefreshTicker = ticker;
448
+ if (ticker &&
449
+ typeof ticker === "object" &&
450
+ typeof ticker.unref === "function") {
451
+ // ticker is a NodeJS Timeout object that has an `unref` method
452
+ // https://nodejs.org/api/timers.html#timeoutunref
453
+ // When auto refresh is used in NodeJS (like for testing) the
454
+ // `setInterval` is preventing the process from being marked as
455
+ // finished and tests run endlessly. This can be prevented by calling
456
+ // `unref()` on the returned object.
457
+ ticker.unref();
458
+ // @ts-ignore
459
+ }
460
+ else if (typeof globalThis.Deno !== "undefined" &&
461
+ typeof globalThis.Deno.unrefTimer === "function") {
462
+ // similar like for NodeJS, but with the Deno API
463
+ // https://deno.land/api@latest?unstable&s=Deno.unrefTimer
464
+ // @ts-ignore
465
+ Deno.unrefTimer(ticker);
466
+ }
467
+ // run the tick immediately, but in the next pass of the event loop so that
468
+ // #_initialize can be allowed to complete without recursively waiting on
469
+ // itself
470
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
471
+ yield this.initializePromise;
472
+ yield this._autoRefreshTokenTick();
473
+ }), 0);
474
+ });
475
+ }
476
+ /**
477
+ * This is the private implementation of {@link #stopAutoRefresh}. Use this
478
+ * within the library.
479
+ */
480
+ _stopAutoRefresh() {
481
+ return __awaiter(this, void 0, void 0, function* () {
482
+ this._debug("#_stopAutoRefresh()");
483
+ const ticker = this.autoRefreshTicker;
484
+ this.autoRefreshTicker = null;
485
+ if (ticker) {
486
+ clearInterval(ticker);
487
+ }
488
+ });
489
+ }
490
+ /**
491
+ * Runs the auto refresh token tick.
492
+ */
493
+ _autoRefreshTokenTick() {
494
+ return __awaiter(this, void 0, void 0, function* () {
495
+ this._debug("#_autoRefreshTokenTick()", "begin");
496
+ try {
497
+ yield this.lock._acquireLock(0, () => __awaiter(this, void 0, void 0, function* () {
498
+ try {
499
+ const now = Date.now();
500
+ try {
501
+ return yield this._useSession((result) => __awaiter(this, void 0, void 0, function* () {
502
+ const { data: { session }, } = result;
503
+ if (!session || !session.refresh_token || !session.expires_at) {
504
+ this._debug("#_autoRefreshTokenTick()", "no session");
505
+ return;
506
+ }
507
+ // session will expire in this many ticks (or has already expired if <= 0)
508
+ const expiresInTicks = Math.floor((session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION);
509
+ this._debug("#_autoRefreshTokenTick()", `access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`);
510
+ if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {
511
+ yield this._callRefreshToken(session.refresh_token);
512
+ }
513
+ }));
514
+ }
515
+ catch (e) {
516
+ console.error("Auto refresh tick failed with error. This is likely a transient error.", e);
517
+ }
518
+ }
519
+ finally {
520
+ this._debug("#_autoRefreshTokenTick()", "end");
521
+ }
522
+ }));
523
+ }
524
+ catch (e) {
525
+ if (e.isAcquireTimeout || e instanceof locks_1.LockAcquireTimeoutError) {
526
+ this._debug("auto refresh token tick lock not available");
527
+ }
528
+ else {
529
+ throw e;
530
+ }
531
+ }
532
+ });
533
+ }
534
+ /**
535
+ * Checks if the current URL and backing storage contain parameters given by a PKCE flow
536
+ */
537
+ _isPKCEFlow() {
538
+ return __awaiter(this, void 0, void 0, function* () {
539
+ const params = (0, helpers_1.parseParametersFromURL)(window.location.href);
540
+ const currentStorageContent = yield (0, storage_helpers_1.getItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
541
+ return !!(params.code && currentStorageContent);
542
+ });
543
+ }
544
+ /**
545
+ * Checks if the current URL contains parameters given by an implicit oauth grant flow (https://www.rfc-editor.org/rfc/rfc6749.html#section-4.2)
546
+ */
547
+ _isImplicitGrantFlow() {
548
+ const params = (0, helpers_1.parseParametersFromURL)(window.location.href);
549
+ return !!((0, helpers_1.isBrowser)() && (params.access_token || params.error_description));
550
+ }
551
+ _scope() {
552
+ return this.scope || "openid profile email";
553
+ }
554
+ _getUrlForConnection(url, params) {
555
+ return __awaiter(this, void 0, void 0, function* () {
556
+ let urlParams = params.queryParams || {};
557
+ const authorize_params = {
558
+ client_id: this.clientId,
559
+ response_type: params.response_type,
560
+ redirect_uri: params.redirectTo || this.redirect_uri || window.location.origin,
561
+ scope: params.scopes || this._scope(),
562
+ };
563
+ if (this.flowType === "pkce") {
564
+ const [codeChallenge, codeChallengeMethod] = yield (0, helpers_1.getCodeChallengeAndMethod)(this.storage, this.storageKey);
565
+ urlParams = Object.assign(Object.assign({}, urlParams), { code_challenge: codeChallenge, code_challenge_method: codeChallengeMethod });
566
+ }
567
+ // Set connection if specified
568
+ if (params.connection) {
569
+ authorize_params.connection = params.connection;
570
+ }
571
+ // Merge authorize params with urlParams
572
+ return `${url}?${new URLSearchParams(Object.assign(Object.assign({}, urlParams), authorize_params))}`;
573
+ });
574
+ }
575
+ signInWithOauthConnection(credentials) {
576
+ return __awaiter(this, void 0, void 0, function* () {
577
+ return yield this._handleConnectionSignIn({
578
+ connection: credentials.connection,
579
+ redirectTo: credentials === null || credentials === void 0 ? void 0 : credentials.redirectTo,
580
+ scopes: credentials === null || credentials === void 0 ? void 0 : credentials.scopes,
581
+ queryParams: credentials.queryParams,
582
+ skipBrowserRedirect: credentials.skipBrowserRedirect,
583
+ });
584
+ });
585
+ }
586
+ _handleConnectionSignIn(options) {
587
+ return __awaiter(this, void 0, void 0, function* () {
588
+ const url = yield this._getUrlForConnection(`${this.domainUrl}/authorize`, {
589
+ response_type: (0, helpers_1.isBrowser)() ? "code" : "token",
590
+ connection: options.connection,
591
+ redirectTo: options.redirectTo,
592
+ scopes: options.scopes,
593
+ queryParams: options.queryParams,
594
+ });
595
+ this._debug("#_handleProviderSignIn()", "options", options, "url", url);
596
+ // try to open on the browser
597
+ if ((0, helpers_1.isBrowser)() && !options.skipBrowserRedirect) {
598
+ window.location.assign(url);
599
+ }
600
+ return { data: { url }, error: null };
601
+ });
602
+ }
603
+ /**
604
+ * Sets the session data from the current session. If the current session is expired, setSession will take care of refreshing it to obtain a new session.
605
+ * If the refresh token or access token in the current session is invalid, an error will be thrown.
606
+ * @param currentSession The current session that minimally contains an access token and refresh token.
607
+ */
608
+ setSession(currentSession) {
609
+ return __awaiter(this, void 0, void 0, function* () {
610
+ yield this.initializePromise;
611
+ return yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
612
+ return yield this._setSession(currentSession);
613
+ }));
614
+ });
615
+ }
616
+ /**
617
+ * Returns the session, refreshing it if necessary.
618
+ *
619
+ * The session returned can be null if the session is not detected which can happen in the event a user is not signed-in or has logged out.
620
+ *
621
+ * **IMPORTANT:** This method loads values directly from the storage attached
622
+ * to the client. If that storage is based on request cookies for example,
623
+ * the values in it may not be authentic and therefore it's strongly advised
624
+ * against using this method and its results in such circumstances. A warning
625
+ * will be emitted if this is detected. Use {@link #getUser()} instead.
626
+ */
627
+ getSession() {
628
+ return __awaiter(this, void 0, void 0, function* () {
629
+ yield this.initializePromise;
630
+ const result = yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
631
+ return this._useSession((result) => __awaiter(this, void 0, void 0, function* () {
632
+ return result;
633
+ }));
634
+ }));
635
+ return result;
636
+ });
637
+ }
638
+ /**
639
+ * Use instead of {@link #getSession} inside the library. It is
640
+ * semantically usually what you want, as getting a session involves some
641
+ * processing afterwards that requires only one client operating on the
642
+ * session at once across multiple tabs or processes.
643
+ */
644
+ _useSession(fn) {
645
+ return __awaiter(this, void 0, void 0, function* () {
646
+ this._debug("#_useSession", "begin");
647
+ try {
648
+ // the use of __loadSession here is the only correct use of the function!
649
+ const result = yield this.__loadSession();
650
+ return yield fn(result);
651
+ }
652
+ finally {
653
+ this._debug("#_useSession", "end");
654
+ }
655
+ });
656
+ }
657
+ /**
658
+ * NEVER USE DIRECTLY!
659
+ *
660
+ * Always use {@link #_useSession}.
661
+ */
662
+ __loadSession() {
663
+ return __awaiter(this, void 0, void 0, function* () {
664
+ this._debug("#__loadSession()", "begin");
665
+ if (!this.lock.lockAcquired) {
666
+ this._debug("#__loadSession()", "used outside of an acquired lock!", new Error().stack);
667
+ }
668
+ try {
669
+ let currentSession = null;
670
+ const maybeSession = yield (0, storage_helpers_1.getItemAsync)(this.storage, this.storageKey);
671
+ this._debug("#getSession()", "session from storage", maybeSession);
672
+ if (maybeSession !== null) {
673
+ if (this._isValidSession(maybeSession)) {
674
+ currentSession = maybeSession;
675
+ }
676
+ else {
677
+ this._debug("#getSession()", "session from storage is not valid");
678
+ yield this._removeSession();
679
+ }
680
+ }
681
+ if (!currentSession) {
682
+ return { data: { session: null }, error: null };
683
+ }
684
+ const hasExpired = currentSession.expires_at
685
+ ? currentSession.expires_at <= Date.now() / 1000
686
+ : false;
687
+ this._debug("#__loadSession()", `session has${hasExpired ? "" : " not"} expired`, "expires_at", currentSession.expires_at);
688
+ if (!hasExpired) {
689
+ if (this.storage.isServer) {
690
+ const proxySession = new Proxy(currentSession, {
691
+ get(target, prop, receiver) {
692
+ if (prop === "user") {
693
+ // only show warning when the user object is being accessed from the server
694
+ console.warn("Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and many not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server.");
695
+ }
696
+ return Reflect.get(target, prop, receiver);
697
+ },
698
+ });
699
+ currentSession = proxySession;
700
+ }
701
+ return { data: { session: currentSession }, error: null };
702
+ }
703
+ const { session, error } = yield this._callRefreshToken(currentSession.refresh_token);
704
+ if (error) {
705
+ return { data: { session: null }, error };
706
+ }
707
+ return { data: { session }, error: null };
708
+ }
709
+ finally {
710
+ this._debug("#__loadSession()", "end");
711
+ }
712
+ });
713
+ }
714
+ _removeSession() {
715
+ return __awaiter(this, void 0, void 0, function* () {
716
+ this._debug("#_removeSession()");
717
+ yield (0, storage_helpers_1.removeItemAsync)(this.storage, this.storageKey);
718
+ });
719
+ }
720
+ _isValidSession(maybeSession) {
721
+ const isValidSession = typeof maybeSession === "object" &&
722
+ maybeSession !== null &&
723
+ "access_token" in maybeSession &&
724
+ "refresh_token" in maybeSession &&
725
+ "expires_at" in maybeSession;
726
+ return isValidSession;
727
+ }
728
+ _setSession(currentSession) {
729
+ return __awaiter(this, void 0, void 0, function* () {
730
+ try {
731
+ if (!currentSession.access_token || !currentSession.refresh_token) {
732
+ throw new errors_1.AuthSessionMissingError();
733
+ }
734
+ const timeNow = Date.now() / 1000;
735
+ let expiresAt = timeNow;
736
+ let hasExpired = true;
737
+ let session = null;
738
+ const payload = (0, jwt_1.decodeJWTPayload)(currentSession.access_token);
739
+ if (payload.exp) {
740
+ expiresAt = payload.exp;
741
+ hasExpired = expiresAt <= timeNow;
742
+ }
743
+ if (hasExpired) {
744
+ const { session: refreshedSession, error } = yield this._callRefreshToken(currentSession.refresh_token);
745
+ if (error) {
746
+ return { data: { user: null, session: null }, error: error };
747
+ }
748
+ if (!refreshedSession) {
749
+ return { data: { user: null, session: null }, error: null };
750
+ }
751
+ session = refreshedSession;
752
+ }
753
+ else {
754
+ const { data, error } = yield this._getUser(currentSession.access_token);
755
+ if (error) {
756
+ throw error;
757
+ }
758
+ session = {
759
+ access_token: currentSession.access_token,
760
+ refresh_token: currentSession.refresh_token,
761
+ user: data.user,
762
+ token_type: "bearer",
763
+ expires_in: expiresAt - timeNow,
764
+ expires_at: expiresAt,
765
+ };
766
+ yield this._saveSession(session);
767
+ yield this._notifyAllSubscribers("SIGNED_IN", session);
768
+ }
769
+ return { data: { user: session.user, session }, error: null };
770
+ }
771
+ catch (error) {
772
+ if ((0, errors_1.isAuthError)(error)) {
773
+ return { data: { session: null, user: null }, error };
774
+ }
775
+ throw error;
776
+ }
777
+ });
778
+ }
779
+ /**
780
+ * set currentSession and currentUser
781
+ * process to _startAutoRefreshToken if possible
782
+ */
783
+ _saveSession(session) {
784
+ return __awaiter(this, void 0, void 0, function* () {
785
+ this._debug("#_saveSession()", session);
786
+ yield (0, storage_helpers_1.setItemAsync)(this.storage, this.storageKey, session);
787
+ });
788
+ }
789
+ _getUser(access_token) {
790
+ return __awaiter(this, void 0, void 0, function* () {
791
+ if (!access_token)
792
+ throw new Error("Cannot fetch user without token");
793
+ this._debug("#_getUser() begin");
794
+ const res = yield (0, fetch_1._get)(`${this.domainUrl}/me`, {
795
+ token: access_token,
796
+ });
797
+ this._debug("#_getUser() end");
798
+ return { data: { user: res.data }, error: res.error };
799
+ });
800
+ }
801
+ _callRefreshToken(refreshToken) {
802
+ return __awaiter(this, void 0, void 0, function* () {
803
+ var _a, _b;
804
+ if (!refreshToken) {
805
+ throw new errors_1.AuthSessionMissingError();
806
+ }
807
+ // refreshing is already in progress
808
+ if (this.refreshingDeferred) {
809
+ return this.refreshingDeferred.promise;
810
+ }
811
+ const debugName = `#_callRefreshToken(${refreshToken.substring(0, 5)}...)`;
812
+ this._debug(debugName, "begin");
813
+ try {
814
+ this.refreshingDeferred = new helpers_1.Deferred();
815
+ const { data, error } = yield this._refreshAccessToken(refreshToken);
816
+ if (error)
817
+ throw error;
818
+ if (!data.session)
819
+ throw new errors_1.AuthSessionMissingError();
820
+ yield this._saveSession(data.session);
821
+ yield this._notifyAllSubscribers("TOKEN_REFRESHED", data.session);
822
+ const result = { session: data.session, error: null };
823
+ this.refreshingDeferred.resolve(result);
824
+ return result;
825
+ }
826
+ catch (error) {
827
+ this._debug(debugName, "error", error);
828
+ if ((0, errors_1.isAuthError)(error)) {
829
+ const result = { session: null, error };
830
+ if (!(0, errors_1.isAuthRetryableFetchError)(error)) {
831
+ yield this._removeSession();
832
+ yield this._notifyAllSubscribers("SIGNED_OUT", null);
833
+ }
834
+ (_a = this.refreshingDeferred) === null || _a === void 0 ? void 0 : _a.resolve(result);
835
+ return result;
836
+ }
837
+ (_b = this.refreshingDeferred) === null || _b === void 0 ? void 0 : _b.reject(error);
838
+ throw error;
839
+ }
840
+ finally {
841
+ this.refreshingDeferred = null;
842
+ this._debug(debugName, "end");
843
+ }
844
+ });
845
+ }
846
+ /**
847
+ * Generates a new JWT.
848
+ * @param refreshToken A valid refresh token that was returned on login.
849
+ */
850
+ _refreshAccessToken(refreshToken) {
851
+ return __awaiter(this, void 0, void 0, function* () {
852
+ const debugName = `#_refreshAccessToken(${refreshToken.substring(0, 5)}...)`;
853
+ this._debug(debugName, "begin");
854
+ try {
855
+ const startedAt = Date.now();
856
+ // will attempt to refresh the token with exponential backoff
857
+ return yield (0, helpers_1.retryable)((attempt) => __awaiter(this, void 0, void 0, function* () {
858
+ var _a;
859
+ if (attempt > 0) {
860
+ yield (0, helpers_1.sleep)(200 * Math.pow(2, attempt - 1)); // 200, 400, 800, ...
861
+ }
862
+ this._debug(debugName, "refreshing attempt", attempt);
863
+ // return await _post(`${this.url}/token?grant_type=refresh_token`, {
864
+ // body: { refresh_token: refreshToken },
865
+ // headers: this.headers,
866
+ // xform: _sessionResponse,
867
+ // });
868
+ const session_res = yield (0, fetch_1._post)(`${this.domainUrl}/oauth/token`, {
869
+ client_id: this.clientId,
870
+ grant_type: "refresh_token",
871
+ refresh_token: refreshToken,
872
+ }, { transform: helpers_1._sessionResponse });
873
+ const user_res = yield this._getUser((_a = session_res.data.session) === null || _a === void 0 ? void 0 : _a.access_token);
874
+ const { user } = user_res.data;
875
+ const x = {
876
+ data: {
877
+ session: Object.assign(Object.assign({}, session_res.data.session), { user }),
878
+ user,
879
+ },
880
+ error: null,
881
+ };
882
+ // this._debug(x);
883
+ return x;
884
+ }), (attempt, error) => {
885
+ const nextBackOffInterval = 200 * Math.pow(2, attempt);
886
+ return (error &&
887
+ (0, errors_1.isAuthRetryableFetchError)(error) &&
888
+ // retryable only if the request can be sent before the backoff overflows the tick duration
889
+ Date.now() + nextBackOffInterval - startedAt <
890
+ AUTO_REFRESH_TICK_DURATION);
891
+ });
892
+ }
893
+ catch (error) {
894
+ this._debug(debugName, "error", error);
895
+ if ((0, errors_1.isAuthError)(error)) {
896
+ return { data: { session: null, user: null }, error };
897
+ }
898
+ throw error;
899
+ }
900
+ finally {
901
+ this._debug(debugName, "end");
902
+ }
903
+ });
904
+ }
905
+ _notifyAllSubscribers(event_1, session_1) {
906
+ return __awaiter(this, arguments, void 0, function* (event, session, broadcast = true) {
907
+ const debugName = `#_notifyAllSubscribers(${event})`;
908
+ this._debug(debugName, "begin", session, `broadcast = ${broadcast}`);
909
+ try {
910
+ if (this.broadcastChannel && broadcast) {
911
+ this.broadcastChannel.postMessage({ event, session });
912
+ }
913
+ const errors = [];
914
+ const promises = Array.from(this.stateChangeEmitters.values()).map((x) => __awaiter(this, void 0, void 0, function* () {
915
+ try {
916
+ yield x.callback(event, session);
917
+ }
918
+ catch (e) {
919
+ errors.push(e);
920
+ }
921
+ }));
922
+ yield Promise.all(promises);
923
+ if (errors.length > 0) {
924
+ for (let i = 0; i < errors.length; i += 1) {
925
+ console.error(errors[i]);
926
+ }
927
+ throw errors[0];
928
+ }
929
+ }
930
+ finally {
931
+ this._debug(debugName, "end");
932
+ }
933
+ });
934
+ }
935
+ /**
936
+ * Inside a browser context, `signOut()` will remove the logged in user from the browser session and log them out - removing all items from localstorage and then trigger a `"SIGNED_OUT"` event.
937
+ *
938
+ * For server-side management, you can revoke all refresh tokens for a user by passing a user's JWT through to `auth.api.signOut(JWT: string)`.
939
+ * There is no way to revoke a user's access token jwt until it expires. It is recommended to set a shorter expiry on the jwt for this reason.
940
+ *
941
+ * If using `others` scope, no `SIGNED_OUT` event is fired!
942
+ */
943
+ signOut() {
944
+ return __awaiter(this, arguments, void 0, function* (options = { scope: "global" }) {
945
+ yield this.initializePromise;
946
+ return yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
947
+ return yield this._signOut(options);
948
+ }));
949
+ });
950
+ }
951
+ _signOut() {
952
+ return __awaiter(this, arguments, void 0, function* ({ scope } = { scope: "global" }) {
953
+ return yield this._useSession((result) => __awaiter(this, void 0, void 0, function* () {
954
+ var _a;
955
+ const { data, error: sessionError } = result;
956
+ if (sessionError) {
957
+ return { error: sessionError };
958
+ }
959
+ const accessToken = (_a = data.session) === null || _a === void 0 ? void 0 : _a.access_token;
960
+ if (accessToken) {
961
+ const { error } = yield this.api.signOut({ client_id: this.clientId });
962
+ if (error) {
963
+ // ignore 404s since user might not exist anymore
964
+ // ignore 401s since an invalid or expired JWT should sign out the current session
965
+ if (!((0, errors_1.isAuthApiError)(error) &&
966
+ (error.status === 404 || error.status === 401))) {
967
+ return { error };
968
+ }
969
+ }
970
+ }
971
+ if (scope !== "others") {
972
+ yield this._removeSession();
973
+ yield (0, storage_helpers_1.removeItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
974
+ yield this._notifyAllSubscribers("SIGNED_OUT", null);
975
+ }
976
+ return { error: null };
977
+ }));
978
+ });
979
+ }
980
+ /**
981
+ * Receive a notification every time an auth event happens.
982
+ * @param callback A callback function to be invoked when an auth event happens.
983
+ */
984
+ onAuthStateChange(callback) {
985
+ const id = (0, helpers_1.uuid)();
986
+ const subscription = {
987
+ id,
988
+ callback,
989
+ unsubscribe: () => {
990
+ this._debug("#unsubscribe()", "state change callback with id removed", id);
991
+ this.stateChangeEmitters.delete(id);
992
+ },
993
+ };
994
+ this._debug("#onAuthStateChange()", "registered callback with id", id);
995
+ this.stateChangeEmitters.set(id, subscription);
996
+ (() => __awaiter(this, void 0, void 0, function* () {
997
+ yield this.initializePromise;
998
+ yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
999
+ this._emitInitialSession(id);
1000
+ }));
1001
+ }))();
1002
+ return { data: { subscription } };
1003
+ }
1004
+ _emitInitialSession(id) {
1005
+ return __awaiter(this, void 0, void 0, function* () {
1006
+ return yield this._useSession((result) => __awaiter(this, void 0, void 0, function* () {
1007
+ var _a, _b;
1008
+ try {
1009
+ const { data: { session }, error, } = result;
1010
+ if (error)
1011
+ throw error;
1012
+ yield ((_a = this.stateChangeEmitters
1013
+ .get(id)) === null || _a === void 0 ? void 0 : _a.callback("INITIAL_SESSION", session));
1014
+ this._debug("INITIAL_SESSION", "callback id", id, "session", session);
1015
+ }
1016
+ catch (err) {
1017
+ yield ((_b = this.stateChangeEmitters
1018
+ .get(id)) === null || _b === void 0 ? void 0 : _b.callback("INITIAL_SESSION", null));
1019
+ this._debug("INITIAL_SESSION", "callback id", id, "error", err);
1020
+ console.error(err);
1021
+ }
1022
+ }));
1023
+ });
1024
+ }
1025
+ /**
1026
+ * Returns a new session, regardless of expiry status.
1027
+ * Takes in an optional current session. If not passed in, then refreshSession() will attempt to retrieve it from getSession().
1028
+ * If the current session's refresh token is invalid, an error will be thrown.
1029
+ * @param currentSession The current session. If passed in, it must contain a refresh token.
1030
+ */
1031
+ refreshSession(currentSession) {
1032
+ return __awaiter(this, void 0, void 0, function* () {
1033
+ yield this.initializePromise;
1034
+ return yield this.lock._acquireLock(-1, () => __awaiter(this, void 0, void 0, function* () {
1035
+ return yield this._refreshSession(currentSession);
1036
+ }));
1037
+ });
1038
+ }
1039
+ _refreshSession(currentSession) {
1040
+ return __awaiter(this, void 0, void 0, function* () {
1041
+ try {
1042
+ return yield this._useSession((result) => __awaiter(this, void 0, void 0, function* () {
1043
+ var _a;
1044
+ if (!currentSession) {
1045
+ const { data, error } = result;
1046
+ if (error) {
1047
+ throw error;
1048
+ }
1049
+ currentSession = (_a = data.session) !== null && _a !== void 0 ? _a : undefined;
1050
+ }
1051
+ if (!(currentSession === null || currentSession === void 0 ? void 0 : currentSession.refresh_token)) {
1052
+ throw new errors_1.AuthSessionMissingError();
1053
+ }
1054
+ const { session, error } = yield this._callRefreshToken(currentSession.refresh_token);
1055
+ if (error) {
1056
+ return { data: { user: null, session: null }, error: error };
1057
+ }
1058
+ if (!session) {
1059
+ return { data: { user: null, session: null }, error: null };
1060
+ }
1061
+ return { data: { user: session.user, session }, error: null };
1062
+ }));
1063
+ }
1064
+ catch (error) {
1065
+ if ((0, errors_1.isAuthError)(error)) {
1066
+ return { data: { user: null, session: null }, error };
1067
+ }
1068
+ throw error;
1069
+ }
1070
+ });
1071
+ }
1072
+ }
1073
+ exports.FaableAuthClient = FaableAuthClient;