@netlify/identity 0.1.1 → 0.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.
- package/README.md +726 -13
- package/dist/index.cjs +636 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +175 -5
- package/dist/index.d.ts +175 -5
- package/dist/index.js +628 -25
- package/dist/index.js.map +1 -1
- package/package.json +10 -2
package/dist/index.cjs
CHANGED
|
@@ -30,12 +30,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AUTH_EVENTS: () => AUTH_EVENTS,
|
|
33
34
|
AuthError: () => AuthError,
|
|
34
35
|
MissingIdentityError: () => MissingIdentityError,
|
|
36
|
+
acceptInvite: () => acceptInvite,
|
|
37
|
+
confirmEmail: () => confirmEmail,
|
|
35
38
|
getIdentityConfig: () => getIdentityConfig,
|
|
36
39
|
getSettings: () => getSettings,
|
|
37
40
|
getUser: () => getUser,
|
|
38
|
-
|
|
41
|
+
handleAuthCallback: () => handleAuthCallback,
|
|
42
|
+
hydrateSession: () => hydrateSession,
|
|
43
|
+
isAuthenticated: () => isAuthenticated,
|
|
44
|
+
login: () => login,
|
|
45
|
+
logout: () => logout,
|
|
46
|
+
oauthLogin: () => oauthLogin,
|
|
47
|
+
onAuthChange: () => onAuthChange,
|
|
48
|
+
recoverPassword: () => recoverPassword,
|
|
49
|
+
requestPasswordRecovery: () => requestPasswordRecovery,
|
|
50
|
+
signup: () => signup,
|
|
51
|
+
updateUser: () => updateUser,
|
|
52
|
+
verifyEmailChange: () => verifyEmailChange
|
|
39
53
|
});
|
|
40
54
|
module.exports = __toCommonJS(index_exports);
|
|
41
55
|
|
|
@@ -44,6 +58,31 @@ var AUTH_PROVIDERS = ["google", "github", "gitlab", "bitbucket", "facebook", "sa
|
|
|
44
58
|
|
|
45
59
|
// src/environment.ts
|
|
46
60
|
var import_gotrue_js = __toESM(require("gotrue-js"), 1);
|
|
61
|
+
|
|
62
|
+
// src/errors.ts
|
|
63
|
+
var AuthError = class _AuthError extends Error {
|
|
64
|
+
constructor(message, status, options) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "AuthError";
|
|
67
|
+
this.status = status;
|
|
68
|
+
if (options && "cause" in options) {
|
|
69
|
+
this.cause = options.cause;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
static from(error) {
|
|
73
|
+
if (error instanceof _AuthError) return error;
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
return new _AuthError(message, void 0, { cause: error });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var MissingIdentityError = class extends Error {
|
|
79
|
+
constructor(message = "Netlify Identity is not available.") {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = "MissingIdentityError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/environment.ts
|
|
47
86
|
var IDENTITY_PATH = "/.netlify/identity";
|
|
48
87
|
var goTrueClient = null;
|
|
49
88
|
var cachedApiUrl;
|
|
@@ -59,6 +98,8 @@ var discoverApiUrl = () => {
|
|
|
59
98
|
cachedApiUrl = identityContext.url;
|
|
60
99
|
} else if (globalThis.Netlify?.context?.url) {
|
|
61
100
|
cachedApiUrl = new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href;
|
|
101
|
+
} else if (typeof process !== "undefined" && process.env?.URL) {
|
|
102
|
+
cachedApiUrl = new URL(IDENTITY_PATH, process.env.URL).href;
|
|
62
103
|
}
|
|
63
104
|
}
|
|
64
105
|
return cachedApiUrl ?? null;
|
|
@@ -75,9 +116,14 @@ var getGoTrueClient = () => {
|
|
|
75
116
|
}
|
|
76
117
|
return null;
|
|
77
118
|
}
|
|
78
|
-
goTrueClient = new import_gotrue_js.default({ APIUrl: apiUrl, setCookie:
|
|
119
|
+
goTrueClient = new import_gotrue_js.default({ APIUrl: apiUrl, setCookie: false });
|
|
79
120
|
return goTrueClient;
|
|
80
121
|
};
|
|
122
|
+
var getClient = () => {
|
|
123
|
+
const client = getGoTrueClient();
|
|
124
|
+
if (!client) throw new MissingIdentityError();
|
|
125
|
+
return client;
|
|
126
|
+
};
|
|
81
127
|
var getIdentityContext = () => {
|
|
82
128
|
const identityContext = globalThis.netlifyIdentityContext;
|
|
83
129
|
if (identityContext?.url) {
|
|
@@ -89,9 +135,96 @@ var getIdentityContext = () => {
|
|
|
89
135
|
if (globalThis.Netlify?.context?.url) {
|
|
90
136
|
return { url: new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href };
|
|
91
137
|
}
|
|
138
|
+
const siteUrl = typeof process !== "undefined" ? process.env?.URL : void 0;
|
|
139
|
+
if (siteUrl) {
|
|
140
|
+
return { url: new URL(IDENTITY_PATH, siteUrl).href };
|
|
141
|
+
}
|
|
92
142
|
return null;
|
|
93
143
|
};
|
|
94
144
|
|
|
145
|
+
// src/cookies.ts
|
|
146
|
+
var NF_JWT_COOKIE = "nf_jwt";
|
|
147
|
+
var NF_REFRESH_COOKIE = "nf_refresh";
|
|
148
|
+
var getCookie = (name) => {
|
|
149
|
+
if (typeof document === "undefined") return null;
|
|
150
|
+
const match = document.cookie.match(new RegExp(`(?:^|; )${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)`));
|
|
151
|
+
if (!match) return null;
|
|
152
|
+
try {
|
|
153
|
+
return decodeURIComponent(match[1]);
|
|
154
|
+
} catch {
|
|
155
|
+
return match[1];
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
var setAuthCookies = (cookies, accessToken, refreshToken) => {
|
|
159
|
+
cookies.set({
|
|
160
|
+
name: NF_JWT_COOKIE,
|
|
161
|
+
value: accessToken,
|
|
162
|
+
httpOnly: false,
|
|
163
|
+
secure: true,
|
|
164
|
+
path: "/",
|
|
165
|
+
sameSite: "Lax"
|
|
166
|
+
});
|
|
167
|
+
if (refreshToken) {
|
|
168
|
+
cookies.set({
|
|
169
|
+
name: NF_REFRESH_COOKIE,
|
|
170
|
+
value: refreshToken,
|
|
171
|
+
httpOnly: false,
|
|
172
|
+
secure: true,
|
|
173
|
+
path: "/",
|
|
174
|
+
sameSite: "Lax"
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var deleteAuthCookies = (cookies) => {
|
|
179
|
+
cookies.delete(NF_JWT_COOKIE);
|
|
180
|
+
cookies.delete(NF_REFRESH_COOKIE);
|
|
181
|
+
};
|
|
182
|
+
var setBrowserAuthCookies = (accessToken, refreshToken) => {
|
|
183
|
+
if (typeof document === "undefined") return;
|
|
184
|
+
document.cookie = `${NF_JWT_COOKIE}=${encodeURIComponent(accessToken)}; path=/; secure; samesite=lax`;
|
|
185
|
+
if (refreshToken) {
|
|
186
|
+
document.cookie = `${NF_REFRESH_COOKIE}=${encodeURIComponent(refreshToken)}; path=/; secure; samesite=lax`;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
var deleteBrowserAuthCookies = () => {
|
|
190
|
+
if (typeof document === "undefined") return;
|
|
191
|
+
document.cookie = `${NF_JWT_COOKIE}=; path=/; secure; samesite=lax; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
192
|
+
document.cookie = `${NF_REFRESH_COOKIE}=; path=/; secure; samesite=lax; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
193
|
+
};
|
|
194
|
+
var getServerCookie = (name) => {
|
|
195
|
+
const cookies = globalThis.Netlify?.context?.cookies;
|
|
196
|
+
if (!cookies || typeof cookies.get !== "function") return null;
|
|
197
|
+
return cookies.get(name) ?? null;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// src/nextjs.ts
|
|
201
|
+
var nextHeadersFn;
|
|
202
|
+
var triggerNextjsDynamic = () => {
|
|
203
|
+
if (nextHeadersFn === null) return;
|
|
204
|
+
if (nextHeadersFn === void 0) {
|
|
205
|
+
try {
|
|
206
|
+
if (typeof require === "undefined") {
|
|
207
|
+
nextHeadersFn = null;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const mod = require("next/headers");
|
|
211
|
+
nextHeadersFn = mod.headers;
|
|
212
|
+
} catch {
|
|
213
|
+
nextHeadersFn = null;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const fn = nextHeadersFn;
|
|
218
|
+
if (!fn) return;
|
|
219
|
+
try {
|
|
220
|
+
fn();
|
|
221
|
+
} catch (e) {
|
|
222
|
+
if (e instanceof Error && ("digest" in e || /bail\s*out.*prerende/i.test(e.message))) {
|
|
223
|
+
throw e;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
95
228
|
// src/user.ts
|
|
96
229
|
var toAuthProvider = (value) => typeof value === "string" && AUTH_PROVIDERS.includes(value) ? value : void 0;
|
|
97
230
|
var toUser = (userData) => {
|
|
@@ -124,36 +257,80 @@ var claimsToUser = (claims) => {
|
|
|
124
257
|
metadata: userMeta
|
|
125
258
|
};
|
|
126
259
|
};
|
|
260
|
+
var hydrating = false;
|
|
261
|
+
var backgroundHydrate = (accessToken) => {
|
|
262
|
+
if (hydrating) return;
|
|
263
|
+
hydrating = true;
|
|
264
|
+
const refreshToken = getCookie(NF_REFRESH_COOKIE) ?? "";
|
|
265
|
+
const decoded = decodeJwtPayload(accessToken);
|
|
266
|
+
const expiresAt = decoded?.exp ?? Math.floor(Date.now() / 1e3) + 3600;
|
|
267
|
+
const expiresIn = Math.max(0, expiresAt - Math.floor(Date.now() / 1e3));
|
|
268
|
+
setTimeout(() => {
|
|
269
|
+
try {
|
|
270
|
+
const client = getClient();
|
|
271
|
+
client.createUser(
|
|
272
|
+
{
|
|
273
|
+
access_token: accessToken,
|
|
274
|
+
token_type: "bearer",
|
|
275
|
+
expires_in: expiresIn,
|
|
276
|
+
expires_at: expiresAt,
|
|
277
|
+
refresh_token: refreshToken
|
|
278
|
+
},
|
|
279
|
+
true
|
|
280
|
+
).catch(() => {
|
|
281
|
+
}).finally(() => {
|
|
282
|
+
hydrating = false;
|
|
283
|
+
});
|
|
284
|
+
} catch {
|
|
285
|
+
hydrating = false;
|
|
286
|
+
}
|
|
287
|
+
}, 0);
|
|
288
|
+
};
|
|
289
|
+
var decodeJwtPayload = (token) => {
|
|
290
|
+
try {
|
|
291
|
+
const parts = token.split(".");
|
|
292
|
+
if (parts.length !== 3) return null;
|
|
293
|
+
const payload = atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"));
|
|
294
|
+
return JSON.parse(payload);
|
|
295
|
+
} catch {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
};
|
|
127
299
|
var getUser = () => {
|
|
128
300
|
if (isBrowser()) {
|
|
129
301
|
const client = getGoTrueClient();
|
|
130
302
|
const currentUser = client?.currentUser() ?? null;
|
|
131
|
-
if (
|
|
132
|
-
|
|
303
|
+
if (currentUser) {
|
|
304
|
+
const jwt2 = getCookie(NF_JWT_COOKIE);
|
|
305
|
+
if (!jwt2) {
|
|
306
|
+
try {
|
|
307
|
+
currentUser.clearSession();
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
return toUser(currentUser);
|
|
313
|
+
}
|
|
314
|
+
const jwt = getCookie(NF_JWT_COOKIE);
|
|
315
|
+
if (!jwt) return null;
|
|
316
|
+
const claims = decodeJwtPayload(jwt);
|
|
317
|
+
if (!claims) return null;
|
|
318
|
+
backgroundHydrate(jwt);
|
|
319
|
+
return claimsToUser(claims);
|
|
133
320
|
}
|
|
321
|
+
triggerNextjsDynamic();
|
|
134
322
|
const identityContext = globalThis.netlifyIdentityContext;
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
};
|
|
138
|
-
var isAuthenticated = () => getUser() !== null;
|
|
139
|
-
|
|
140
|
-
// src/errors.ts
|
|
141
|
-
var AuthError = class extends Error {
|
|
142
|
-
constructor(message, status, options) {
|
|
143
|
-
super(message);
|
|
144
|
-
this.name = "AuthError";
|
|
145
|
-
this.status = status;
|
|
146
|
-
if (options && "cause" in options) {
|
|
147
|
-
this.cause = options.cause;
|
|
148
|
-
}
|
|
323
|
+
if (identityContext?.user) {
|
|
324
|
+
return claimsToUser(identityContext.user);
|
|
149
325
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
this.name = "MissingIdentityError";
|
|
326
|
+
const serverJwt = getServerCookie(NF_JWT_COOKIE);
|
|
327
|
+
if (serverJwt) {
|
|
328
|
+
const claims = decodeJwtPayload(serverJwt);
|
|
329
|
+
if (claims) return claimsToUser(claims);
|
|
155
330
|
}
|
|
331
|
+
return null;
|
|
156
332
|
};
|
|
333
|
+
var isAuthenticated = () => getUser() !== null;
|
|
157
334
|
|
|
158
335
|
// src/config.ts
|
|
159
336
|
var getIdentityConfig = () => {
|
|
@@ -163,8 +340,7 @@ var getIdentityConfig = () => {
|
|
|
163
340
|
return getIdentityContext();
|
|
164
341
|
};
|
|
165
342
|
var getSettings = async () => {
|
|
166
|
-
const client =
|
|
167
|
-
if (!client) throw new MissingIdentityError();
|
|
343
|
+
const client = getClient();
|
|
168
344
|
try {
|
|
169
345
|
const raw = await client.settings();
|
|
170
346
|
const external = raw.external ?? {};
|
|
@@ -185,13 +361,447 @@ var getSettings = async () => {
|
|
|
185
361
|
throw new AuthError(err instanceof Error ? err.message : "Failed to fetch identity settings", 502, { cause: err });
|
|
186
362
|
}
|
|
187
363
|
};
|
|
364
|
+
|
|
365
|
+
// src/events.ts
|
|
366
|
+
var AUTH_EVENTS = {
|
|
367
|
+
LOGIN: "login",
|
|
368
|
+
LOGOUT: "logout",
|
|
369
|
+
TOKEN_REFRESH: "token_refresh",
|
|
370
|
+
USER_UPDATED: "user_updated",
|
|
371
|
+
RECOVERY: "recovery"
|
|
372
|
+
};
|
|
373
|
+
var GOTRUE_STORAGE_KEY = "gotrue.user";
|
|
374
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
375
|
+
var emitAuthEvent = (event, user) => {
|
|
376
|
+
for (const listener of listeners) {
|
|
377
|
+
try {
|
|
378
|
+
listener(event, user);
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
var storageListenerAttached = false;
|
|
384
|
+
var attachStorageListener = () => {
|
|
385
|
+
if (storageListenerAttached || !isBrowser()) return;
|
|
386
|
+
storageListenerAttached = true;
|
|
387
|
+
window.addEventListener("storage", (event) => {
|
|
388
|
+
if (event.key !== GOTRUE_STORAGE_KEY) return;
|
|
389
|
+
if (event.newValue) {
|
|
390
|
+
const client = getGoTrueClient();
|
|
391
|
+
const currentUser = client?.currentUser();
|
|
392
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, currentUser ? toUser(currentUser) : null);
|
|
393
|
+
} else {
|
|
394
|
+
emitAuthEvent(AUTH_EVENTS.LOGOUT, null);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
};
|
|
398
|
+
var onAuthChange = (callback) => {
|
|
399
|
+
if (!isBrowser()) {
|
|
400
|
+
return () => {
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
listeners.add(callback);
|
|
404
|
+
attachStorageListener();
|
|
405
|
+
return () => {
|
|
406
|
+
listeners.delete(callback);
|
|
407
|
+
};
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// src/auth.ts
|
|
411
|
+
var getCookies = () => {
|
|
412
|
+
const cookies = globalThis.Netlify?.context?.cookies;
|
|
413
|
+
if (!cookies) {
|
|
414
|
+
throw new AuthError("Server-side auth requires Netlify Functions runtime");
|
|
415
|
+
}
|
|
416
|
+
return cookies;
|
|
417
|
+
};
|
|
418
|
+
var getServerIdentityUrl = () => {
|
|
419
|
+
const ctx = getIdentityContext();
|
|
420
|
+
if (!ctx?.url) {
|
|
421
|
+
throw new AuthError("Could not determine the Identity endpoint URL on the server");
|
|
422
|
+
}
|
|
423
|
+
return ctx.url;
|
|
424
|
+
};
|
|
425
|
+
var persistSession = true;
|
|
426
|
+
var login = async (email, password) => {
|
|
427
|
+
if (!isBrowser()) {
|
|
428
|
+
const identityUrl = getServerIdentityUrl();
|
|
429
|
+
const cookies = getCookies();
|
|
430
|
+
const body = new URLSearchParams({
|
|
431
|
+
grant_type: "password",
|
|
432
|
+
username: email,
|
|
433
|
+
password
|
|
434
|
+
});
|
|
435
|
+
let res;
|
|
436
|
+
try {
|
|
437
|
+
res = await fetch(`${identityUrl}/token`, {
|
|
438
|
+
method: "POST",
|
|
439
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
440
|
+
body: body.toString()
|
|
441
|
+
});
|
|
442
|
+
} catch (error) {
|
|
443
|
+
throw AuthError.from(error);
|
|
444
|
+
}
|
|
445
|
+
if (!res.ok) {
|
|
446
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
447
|
+
throw new AuthError(errorBody.msg || errorBody.error_description || `Login failed (${res.status})`, res.status);
|
|
448
|
+
}
|
|
449
|
+
const data = await res.json();
|
|
450
|
+
const accessToken = data.access_token;
|
|
451
|
+
let userRes;
|
|
452
|
+
try {
|
|
453
|
+
userRes = await fetch(`${identityUrl}/user`, {
|
|
454
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
455
|
+
});
|
|
456
|
+
} catch (error) {
|
|
457
|
+
throw AuthError.from(error);
|
|
458
|
+
}
|
|
459
|
+
if (!userRes.ok) {
|
|
460
|
+
const errorBody = await userRes.json().catch(() => ({}));
|
|
461
|
+
throw new AuthError(errorBody.msg || `Failed to fetch user data (${userRes.status})`, userRes.status);
|
|
462
|
+
}
|
|
463
|
+
const userData = await userRes.json();
|
|
464
|
+
const user = toUser(userData);
|
|
465
|
+
setAuthCookies(cookies, accessToken, data.refresh_token);
|
|
466
|
+
return user;
|
|
467
|
+
}
|
|
468
|
+
const client = getClient();
|
|
469
|
+
try {
|
|
470
|
+
const gotrueUser = await client.login(email, password, persistSession);
|
|
471
|
+
const jwt = await gotrueUser.jwt();
|
|
472
|
+
setBrowserAuthCookies(jwt, gotrueUser.tokenDetails()?.refresh_token);
|
|
473
|
+
const user = toUser(gotrueUser);
|
|
474
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
475
|
+
return user;
|
|
476
|
+
} catch (error) {
|
|
477
|
+
throw AuthError.from(error);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var signup = async (email, password, data) => {
|
|
481
|
+
if (!isBrowser()) {
|
|
482
|
+
const identityUrl = getServerIdentityUrl();
|
|
483
|
+
const cookies = getCookies();
|
|
484
|
+
let res;
|
|
485
|
+
try {
|
|
486
|
+
res = await fetch(`${identityUrl}/signup`, {
|
|
487
|
+
method: "POST",
|
|
488
|
+
headers: { "Content-Type": "application/json" },
|
|
489
|
+
body: JSON.stringify({ email, password, data })
|
|
490
|
+
});
|
|
491
|
+
} catch (error) {
|
|
492
|
+
throw AuthError.from(error);
|
|
493
|
+
}
|
|
494
|
+
if (!res.ok) {
|
|
495
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
496
|
+
throw new AuthError(errorBody.msg || `Signup failed (${res.status})`, res.status);
|
|
497
|
+
}
|
|
498
|
+
const responseData = await res.json();
|
|
499
|
+
const user = toUser(responseData);
|
|
500
|
+
if (responseData.confirmed_at) {
|
|
501
|
+
const accessToken = responseData.access_token;
|
|
502
|
+
if (accessToken) {
|
|
503
|
+
setAuthCookies(cookies, accessToken, responseData.refresh_token);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return user;
|
|
507
|
+
}
|
|
508
|
+
const client = getClient();
|
|
509
|
+
try {
|
|
510
|
+
const response = await client.signup(email, password, data);
|
|
511
|
+
const user = toUser(response);
|
|
512
|
+
if (response.confirmed_at) {
|
|
513
|
+
const jwt = await response.jwt?.();
|
|
514
|
+
if (jwt) {
|
|
515
|
+
const refreshToken = response.tokenDetails?.()?.refresh_token;
|
|
516
|
+
setBrowserAuthCookies(jwt, refreshToken);
|
|
517
|
+
}
|
|
518
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
519
|
+
}
|
|
520
|
+
return user;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
throw AuthError.from(error);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
var logout = async () => {
|
|
526
|
+
if (!isBrowser()) {
|
|
527
|
+
const identityUrl = getServerIdentityUrl();
|
|
528
|
+
const cookies = getCookies();
|
|
529
|
+
const jwt = cookies.get(NF_JWT_COOKIE);
|
|
530
|
+
if (jwt) {
|
|
531
|
+
try {
|
|
532
|
+
await fetch(`${identityUrl}/logout`, {
|
|
533
|
+
method: "POST",
|
|
534
|
+
headers: { Authorization: `Bearer ${jwt}` }
|
|
535
|
+
});
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
deleteAuthCookies(cookies);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const client = getClient();
|
|
543
|
+
try {
|
|
544
|
+
const currentUser = client.currentUser();
|
|
545
|
+
if (currentUser) {
|
|
546
|
+
await currentUser.logout();
|
|
547
|
+
}
|
|
548
|
+
deleteBrowserAuthCookies();
|
|
549
|
+
emitAuthEvent(AUTH_EVENTS.LOGOUT, null);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
throw AuthError.from(error);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
var oauthLogin = (provider) => {
|
|
555
|
+
if (!isBrowser()) {
|
|
556
|
+
throw new AuthError("oauthLogin() is only available in the browser");
|
|
557
|
+
}
|
|
558
|
+
const client = getClient();
|
|
559
|
+
window.location.href = client.loginExternalUrl(provider);
|
|
560
|
+
throw new AuthError("Redirecting to OAuth provider");
|
|
561
|
+
};
|
|
562
|
+
var handleAuthCallback = async () => {
|
|
563
|
+
if (!isBrowser()) return null;
|
|
564
|
+
const hash = window.location.hash.substring(1);
|
|
565
|
+
if (!hash) return null;
|
|
566
|
+
const client = getClient();
|
|
567
|
+
const params = new URLSearchParams(hash);
|
|
568
|
+
try {
|
|
569
|
+
const accessToken = params.get("access_token");
|
|
570
|
+
if (accessToken) return await handleOAuthCallback(client, params, accessToken);
|
|
571
|
+
const confirmationToken = params.get("confirmation_token");
|
|
572
|
+
if (confirmationToken) return await handleConfirmationCallback(client, confirmationToken);
|
|
573
|
+
const recoveryToken = params.get("recovery_token");
|
|
574
|
+
if (recoveryToken) return await handleRecoveryCallback(client, recoveryToken);
|
|
575
|
+
const inviteToken = params.get("invite_token");
|
|
576
|
+
if (inviteToken) return handleInviteCallback(inviteToken);
|
|
577
|
+
const emailChangeToken = params.get("email_change_token");
|
|
578
|
+
if (emailChangeToken) return await handleEmailChangeCallback(client, emailChangeToken);
|
|
579
|
+
return null;
|
|
580
|
+
} catch (error) {
|
|
581
|
+
if (error instanceof AuthError) throw error;
|
|
582
|
+
throw AuthError.from(error);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
var handleOAuthCallback = async (client, params, accessToken) => {
|
|
586
|
+
const refreshToken = params.get("refresh_token") ?? "";
|
|
587
|
+
const expiresIn = parseInt(params.get("expires_in") ?? "", 10);
|
|
588
|
+
const expiresAt = parseInt(params.get("expires_at") ?? "", 10);
|
|
589
|
+
const gotrueUser = await client.createUser(
|
|
590
|
+
{
|
|
591
|
+
access_token: accessToken,
|
|
592
|
+
token_type: params.get("token_type") ?? "bearer",
|
|
593
|
+
expires_in: isFinite(expiresIn) ? expiresIn : 3600,
|
|
594
|
+
expires_at: isFinite(expiresAt) ? expiresAt : Math.floor(Date.now() / 1e3) + 3600,
|
|
595
|
+
refresh_token: refreshToken
|
|
596
|
+
},
|
|
597
|
+
persistSession
|
|
598
|
+
);
|
|
599
|
+
setBrowserAuthCookies(accessToken, refreshToken || void 0);
|
|
600
|
+
const user = toUser(gotrueUser);
|
|
601
|
+
clearHash();
|
|
602
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
603
|
+
return { type: "oauth", user };
|
|
604
|
+
};
|
|
605
|
+
var handleConfirmationCallback = async (client, token) => {
|
|
606
|
+
const gotrueUser = await client.confirm(token, persistSession);
|
|
607
|
+
const jwt = await gotrueUser.jwt();
|
|
608
|
+
setBrowserAuthCookies(jwt, gotrueUser.tokenDetails()?.refresh_token);
|
|
609
|
+
const user = toUser(gotrueUser);
|
|
610
|
+
clearHash();
|
|
611
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
612
|
+
return { type: "confirmation", user };
|
|
613
|
+
};
|
|
614
|
+
var handleRecoveryCallback = async (client, token) => {
|
|
615
|
+
const gotrueUser = await client.recover(token, persistSession);
|
|
616
|
+
const jwt = await gotrueUser.jwt();
|
|
617
|
+
setBrowserAuthCookies(jwt, gotrueUser.tokenDetails()?.refresh_token);
|
|
618
|
+
const user = toUser(gotrueUser);
|
|
619
|
+
clearHash();
|
|
620
|
+
emitAuthEvent(AUTH_EVENTS.RECOVERY, user);
|
|
621
|
+
return { type: "recovery", user };
|
|
622
|
+
};
|
|
623
|
+
var handleInviteCallback = (token) => {
|
|
624
|
+
clearHash();
|
|
625
|
+
return { type: "invite", user: null, token };
|
|
626
|
+
};
|
|
627
|
+
var handleEmailChangeCallback = async (client, emailChangeToken) => {
|
|
628
|
+
const currentUser = client.currentUser();
|
|
629
|
+
if (!currentUser) {
|
|
630
|
+
throw new AuthError("Email change verification requires an active browser session");
|
|
631
|
+
}
|
|
632
|
+
const jwt = await currentUser.jwt();
|
|
633
|
+
const identityUrl = `${window.location.origin}${IDENTITY_PATH}`;
|
|
634
|
+
const emailChangeRes = await fetch(`${identityUrl}/user`, {
|
|
635
|
+
method: "PUT",
|
|
636
|
+
headers: {
|
|
637
|
+
"Content-Type": "application/json",
|
|
638
|
+
Authorization: `Bearer ${jwt}`
|
|
639
|
+
},
|
|
640
|
+
body: JSON.stringify({ email_change_token: emailChangeToken })
|
|
641
|
+
});
|
|
642
|
+
if (!emailChangeRes.ok) {
|
|
643
|
+
const errorBody = await emailChangeRes.json().catch(() => ({}));
|
|
644
|
+
throw new AuthError(
|
|
645
|
+
errorBody.msg || `Email change verification failed (${emailChangeRes.status})`,
|
|
646
|
+
emailChangeRes.status
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
const emailChangeData = await emailChangeRes.json();
|
|
650
|
+
const user = toUser(emailChangeData);
|
|
651
|
+
clearHash();
|
|
652
|
+
emitAuthEvent(AUTH_EVENTS.USER_UPDATED, user);
|
|
653
|
+
return { type: "email_change", user };
|
|
654
|
+
};
|
|
655
|
+
var clearHash = () => {
|
|
656
|
+
history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
657
|
+
};
|
|
658
|
+
var hydrateSession = async () => {
|
|
659
|
+
if (!isBrowser()) return null;
|
|
660
|
+
const client = getClient();
|
|
661
|
+
const currentUser = client.currentUser();
|
|
662
|
+
if (currentUser) return toUser(currentUser);
|
|
663
|
+
const accessToken = getCookie(NF_JWT_COOKIE);
|
|
664
|
+
if (!accessToken) return null;
|
|
665
|
+
const refreshToken = getCookie(NF_REFRESH_COOKIE) ?? "";
|
|
666
|
+
const decoded = decodeJwtPayload(accessToken);
|
|
667
|
+
const expiresAt = decoded?.exp ?? Math.floor(Date.now() / 1e3) + 3600;
|
|
668
|
+
const expiresIn = Math.max(0, expiresAt - Math.floor(Date.now() / 1e3));
|
|
669
|
+
let gotrueUser;
|
|
670
|
+
try {
|
|
671
|
+
gotrueUser = await client.createUser(
|
|
672
|
+
{
|
|
673
|
+
access_token: accessToken,
|
|
674
|
+
token_type: "bearer",
|
|
675
|
+
expires_in: expiresIn,
|
|
676
|
+
expires_at: expiresAt,
|
|
677
|
+
refresh_token: refreshToken
|
|
678
|
+
},
|
|
679
|
+
persistSession
|
|
680
|
+
);
|
|
681
|
+
} catch {
|
|
682
|
+
deleteBrowserAuthCookies();
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
const user = toUser(gotrueUser);
|
|
686
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
687
|
+
return user;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// src/account.ts
|
|
691
|
+
var resolveCurrentUser = async () => {
|
|
692
|
+
const client = getClient();
|
|
693
|
+
let currentUser = client.currentUser();
|
|
694
|
+
if (!currentUser && isBrowser()) {
|
|
695
|
+
try {
|
|
696
|
+
await hydrateSession();
|
|
697
|
+
} catch {
|
|
698
|
+
}
|
|
699
|
+
currentUser = client.currentUser();
|
|
700
|
+
}
|
|
701
|
+
if (!currentUser) throw new AuthError("No user is currently logged in");
|
|
702
|
+
return currentUser;
|
|
703
|
+
};
|
|
704
|
+
var requestPasswordRecovery = async (email) => {
|
|
705
|
+
const client = getClient();
|
|
706
|
+
try {
|
|
707
|
+
await client.requestPasswordRecovery(email);
|
|
708
|
+
} catch (error) {
|
|
709
|
+
throw AuthError.from(error);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
var recoverPassword = async (token, newPassword) => {
|
|
713
|
+
const client = getClient();
|
|
714
|
+
try {
|
|
715
|
+
const gotrueUser = await client.recover(token, persistSession);
|
|
716
|
+
const updatedUser = await gotrueUser.update({ password: newPassword });
|
|
717
|
+
const user = toUser(updatedUser);
|
|
718
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
719
|
+
return user;
|
|
720
|
+
} catch (error) {
|
|
721
|
+
throw AuthError.from(error);
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
var confirmEmail = async (token) => {
|
|
725
|
+
const client = getClient();
|
|
726
|
+
try {
|
|
727
|
+
const gotrueUser = await client.confirm(token, persistSession);
|
|
728
|
+
const user = toUser(gotrueUser);
|
|
729
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
730
|
+
return user;
|
|
731
|
+
} catch (error) {
|
|
732
|
+
throw AuthError.from(error);
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
var acceptInvite = async (token, password) => {
|
|
736
|
+
const client = getClient();
|
|
737
|
+
try {
|
|
738
|
+
const gotrueUser = await client.acceptInvite(token, password, persistSession);
|
|
739
|
+
const user = toUser(gotrueUser);
|
|
740
|
+
emitAuthEvent(AUTH_EVENTS.LOGIN, user);
|
|
741
|
+
return user;
|
|
742
|
+
} catch (error) {
|
|
743
|
+
throw AuthError.from(error);
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
var verifyEmailChange = async (token) => {
|
|
747
|
+
if (!isBrowser()) throw new AuthError("verifyEmailChange() is only available in the browser");
|
|
748
|
+
const currentUser = await resolveCurrentUser();
|
|
749
|
+
try {
|
|
750
|
+
const jwt = await currentUser.jwt();
|
|
751
|
+
const identityUrl = `${window.location.origin}${IDENTITY_PATH}`;
|
|
752
|
+
const res = await fetch(`${identityUrl}/user`, {
|
|
753
|
+
method: "PUT",
|
|
754
|
+
headers: {
|
|
755
|
+
"Content-Type": "application/json",
|
|
756
|
+
Authorization: `Bearer ${jwt}`
|
|
757
|
+
},
|
|
758
|
+
body: JSON.stringify({ email_change_token: token })
|
|
759
|
+
});
|
|
760
|
+
if (!res.ok) {
|
|
761
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
762
|
+
throw new AuthError(errorBody.msg || `Email change verification failed (${res.status})`, res.status);
|
|
763
|
+
}
|
|
764
|
+
const userData = await res.json();
|
|
765
|
+
const user = toUser(userData);
|
|
766
|
+
emitAuthEvent(AUTH_EVENTS.USER_UPDATED, user);
|
|
767
|
+
return user;
|
|
768
|
+
} catch (error) {
|
|
769
|
+
if (error instanceof AuthError) throw error;
|
|
770
|
+
throw AuthError.from(error);
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
var updateUser = async (updates) => {
|
|
774
|
+
const currentUser = await resolveCurrentUser();
|
|
775
|
+
try {
|
|
776
|
+
const updatedUser = await currentUser.update(updates);
|
|
777
|
+
const user = toUser(updatedUser);
|
|
778
|
+
emitAuthEvent(AUTH_EVENTS.USER_UPDATED, user);
|
|
779
|
+
return user;
|
|
780
|
+
} catch (error) {
|
|
781
|
+
throw AuthError.from(error);
|
|
782
|
+
}
|
|
783
|
+
};
|
|
188
784
|
// Annotate the CommonJS export names for ESM import in node:
|
|
189
785
|
0 && (module.exports = {
|
|
786
|
+
AUTH_EVENTS,
|
|
190
787
|
AuthError,
|
|
191
788
|
MissingIdentityError,
|
|
789
|
+
acceptInvite,
|
|
790
|
+
confirmEmail,
|
|
192
791
|
getIdentityConfig,
|
|
193
792
|
getSettings,
|
|
194
793
|
getUser,
|
|
195
|
-
|
|
794
|
+
handleAuthCallback,
|
|
795
|
+
hydrateSession,
|
|
796
|
+
isAuthenticated,
|
|
797
|
+
login,
|
|
798
|
+
logout,
|
|
799
|
+
oauthLogin,
|
|
800
|
+
onAuthChange,
|
|
801
|
+
recoverPassword,
|
|
802
|
+
requestPasswordRecovery,
|
|
803
|
+
signup,
|
|
804
|
+
updateUser,
|
|
805
|
+
verifyEmailChange
|
|
196
806
|
});
|
|
197
807
|
//# sourceMappingURL=index.cjs.map
|