@netlify/identity 0.1.1-alpha.2 → 0.1.1-alpha.21
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 +505 -19
- package/dist/index.cjs +383 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +129 -17
- package/dist/index.d.ts +129 -17
- package/dist/index.js +388 -33
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
package/dist/index.cjs
CHANGED
|
@@ -38,11 +38,13 @@ __export(index_exports, {
|
|
|
38
38
|
getSettings: () => getSettings,
|
|
39
39
|
getUser: () => getUser,
|
|
40
40
|
handleAuthCallback: () => handleAuthCallback,
|
|
41
|
+
hydrateSession: () => hydrateSession,
|
|
41
42
|
isAuthenticated: () => isAuthenticated,
|
|
42
43
|
login: () => login,
|
|
43
44
|
logout: () => logout,
|
|
44
45
|
oauthLogin: () => oauthLogin,
|
|
45
46
|
onAuthChange: () => onAuthChange,
|
|
47
|
+
recoverPassword: () => recoverPassword,
|
|
46
48
|
requestPasswordRecovery: () => requestPasswordRecovery,
|
|
47
49
|
signup: () => signup,
|
|
48
50
|
updateUser: () => updateUser,
|
|
@@ -68,13 +70,14 @@ var AuthError = class extends Error {
|
|
|
68
70
|
}
|
|
69
71
|
};
|
|
70
72
|
var MissingIdentityError = class extends Error {
|
|
71
|
-
constructor(message = "Identity is not available in
|
|
73
|
+
constructor(message = "Netlify Identity is not available. Enable Identity in your site dashboard and use `netlify dev` for local development.") {
|
|
72
74
|
super(message);
|
|
73
75
|
this.name = "MissingIdentityError";
|
|
74
76
|
}
|
|
75
77
|
};
|
|
76
78
|
|
|
77
79
|
// src/environment.ts
|
|
80
|
+
var IDENTITY_PATH = "/.netlify/identity";
|
|
78
81
|
var goTrueClient = null;
|
|
79
82
|
var cachedApiUrl;
|
|
80
83
|
var warnedMissingUrl = false;
|
|
@@ -82,13 +85,15 @@ var isBrowser = () => typeof window !== "undefined" && typeof window.location !=
|
|
|
82
85
|
var discoverApiUrl = () => {
|
|
83
86
|
if (cachedApiUrl !== void 0) return cachedApiUrl;
|
|
84
87
|
if (isBrowser()) {
|
|
85
|
-
cachedApiUrl = `${window.location.origin}
|
|
88
|
+
cachedApiUrl = `${window.location.origin}${IDENTITY_PATH}`;
|
|
86
89
|
} else {
|
|
87
90
|
const identityContext = getIdentityContext();
|
|
88
91
|
if (identityContext?.url) {
|
|
89
92
|
cachedApiUrl = identityContext.url;
|
|
90
93
|
} else if (globalThis.Netlify?.context?.url) {
|
|
91
|
-
cachedApiUrl = new URL(
|
|
94
|
+
cachedApiUrl = new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href;
|
|
95
|
+
} else if (process.env.URL) {
|
|
96
|
+
cachedApiUrl = new URL(IDENTITY_PATH, process.env.URL).href;
|
|
92
97
|
}
|
|
93
98
|
}
|
|
94
99
|
return cachedApiUrl ?? null;
|
|
@@ -105,7 +110,7 @@ var getGoTrueClient = () => {
|
|
|
105
110
|
}
|
|
106
111
|
return null;
|
|
107
112
|
}
|
|
108
|
-
goTrueClient = new import_gotrue_js.default({ APIUrl: apiUrl, setCookie:
|
|
113
|
+
goTrueClient = new import_gotrue_js.default({ APIUrl: apiUrl, setCookie: false });
|
|
109
114
|
return goTrueClient;
|
|
110
115
|
};
|
|
111
116
|
var getClient = () => {
|
|
@@ -115,18 +120,97 @@ var getClient = () => {
|
|
|
115
120
|
};
|
|
116
121
|
var getIdentityContext = () => {
|
|
117
122
|
const identityContext = globalThis.netlifyIdentityContext;
|
|
118
|
-
if (identityContext?.url
|
|
123
|
+
if (identityContext?.url) {
|
|
119
124
|
return {
|
|
120
125
|
url: identityContext.url,
|
|
121
|
-
token:
|
|
126
|
+
token: identityContext.token
|
|
122
127
|
};
|
|
123
128
|
}
|
|
124
129
|
if (globalThis.Netlify?.context?.url) {
|
|
125
|
-
return { url: new URL(
|
|
130
|
+
return { url: new URL(IDENTITY_PATH, globalThis.Netlify.context.url).href };
|
|
131
|
+
}
|
|
132
|
+
const siteUrl = process.env.URL;
|
|
133
|
+
if (siteUrl) {
|
|
134
|
+
return { url: new URL(IDENTITY_PATH, siteUrl).href };
|
|
126
135
|
}
|
|
127
136
|
return null;
|
|
128
137
|
};
|
|
129
138
|
|
|
139
|
+
// src/cookies.ts
|
|
140
|
+
var NF_JWT_COOKIE = "nf_jwt";
|
|
141
|
+
var NF_REFRESH_COOKIE = "nf_refresh";
|
|
142
|
+
var getCookie = (name) => {
|
|
143
|
+
const match = document.cookie.match(new RegExp(`(?:^|; )${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)`));
|
|
144
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
145
|
+
};
|
|
146
|
+
var setAuthCookies = (cookies, accessToken, refreshToken) => {
|
|
147
|
+
cookies.set({
|
|
148
|
+
name: NF_JWT_COOKIE,
|
|
149
|
+
value: accessToken,
|
|
150
|
+
httpOnly: false,
|
|
151
|
+
secure: true,
|
|
152
|
+
path: "/",
|
|
153
|
+
sameSite: "Lax"
|
|
154
|
+
});
|
|
155
|
+
if (refreshToken) {
|
|
156
|
+
cookies.set({
|
|
157
|
+
name: NF_REFRESH_COOKIE,
|
|
158
|
+
value: refreshToken,
|
|
159
|
+
httpOnly: false,
|
|
160
|
+
secure: true,
|
|
161
|
+
path: "/",
|
|
162
|
+
sameSite: "Lax"
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var deleteAuthCookies = (cookies) => {
|
|
167
|
+
cookies.delete(NF_JWT_COOKIE);
|
|
168
|
+
cookies.delete(NF_REFRESH_COOKIE);
|
|
169
|
+
};
|
|
170
|
+
var setBrowserAuthCookies = (accessToken, refreshToken) => {
|
|
171
|
+
document.cookie = `${NF_JWT_COOKIE}=${encodeURIComponent(accessToken)}; path=/; secure; samesite=lax`;
|
|
172
|
+
if (refreshToken) {
|
|
173
|
+
document.cookie = `${NF_REFRESH_COOKIE}=${encodeURIComponent(refreshToken)}; path=/; secure; samesite=lax`;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var deleteBrowserAuthCookies = () => {
|
|
177
|
+
document.cookie = `${NF_JWT_COOKIE}=; path=/; secure; samesite=lax; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
178
|
+
document.cookie = `${NF_REFRESH_COOKIE}=; path=/; secure; samesite=lax; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
179
|
+
};
|
|
180
|
+
var getServerCookie = (name) => {
|
|
181
|
+
const cookies = globalThis.Netlify?.context?.cookies;
|
|
182
|
+
if (!cookies || typeof cookies.get !== "function") return null;
|
|
183
|
+
return cookies.get(name) ?? null;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/nextjs.ts
|
|
187
|
+
var nextHeadersFn;
|
|
188
|
+
var triggerNextjsDynamic = () => {
|
|
189
|
+
if (nextHeadersFn === null) return;
|
|
190
|
+
if (nextHeadersFn === void 0) {
|
|
191
|
+
try {
|
|
192
|
+
if (typeof require === "undefined") {
|
|
193
|
+
nextHeadersFn = null;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const mod = require("next/headers");
|
|
197
|
+
nextHeadersFn = mod.headers;
|
|
198
|
+
} catch {
|
|
199
|
+
nextHeadersFn = null;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const fn = nextHeadersFn;
|
|
204
|
+
if (!fn) return;
|
|
205
|
+
try {
|
|
206
|
+
fn();
|
|
207
|
+
} catch (e) {
|
|
208
|
+
if (e instanceof Error && ("digest" in e || /bail\s*out.*prerende/i.test(e.message))) {
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
130
214
|
// src/user.ts
|
|
131
215
|
var toAuthProvider = (value) => typeof value === "string" && AUTH_PROVIDERS.includes(value) ? value : void 0;
|
|
132
216
|
var toUser = (userData) => {
|
|
@@ -152,32 +236,92 @@ var claimsToUser = (claims) => {
|
|
|
152
236
|
const userMeta = claims.user_metadata ?? {};
|
|
153
237
|
const name = userMeta.full_name || userMeta.name;
|
|
154
238
|
return {
|
|
155
|
-
id:
|
|
156
|
-
email:
|
|
239
|
+
id: claims.sub ?? "",
|
|
240
|
+
email: claims.email,
|
|
157
241
|
provider: toAuthProvider(appMeta.provider),
|
|
158
242
|
name: typeof name === "string" ? name : void 0,
|
|
159
243
|
metadata: userMeta
|
|
160
244
|
};
|
|
161
245
|
};
|
|
246
|
+
var hydrating = false;
|
|
247
|
+
var backgroundHydrate = (accessToken) => {
|
|
248
|
+
if (hydrating) return;
|
|
249
|
+
hydrating = true;
|
|
250
|
+
const refreshToken = getCookie(NF_REFRESH_COOKIE) ?? "";
|
|
251
|
+
const decoded = decodeJwtPayload(accessToken);
|
|
252
|
+
const expiresAt = decoded?.exp ?? Math.floor(Date.now() / 1e3) + 3600;
|
|
253
|
+
const expiresIn = Math.max(0, expiresAt - Math.floor(Date.now() / 1e3));
|
|
254
|
+
setTimeout(() => {
|
|
255
|
+
try {
|
|
256
|
+
const client = getClient();
|
|
257
|
+
client.createUser(
|
|
258
|
+
{
|
|
259
|
+
access_token: accessToken,
|
|
260
|
+
token_type: "bearer",
|
|
261
|
+
expires_in: expiresIn,
|
|
262
|
+
expires_at: expiresAt,
|
|
263
|
+
refresh_token: refreshToken
|
|
264
|
+
},
|
|
265
|
+
true
|
|
266
|
+
).catch(() => {
|
|
267
|
+
}).finally(() => {
|
|
268
|
+
hydrating = false;
|
|
269
|
+
});
|
|
270
|
+
} catch {
|
|
271
|
+
hydrating = false;
|
|
272
|
+
}
|
|
273
|
+
}, 0);
|
|
274
|
+
};
|
|
275
|
+
var decodeJwtPayload = (token) => {
|
|
276
|
+
try {
|
|
277
|
+
const parts = token.split(".");
|
|
278
|
+
if (parts.length !== 3) return null;
|
|
279
|
+
const payload = atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"));
|
|
280
|
+
return JSON.parse(payload);
|
|
281
|
+
} catch {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
162
285
|
var getUser = () => {
|
|
163
286
|
if (isBrowser()) {
|
|
164
287
|
const client = getGoTrueClient();
|
|
165
288
|
const currentUser = client?.currentUser() ?? null;
|
|
166
|
-
if (
|
|
167
|
-
|
|
289
|
+
if (currentUser) {
|
|
290
|
+
const jwt2 = getCookie(NF_JWT_COOKIE);
|
|
291
|
+
if (!jwt2) {
|
|
292
|
+
try {
|
|
293
|
+
currentUser.clearSession();
|
|
294
|
+
} catch {
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return toUser(currentUser);
|
|
299
|
+
}
|
|
300
|
+
const jwt = getCookie(NF_JWT_COOKIE);
|
|
301
|
+
if (!jwt) return null;
|
|
302
|
+
const claims = decodeJwtPayload(jwt);
|
|
303
|
+
if (!claims) return null;
|
|
304
|
+
backgroundHydrate(jwt);
|
|
305
|
+
return claimsToUser(claims);
|
|
168
306
|
}
|
|
307
|
+
triggerNextjsDynamic();
|
|
169
308
|
const identityContext = globalThis.netlifyIdentityContext;
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
309
|
+
if (identityContext?.user) {
|
|
310
|
+
return claimsToUser(identityContext.user);
|
|
311
|
+
}
|
|
312
|
+
const serverJwt = getServerCookie(NF_JWT_COOKIE);
|
|
313
|
+
if (serverJwt) {
|
|
314
|
+
const claims = decodeJwtPayload(serverJwt);
|
|
315
|
+
if (claims) return claimsToUser(claims);
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
174
318
|
};
|
|
175
319
|
var isAuthenticated = () => getUser() !== null;
|
|
176
320
|
|
|
177
321
|
// src/config.ts
|
|
178
322
|
var getIdentityConfig = () => {
|
|
179
323
|
if (isBrowser()) {
|
|
180
|
-
return { url: `${window.location.origin}
|
|
324
|
+
return { url: `${window.location.origin}${IDENTITY_PATH}` };
|
|
181
325
|
}
|
|
182
326
|
return getIdentityContext();
|
|
183
327
|
};
|
|
@@ -205,19 +349,37 @@ var getSettings = async () => {
|
|
|
205
349
|
};
|
|
206
350
|
|
|
207
351
|
// src/auth.ts
|
|
352
|
+
var getCookies = () => {
|
|
353
|
+
const cookies = globalThis.Netlify?.context?.cookies;
|
|
354
|
+
if (!cookies) {
|
|
355
|
+
throw new AuthError("Server-side auth requires Netlify Functions runtime");
|
|
356
|
+
}
|
|
357
|
+
return cookies;
|
|
358
|
+
};
|
|
359
|
+
var getServerIdentityUrl = () => {
|
|
360
|
+
const ctx = getIdentityContext();
|
|
361
|
+
if (!ctx?.url) {
|
|
362
|
+
throw new AuthError("Could not determine the Identity endpoint URL on the server");
|
|
363
|
+
}
|
|
364
|
+
return ctx.url;
|
|
365
|
+
};
|
|
208
366
|
var persistSession = true;
|
|
209
367
|
var listeners = /* @__PURE__ */ new Set();
|
|
210
368
|
var emitAuthEvent = (event, user) => {
|
|
211
369
|
for (const listener of listeners) {
|
|
212
|
-
|
|
370
|
+
try {
|
|
371
|
+
listener(event, user);
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
213
374
|
}
|
|
214
375
|
};
|
|
376
|
+
var GOTRUE_STORAGE_KEY = "gotrue.user";
|
|
215
377
|
var storageListenerAttached = false;
|
|
216
378
|
var attachStorageListener = () => {
|
|
217
379
|
if (storageListenerAttached) return;
|
|
218
380
|
storageListenerAttached = true;
|
|
219
381
|
window.addEventListener("storage", (event) => {
|
|
220
|
-
if (event.key !==
|
|
382
|
+
if (event.key !== GOTRUE_STORAGE_KEY) return;
|
|
221
383
|
if (event.newValue) {
|
|
222
384
|
const client = getGoTrueClient();
|
|
223
385
|
const currentUser = client?.currentUser();
|
|
@@ -239,9 +401,58 @@ var onAuthChange = (callback) => {
|
|
|
239
401
|
};
|
|
240
402
|
};
|
|
241
403
|
var login = async (email, password) => {
|
|
404
|
+
if (!isBrowser()) {
|
|
405
|
+
const identityUrl = getServerIdentityUrl();
|
|
406
|
+
const cookies = getCookies();
|
|
407
|
+
const body = new URLSearchParams({
|
|
408
|
+
grant_type: "password",
|
|
409
|
+
username: email,
|
|
410
|
+
password
|
|
411
|
+
});
|
|
412
|
+
let res;
|
|
413
|
+
try {
|
|
414
|
+
res = await fetch(`${identityUrl}/token`, {
|
|
415
|
+
method: "POST",
|
|
416
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
417
|
+
body: body.toString()
|
|
418
|
+
});
|
|
419
|
+
} catch (error) {
|
|
420
|
+
throw new AuthError(error.message, void 0, { cause: error });
|
|
421
|
+
}
|
|
422
|
+
if (!res.ok) {
|
|
423
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
424
|
+
throw new AuthError(
|
|
425
|
+
errorBody.msg || errorBody.error_description || `Login failed (${res.status})`,
|
|
426
|
+
res.status
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
const data = await res.json();
|
|
430
|
+
const accessToken = data.access_token;
|
|
431
|
+
let userRes;
|
|
432
|
+
try {
|
|
433
|
+
userRes = await fetch(`${identityUrl}/user`, {
|
|
434
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
435
|
+
});
|
|
436
|
+
} catch (error) {
|
|
437
|
+
throw new AuthError(error.message, void 0, { cause: error });
|
|
438
|
+
}
|
|
439
|
+
if (!userRes.ok) {
|
|
440
|
+
const errorBody = await userRes.json().catch(() => ({}));
|
|
441
|
+
throw new AuthError(
|
|
442
|
+
errorBody.msg || `Failed to fetch user data (${userRes.status})`,
|
|
443
|
+
userRes.status
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
const userData = await userRes.json();
|
|
447
|
+
const user = toUser(userData);
|
|
448
|
+
setAuthCookies(cookies, accessToken, data.refresh_token);
|
|
449
|
+
return user;
|
|
450
|
+
}
|
|
242
451
|
const client = getClient();
|
|
243
452
|
try {
|
|
244
453
|
const gotrueUser = await client.login(email, password, persistSession);
|
|
454
|
+
const jwt = await gotrueUser.jwt();
|
|
455
|
+
setBrowserAuthCookies(jwt);
|
|
245
456
|
const user = toUser(gotrueUser);
|
|
246
457
|
emitAuthEvent("login", user);
|
|
247
458
|
return user;
|
|
@@ -250,11 +461,43 @@ var login = async (email, password) => {
|
|
|
250
461
|
}
|
|
251
462
|
};
|
|
252
463
|
var signup = async (email, password, data) => {
|
|
464
|
+
if (!isBrowser()) {
|
|
465
|
+
const identityUrl = getServerIdentityUrl();
|
|
466
|
+
const cookies = getCookies();
|
|
467
|
+
let res;
|
|
468
|
+
try {
|
|
469
|
+
res = await fetch(`${identityUrl}/signup`, {
|
|
470
|
+
method: "POST",
|
|
471
|
+
headers: { "Content-Type": "application/json" },
|
|
472
|
+
body: JSON.stringify({ email, password, data })
|
|
473
|
+
});
|
|
474
|
+
} catch (error) {
|
|
475
|
+
throw new AuthError(error.message, void 0, { cause: error });
|
|
476
|
+
}
|
|
477
|
+
if (!res.ok) {
|
|
478
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
479
|
+
throw new AuthError(errorBody.msg || `Signup failed (${res.status})`, res.status);
|
|
480
|
+
}
|
|
481
|
+
const responseData = await res.json();
|
|
482
|
+
const user = toUser(responseData);
|
|
483
|
+
if (responseData.confirmed_at) {
|
|
484
|
+
const responseRecord = responseData;
|
|
485
|
+
const accessToken = responseRecord.access_token;
|
|
486
|
+
if (accessToken) {
|
|
487
|
+
setAuthCookies(cookies, accessToken, responseRecord.refresh_token);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return user;
|
|
491
|
+
}
|
|
253
492
|
const client = getClient();
|
|
254
493
|
try {
|
|
255
494
|
const response = await client.signup(email, password, data);
|
|
256
495
|
const user = toUser(response);
|
|
257
496
|
if (response.confirmed_at) {
|
|
497
|
+
const jwt = await response.jwt?.();
|
|
498
|
+
if (jwt) {
|
|
499
|
+
setBrowserAuthCookies(jwt);
|
|
500
|
+
}
|
|
258
501
|
emitAuthEvent("login", user);
|
|
259
502
|
}
|
|
260
503
|
return user;
|
|
@@ -263,12 +506,29 @@ var signup = async (email, password, data) => {
|
|
|
263
506
|
}
|
|
264
507
|
};
|
|
265
508
|
var logout = async () => {
|
|
509
|
+
if (!isBrowser()) {
|
|
510
|
+
const identityUrl = getServerIdentityUrl();
|
|
511
|
+
const cookies = getCookies();
|
|
512
|
+
const jwt = cookies.get(NF_JWT_COOKIE);
|
|
513
|
+
if (jwt) {
|
|
514
|
+
try {
|
|
515
|
+
await fetch(`${identityUrl}/logout`, {
|
|
516
|
+
method: "POST",
|
|
517
|
+
headers: { Authorization: `Bearer ${jwt}` }
|
|
518
|
+
});
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
deleteAuthCookies(cookies);
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
266
525
|
const client = getClient();
|
|
267
526
|
try {
|
|
268
527
|
const currentUser = client.currentUser();
|
|
269
528
|
if (currentUser) {
|
|
270
529
|
await currentUser.logout();
|
|
271
530
|
}
|
|
531
|
+
deleteBrowserAuthCookies();
|
|
272
532
|
emitAuthEvent("logout", null);
|
|
273
533
|
} catch (error) {
|
|
274
534
|
throw new AuthError(error.message, void 0, { cause: error });
|
|
@@ -276,11 +536,11 @@ var logout = async () => {
|
|
|
276
536
|
};
|
|
277
537
|
var oauthLogin = (provider) => {
|
|
278
538
|
if (!isBrowser()) {
|
|
279
|
-
throw new
|
|
539
|
+
throw new AuthError("oauthLogin() is only available in the browser");
|
|
280
540
|
}
|
|
281
541
|
const client = getClient();
|
|
282
542
|
window.location.href = client.loginExternalUrl(provider);
|
|
283
|
-
throw new
|
|
543
|
+
throw new AuthError("Redirecting to OAuth provider");
|
|
284
544
|
};
|
|
285
545
|
var handleAuthCallback = async () => {
|
|
286
546
|
if (!isBrowser()) return null;
|
|
@@ -291,16 +551,18 @@ var handleAuthCallback = async () => {
|
|
|
291
551
|
const params = new URLSearchParams(hash);
|
|
292
552
|
const accessToken = params.get("access_token");
|
|
293
553
|
if (accessToken) {
|
|
554
|
+
const refreshToken = params.get("refresh_token") ?? "";
|
|
294
555
|
const gotrueUser = await client.createUser(
|
|
295
556
|
{
|
|
296
557
|
access_token: accessToken,
|
|
297
558
|
token_type: params.get("token_type") ?? "bearer",
|
|
298
559
|
expires_in: Number(params.get("expires_in")),
|
|
299
560
|
expires_at: Number(params.get("expires_at")),
|
|
300
|
-
refresh_token:
|
|
561
|
+
refresh_token: refreshToken
|
|
301
562
|
},
|
|
302
563
|
persistSession
|
|
303
564
|
);
|
|
565
|
+
setBrowserAuthCookies(accessToken, refreshToken || void 0);
|
|
304
566
|
const user = toUser(gotrueUser);
|
|
305
567
|
clearHash();
|
|
306
568
|
emitAuthEvent("login", user);
|
|
@@ -309,6 +571,8 @@ var handleAuthCallback = async () => {
|
|
|
309
571
|
const confirmationToken = params.get("confirmation_token");
|
|
310
572
|
if (confirmationToken) {
|
|
311
573
|
const gotrueUser = await client.confirm(confirmationToken, persistSession);
|
|
574
|
+
const jwt = await gotrueUser.jwt();
|
|
575
|
+
setBrowserAuthCookies(jwt);
|
|
312
576
|
const user = toUser(gotrueUser);
|
|
313
577
|
clearHash();
|
|
314
578
|
emitAuthEvent("login", user);
|
|
@@ -317,6 +581,8 @@ var handleAuthCallback = async () => {
|
|
|
317
581
|
const recoveryToken = params.get("recovery_token");
|
|
318
582
|
if (recoveryToken) {
|
|
319
583
|
const gotrueUser = await client.recover(recoveryToken, persistSession);
|
|
584
|
+
const jwt = await gotrueUser.jwt();
|
|
585
|
+
setBrowserAuthCookies(jwt);
|
|
320
586
|
const user = toUser(gotrueUser);
|
|
321
587
|
clearHash();
|
|
322
588
|
emitAuthEvent("login", user);
|
|
@@ -331,25 +597,80 @@ var handleAuthCallback = async () => {
|
|
|
331
597
|
if (emailChangeToken) {
|
|
332
598
|
const currentUser = client.currentUser();
|
|
333
599
|
if (!currentUser) {
|
|
334
|
-
|
|
335
|
-
return { type: "email_change", user: null, token: emailChangeToken };
|
|
600
|
+
throw new AuthError("Email change verification requires an active browser session");
|
|
336
601
|
}
|
|
337
|
-
const
|
|
338
|
-
const
|
|
602
|
+
const jwt = await currentUser.jwt();
|
|
603
|
+
const identityUrl = `${window.location.origin}${IDENTITY_PATH}`;
|
|
604
|
+
const emailChangeRes = await fetch(`${identityUrl}/user`, {
|
|
605
|
+
method: "PUT",
|
|
606
|
+
headers: {
|
|
607
|
+
"Content-Type": "application/json",
|
|
608
|
+
Authorization: `Bearer ${jwt}`
|
|
609
|
+
},
|
|
610
|
+
body: JSON.stringify({ email_change_token: emailChangeToken })
|
|
611
|
+
});
|
|
612
|
+
if (!emailChangeRes.ok) {
|
|
613
|
+
const errorBody = await emailChangeRes.json().catch(() => ({}));
|
|
614
|
+
throw new AuthError(
|
|
615
|
+
errorBody.msg || `Email change verification failed (${emailChangeRes.status})`,
|
|
616
|
+
emailChangeRes.status
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
const emailChangeData = await emailChangeRes.json();
|
|
620
|
+
const user = toUser(emailChangeData);
|
|
339
621
|
clearHash();
|
|
340
622
|
emitAuthEvent("user_updated", user);
|
|
341
623
|
return { type: "email_change", user };
|
|
342
624
|
}
|
|
343
625
|
return null;
|
|
344
626
|
} catch (error) {
|
|
627
|
+
if (error instanceof AuthError) throw error;
|
|
345
628
|
throw new AuthError(error.message, void 0, { cause: error });
|
|
346
629
|
}
|
|
347
630
|
};
|
|
348
631
|
var clearHash = () => {
|
|
349
632
|
history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
350
633
|
};
|
|
634
|
+
var hydrateSession = async () => {
|
|
635
|
+
if (!isBrowser()) return null;
|
|
636
|
+
const client = getClient();
|
|
637
|
+
const currentUser = client.currentUser();
|
|
638
|
+
if (currentUser) return toUser(currentUser);
|
|
639
|
+
const accessToken = getCookie(NF_JWT_COOKIE);
|
|
640
|
+
if (!accessToken) return null;
|
|
641
|
+
const refreshToken = getCookie(NF_REFRESH_COOKIE) ?? "";
|
|
642
|
+
const decoded = decodeJwtPayload(accessToken);
|
|
643
|
+
const expiresAt = decoded?.exp ?? Math.floor(Date.now() / 1e3) + 3600;
|
|
644
|
+
const expiresIn = Math.max(0, expiresAt - Math.floor(Date.now() / 1e3));
|
|
645
|
+
const gotrueUser = await client.createUser(
|
|
646
|
+
{
|
|
647
|
+
access_token: accessToken,
|
|
648
|
+
token_type: "bearer",
|
|
649
|
+
expires_in: expiresIn,
|
|
650
|
+
expires_at: expiresAt,
|
|
651
|
+
refresh_token: refreshToken
|
|
652
|
+
},
|
|
653
|
+
persistSession
|
|
654
|
+
);
|
|
655
|
+
const user = toUser(gotrueUser);
|
|
656
|
+
emitAuthEvent("login", user);
|
|
657
|
+
return user;
|
|
658
|
+
};
|
|
351
659
|
|
|
352
660
|
// src/account.ts
|
|
661
|
+
var ensureCurrentUser = async () => {
|
|
662
|
+
const client = getClient();
|
|
663
|
+
let currentUser = client.currentUser();
|
|
664
|
+
if (!currentUser && isBrowser()) {
|
|
665
|
+
try {
|
|
666
|
+
await hydrateSession();
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
669
|
+
currentUser = client.currentUser();
|
|
670
|
+
}
|
|
671
|
+
if (!currentUser) throw new AuthError("No user is currently logged in");
|
|
672
|
+
return currentUser;
|
|
673
|
+
};
|
|
353
674
|
var requestPasswordRecovery = async (email) => {
|
|
354
675
|
const client = getClient();
|
|
355
676
|
try {
|
|
@@ -358,6 +679,18 @@ var requestPasswordRecovery = async (email) => {
|
|
|
358
679
|
throw new AuthError(error.message, void 0, { cause: error });
|
|
359
680
|
}
|
|
360
681
|
};
|
|
682
|
+
var recoverPassword = async (token, newPassword) => {
|
|
683
|
+
const client = getClient();
|
|
684
|
+
try {
|
|
685
|
+
const gotrueUser = await client.recover(token, persistSession);
|
|
686
|
+
const updatedUser = await gotrueUser.update({ password: newPassword });
|
|
687
|
+
const user = toUser(updatedUser);
|
|
688
|
+
emitAuthEvent("login", user);
|
|
689
|
+
return user;
|
|
690
|
+
} catch (error) {
|
|
691
|
+
throw new AuthError(error.message, void 0, { cause: error });
|
|
692
|
+
}
|
|
693
|
+
};
|
|
361
694
|
var confirmEmail = async (token) => {
|
|
362
695
|
const client = getClient();
|
|
363
696
|
try {
|
|
@@ -381,22 +714,37 @@ var acceptInvite = async (token, password) => {
|
|
|
381
714
|
}
|
|
382
715
|
};
|
|
383
716
|
var verifyEmailChange = async (token) => {
|
|
384
|
-
|
|
385
|
-
const currentUser =
|
|
386
|
-
|
|
717
|
+
if (!isBrowser()) throw new AuthError("verifyEmailChange() is only available in the browser");
|
|
718
|
+
const currentUser = await ensureCurrentUser();
|
|
719
|
+
const jwt = await currentUser.jwt();
|
|
720
|
+
const identityUrl = `${window.location.origin}${IDENTITY_PATH}`;
|
|
387
721
|
try {
|
|
388
|
-
const
|
|
389
|
-
|
|
722
|
+
const res = await fetch(`${identityUrl}/user`, {
|
|
723
|
+
method: "PUT",
|
|
724
|
+
headers: {
|
|
725
|
+
"Content-Type": "application/json",
|
|
726
|
+
Authorization: `Bearer ${jwt}`
|
|
727
|
+
},
|
|
728
|
+
body: JSON.stringify({ email_change_token: token })
|
|
729
|
+
});
|
|
730
|
+
if (!res.ok) {
|
|
731
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
732
|
+
throw new AuthError(
|
|
733
|
+
errorBody.msg || `Email change verification failed (${res.status})`,
|
|
734
|
+
res.status
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
const userData = await res.json();
|
|
738
|
+
const user = toUser(userData);
|
|
390
739
|
emitAuthEvent("user_updated", user);
|
|
391
740
|
return user;
|
|
392
741
|
} catch (error) {
|
|
742
|
+
if (error instanceof AuthError) throw error;
|
|
393
743
|
throw new AuthError(error.message, void 0, { cause: error });
|
|
394
744
|
}
|
|
395
745
|
};
|
|
396
746
|
var updateUser = async (updates) => {
|
|
397
|
-
const
|
|
398
|
-
const currentUser = client.currentUser();
|
|
399
|
-
if (!currentUser) throw new AuthError("No user is currently logged in");
|
|
747
|
+
const currentUser = await ensureCurrentUser();
|
|
400
748
|
try {
|
|
401
749
|
const updatedUser = await currentUser.update(updates);
|
|
402
750
|
const user = toUser(updatedUser);
|
|
@@ -416,11 +764,13 @@ var updateUser = async (updates) => {
|
|
|
416
764
|
getSettings,
|
|
417
765
|
getUser,
|
|
418
766
|
handleAuthCallback,
|
|
767
|
+
hydrateSession,
|
|
419
768
|
isAuthenticated,
|
|
420
769
|
login,
|
|
421
770
|
logout,
|
|
422
771
|
oauthLogin,
|
|
423
772
|
onAuthChange,
|
|
773
|
+
recoverPassword,
|
|
424
774
|
requestPasswordRecovery,
|
|
425
775
|
signup,
|
|
426
776
|
updateUser,
|