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