@fusionauth/angular-sdk 1.0.2 → 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.
- package/README.md +5 -0
- package/esm2022/lib/SSRCookieAdapter.mjs +23 -0
- package/esm2022/lib/components/fusionauth-account.button/fusion-auth-account-button.component.mjs +18 -0
- package/esm2022/lib/components/fusionauth-login.button/fusion-auth-login-button.component.mjs +4 -4
- package/esm2022/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.mjs +4 -4
- package/esm2022/lib/components/fusionauth-register.button/fusion-auth-register-button.component.mjs +4 -4
- package/esm2022/lib/fusion-auth.module.mjs +15 -11
- package/esm2022/lib/fusion-auth.service.mjs +30 -3
- package/esm2022/lib/injectionToken.mjs +3 -0
- package/esm2022/lib/types.mjs +1 -1
- package/esm2022/public-api.mjs +2 -1
- package/esm2022/sdkcore/CookieHelpers/CookieHelpers.mjs +34 -0
- package/esm2022/sdkcore/CookieHelpers/index.mjs +2 -0
- package/esm2022/sdkcore/RedirectHelper/RedirectHelper.mjs +47 -0
- package/esm2022/sdkcore/RedirectHelper/index.mjs +2 -0
- package/esm2022/sdkcore/SDKConfig/SDKConfig.mjs +2 -0
- package/esm2022/sdkcore/SDKConfig/index.mjs +2 -0
- package/esm2022/sdkcore/SDKContext/SDKContext.mjs +2 -0
- package/esm2022/sdkcore/SDKContext/index.mjs +2 -0
- package/esm2022/sdkcore/SDKCore/SDKCore.mjs +110 -0
- package/esm2022/sdkcore/SDKCore/index.mjs +2 -0
- package/esm2022/sdkcore/UrlHelper/UrlHelper.mjs +69 -0
- package/esm2022/sdkcore/UrlHelper/UrlHelperTypes.mjs +2 -0
- package/esm2022/sdkcore/UrlHelper/index.mjs +3 -0
- package/esm2022/sdkcore/index.mjs +5 -0
- package/esm2022/sdkcore/testUtils/index.mjs +3 -0
- package/esm2022/sdkcore/testUtils/mockLoggedIn.mjs +13 -0
- package/esm2022/sdkcore/testUtils/mockWindowLocation.mjs +10 -0
- package/fesm2022/fusionauth-angular-sdk.mjs +282 -155
- package/fesm2022/fusionauth-angular-sdk.mjs.map +1 -1
- package/lib/SSRCookieAdapter.d.ts +7 -0
- package/lib/components/fusionauth-account.button/fusion-auth-account-button.component.d.ts +9 -0
- package/lib/fusion-auth.module.d.ts +2 -1
- package/lib/fusion-auth.service.d.ts +13 -5
- package/lib/injectionToken.d.ts +3 -0
- package/lib/types.d.ts +9 -1
- package/package.json +3 -3
- package/public-api.d.ts +1 -0
- package/sdkcore/CookieHelpers/CookieHelpers.d.ts +11 -0
- package/sdkcore/CookieHelpers/index.d.ts +1 -0
- package/sdkcore/RedirectHelper/RedirectHelper.d.ts +10 -0
- package/sdkcore/RedirectHelper/index.d.ts +1 -0
- package/sdkcore/SDKConfig/SDKConfig.d.ts +79 -0
- package/sdkcore/SDKConfig/index.d.ts +1 -0
- package/sdkcore/SDKContext/SDKContext.d.ts +69 -0
- package/sdkcore/SDKContext/index.d.ts +1 -0
- package/sdkcore/SDKCore/SDKCore.d.ts +28 -0
- package/sdkcore/SDKCore/index.d.ts +1 -0
- package/sdkcore/UrlHelper/UrlHelper.d.ts +23 -0
- package/sdkcore/UrlHelper/UrlHelperTypes.d.ts +11 -0
- package/sdkcore/UrlHelper/index.d.ts +2 -0
- package/sdkcore/index.d.ts +5 -0
- package/sdkcore/testUtils/index.d.ts +2 -0
- package/sdkcore/testUtils/mockLoggedIn.d.ts +5 -0
- package/sdkcore/testUtils/mockWindowLocation.d.ts +18 -0
- package/esm2022/lib/core.mjs +0 -217
- package/lib/core.d.ts +0 -35
|
@@ -1,57 +1,45 @@
|
|
|
1
|
-
import { BehaviorSubject, Observable, catchError } from 'rxjs';
|
|
2
1
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { Component, Input, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, PLATFORM_ID, Injectable, Inject, Component, Input, NgModule } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { BehaviorSubject, Observable, catchError } from 'rxjs';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
i(this, 'loginPath');
|
|
19
|
-
i(this, 'registerPath');
|
|
20
|
-
i(this, 'logoutPath');
|
|
21
|
-
i(this, 'tokenRefreshPath');
|
|
22
|
-
(this.serverUrl = e.serverUrl),
|
|
23
|
-
(this.clientId = e.clientId),
|
|
24
|
-
(this.redirectUri = e.redirectUri),
|
|
25
|
-
(this.scope = e.scope),
|
|
26
|
-
(this.mePath = e.mePath ?? '/app/me'),
|
|
27
|
-
(this.loginPath = e.loginPath ?? '/app/login'),
|
|
28
|
-
(this.registerPath = e.registerPath ?? '/app/register'),
|
|
29
|
-
(this.logoutPath = e.logoutPath ?? '/app/logout'),
|
|
30
|
-
(this.tokenRefreshPath = e.tokenRefreshPath ?? '/app/refresh');
|
|
6
|
+
/** A class responsible for generating URLs that FusionAuth SDKs interact with. */
|
|
7
|
+
class UrlHelper {
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.serverUrl = config.serverUrl;
|
|
10
|
+
this.clientId = config.clientId;
|
|
11
|
+
this.redirectUri = config.redirectUri;
|
|
12
|
+
this.scope = config.scope;
|
|
13
|
+
this.postLogoutRedirectUri = config.postLogoutRedirectUri;
|
|
14
|
+
this.mePath = config.mePath ?? '/app/me/';
|
|
15
|
+
this.loginPath = config.loginPath ?? '/app/login/';
|
|
16
|
+
this.registerPath = config.registerPath ?? '/app/register/';
|
|
17
|
+
this.logoutPath = config.logoutPath ?? '/app/logout/';
|
|
18
|
+
this.tokenRefreshPath = config.tokenRefreshPath ?? '/app/refresh/';
|
|
31
19
|
}
|
|
32
20
|
getMeUrl() {
|
|
33
21
|
return this.generateUrl(this.mePath);
|
|
34
22
|
}
|
|
35
|
-
getLoginUrl(
|
|
23
|
+
getLoginUrl(state) {
|
|
36
24
|
return this.generateUrl(this.loginPath, {
|
|
37
25
|
client_id: this.clientId,
|
|
38
26
|
redirect_uri: this.redirectUri,
|
|
39
27
|
scope: this.scope,
|
|
40
|
-
state
|
|
28
|
+
state,
|
|
41
29
|
});
|
|
42
30
|
}
|
|
43
|
-
getRegisterUrl(
|
|
31
|
+
getRegisterUrl(state) {
|
|
44
32
|
return this.generateUrl(this.registerPath, {
|
|
45
33
|
client_id: this.clientId,
|
|
46
34
|
redirect_uri: this.redirectUri,
|
|
47
35
|
scope: this.scope,
|
|
48
|
-
state
|
|
36
|
+
state,
|
|
49
37
|
});
|
|
50
38
|
}
|
|
51
39
|
getLogoutUrl() {
|
|
52
40
|
return this.generateUrl(this.logoutPath, {
|
|
53
41
|
client_id: this.clientId,
|
|
54
|
-
post_logout_redirect_uri: this.redirectUri,
|
|
42
|
+
post_logout_redirect_uri: this.postLogoutRedirectUri || this.redirectUri,
|
|
55
43
|
});
|
|
56
44
|
}
|
|
57
45
|
getTokenRefreshUrl() {
|
|
@@ -59,175 +47,276 @@ class g {
|
|
|
59
47
|
client_id: this.clientId,
|
|
60
48
|
});
|
|
61
49
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
getAccountManagementUrl() {
|
|
51
|
+
return this.generateUrl('/account/', {
|
|
52
|
+
client_id: this.clientId,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
generateUrl(path, params) {
|
|
56
|
+
const url = new URL(this.serverUrl);
|
|
57
|
+
url.pathname = path;
|
|
58
|
+
if (params) {
|
|
59
|
+
const urlSearchParams = this.generateURLSearchParams(params);
|
|
60
|
+
url.search = urlSearchParams.toString();
|
|
67
61
|
}
|
|
68
|
-
return
|
|
62
|
+
return url;
|
|
69
63
|
}
|
|
70
|
-
generateURLSearchParams(
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
generateURLSearchParams(params) {
|
|
65
|
+
const urlSearchParams = new URLSearchParams();
|
|
66
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
67
|
+
if (value) {
|
|
68
|
+
urlSearchParams.append(key, value);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return urlSearchParams;
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
|
-
|
|
74
|
+
|
|
75
|
+
/** A class responsible for storing a redirect value in localStorage and cleanup afterward. */
|
|
76
|
+
class RedirectHelper {
|
|
79
77
|
constructor() {
|
|
80
|
-
|
|
78
|
+
this.REDIRECT_VALUE = 'fa-sdk-redirect-value';
|
|
79
|
+
}
|
|
80
|
+
get storage() {
|
|
81
|
+
try {
|
|
82
|
+
return localStorage;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// fallback for non-browser environments where localStorage is not defined.
|
|
86
|
+
return {
|
|
87
|
+
/* eslint-disable */
|
|
88
|
+
setItem(_key, _value) { },
|
|
89
|
+
getItem(_key) { },
|
|
90
|
+
removeItem(_key) { },
|
|
91
|
+
/* eslint-enable */
|
|
92
|
+
};
|
|
93
|
+
}
|
|
81
94
|
}
|
|
82
|
-
handlePreRedirect(
|
|
83
|
-
const
|
|
84
|
-
|
|
95
|
+
handlePreRedirect(state) {
|
|
96
|
+
const valueForStorage = `${this.generateRandomString()}:${state ?? ''}`;
|
|
97
|
+
this.storage.setItem(this.REDIRECT_VALUE, valueForStorage);
|
|
85
98
|
}
|
|
86
|
-
handlePostRedirect(
|
|
87
|
-
const
|
|
88
|
-
|
|
99
|
+
handlePostRedirect(callback) {
|
|
100
|
+
const stateValue = this.stateValue ?? undefined;
|
|
101
|
+
callback?.(stateValue);
|
|
102
|
+
this.storage.removeItem(this.REDIRECT_VALUE);
|
|
89
103
|
}
|
|
90
104
|
get didRedirect() {
|
|
91
|
-
return
|
|
105
|
+
return Boolean(this.storage.getItem(this.REDIRECT_VALUE));
|
|
92
106
|
}
|
|
93
107
|
get stateValue() {
|
|
94
|
-
const
|
|
95
|
-
if (!
|
|
108
|
+
const redirectValue = this.storage.getItem(this.REDIRECT_VALUE);
|
|
109
|
+
if (!redirectValue) {
|
|
96
110
|
return null;
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
}
|
|
112
|
+
const [, ...stateValue] = redirectValue.split(':');
|
|
113
|
+
return stateValue.join(':');
|
|
99
114
|
}
|
|
100
115
|
generateRandomString() {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
const array = new Uint32Array(56 / 2);
|
|
117
|
+
window.crypto.getRandomValues(array);
|
|
118
|
+
return Array.from(array, (n) => ('0' + n.toString(16)).substring(-2)).join('');
|
|
104
119
|
}
|
|
105
120
|
}
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Gets the `app.at_exp` cookie and converts it to milliseconds since epoch.
|
|
124
|
+
* Returns -1 if the cookie is not present.
|
|
125
|
+
* @param cookieName - defaults to `app.at_exp`.
|
|
126
|
+
* @param adapter - SSR frameworks like Nuxt, Next, and angular/ssr will pass in an adapter.
|
|
127
|
+
*/
|
|
128
|
+
function getAccessTokenExpirationMoment(cookieName = 'app.at_exp', adapter) {
|
|
129
|
+
if (adapter) {
|
|
130
|
+
return toMilliseconds(adapter.at_exp(cookieName));
|
|
131
|
+
}
|
|
132
|
+
let cookie;
|
|
133
|
+
try {
|
|
134
|
+
// `document` throws a ReferenceError if this runs in a
|
|
135
|
+
// non-browser environment such as an SSR framework like Nuxt or Next.
|
|
136
|
+
cookie = document.cookie;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
console.error('Error accessing cookies in fusionauth. If you are using SSR you must configure the SDK with a cookie adapter');
|
|
140
|
+
return -1;
|
|
141
|
+
}
|
|
142
|
+
const expCookie = cookie
|
|
108
143
|
.split('; ')
|
|
109
|
-
.map(
|
|
110
|
-
.find(([
|
|
111
|
-
|
|
144
|
+
.map(c => c.split('='))
|
|
145
|
+
.find(([name]) => name === cookieName);
|
|
146
|
+
const cookieValue = expCookie?.[1];
|
|
147
|
+
return toMilliseconds(cookieValue);
|
|
112
148
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
function toMilliseconds(seconds) {
|
|
150
|
+
if (!seconds)
|
|
151
|
+
return -1;
|
|
152
|
+
else
|
|
153
|
+
return Number(seconds) * 1000;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** A class containing framework-agnostic SDK methods */
|
|
157
|
+
class SDKCore {
|
|
158
|
+
constructor(config) {
|
|
159
|
+
this.redirectHelper = new RedirectHelper();
|
|
160
|
+
this.config = config;
|
|
161
|
+
this.urlHelper = new UrlHelper({
|
|
162
|
+
serverUrl: config.serverUrl,
|
|
163
|
+
clientId: config.clientId,
|
|
164
|
+
redirectUri: config.redirectUri,
|
|
165
|
+
scope: config.scope,
|
|
166
|
+
mePath: config.mePath,
|
|
167
|
+
loginPath: config.loginPath,
|
|
168
|
+
registerPath: config.registerPath,
|
|
169
|
+
logoutPath: config.logoutPath,
|
|
170
|
+
tokenRefreshPath: config.tokenRefreshPath,
|
|
171
|
+
postLogoutRedirectUri: config.postLogoutRedirectUri,
|
|
172
|
+
});
|
|
173
|
+
this.scheduleTokenExpiration();
|
|
174
|
+
}
|
|
175
|
+
startLogin(state) {
|
|
176
|
+
this.redirectHelper.handlePreRedirect(state);
|
|
177
|
+
window.location.assign(this.urlHelper.getLoginUrl(state));
|
|
178
|
+
}
|
|
179
|
+
startRegister(state) {
|
|
180
|
+
this.redirectHelper.handlePreRedirect(state);
|
|
181
|
+
window.location.assign(this.urlHelper.getRegisterUrl(state));
|
|
140
182
|
}
|
|
141
183
|
startLogout() {
|
|
142
184
|
window.location.assign(this.urlHelper.getLogoutUrl());
|
|
143
185
|
}
|
|
186
|
+
manageAccount() {
|
|
187
|
+
window.location.assign(this.urlHelper.getAccountManagementUrl());
|
|
188
|
+
}
|
|
144
189
|
async fetchUserInfo() {
|
|
145
|
-
const
|
|
190
|
+
const userInfoResponse = await fetch(this.urlHelper.getMeUrl(), {
|
|
146
191
|
credentials: 'include',
|
|
147
192
|
});
|
|
148
|
-
if (!
|
|
149
|
-
throw new Error(`Unable to fetch userInfo in fusionauth. Request failed with status code ${
|
|
150
|
-
|
|
193
|
+
if (!userInfoResponse.ok) {
|
|
194
|
+
throw new Error(`Unable to fetch userInfo in fusionauth. Request failed with status code ${userInfoResponse?.status}`);
|
|
195
|
+
}
|
|
196
|
+
const userInfo = await userInfoResponse.json();
|
|
197
|
+
return userInfo;
|
|
151
198
|
}
|
|
152
199
|
async refreshToken() {
|
|
153
|
-
const
|
|
200
|
+
const response = await fetch(this.urlHelper.getTokenRefreshUrl(), {
|
|
154
201
|
method: 'POST',
|
|
155
202
|
credentials: 'include',
|
|
156
203
|
headers: {
|
|
157
204
|
'Content-Type': 'text/plain',
|
|
158
205
|
},
|
|
159
206
|
});
|
|
160
|
-
if (!(
|
|
161
|
-
const
|
|
207
|
+
if (!(response.status >= 200 && response.status < 300)) {
|
|
208
|
+
const message = (await response?.text()) ||
|
|
162
209
|
'Error refreshing access token in fusionauth';
|
|
163
|
-
throw new Error(
|
|
210
|
+
throw new Error(message);
|
|
164
211
|
}
|
|
165
|
-
|
|
212
|
+
// a successful request means that app_exp was bumped into the future.
|
|
213
|
+
// reschedule the access token expiration event.
|
|
214
|
+
this.scheduleTokenExpiration();
|
|
215
|
+
return response;
|
|
166
216
|
}
|
|
167
217
|
initAutoRefresh() {
|
|
168
|
-
|
|
169
|
-
if (!e)
|
|
218
|
+
if (!this.isLoggedIn) {
|
|
170
219
|
return;
|
|
171
|
-
|
|
220
|
+
}
|
|
221
|
+
const secondsBeforeRefresh = this.config.autoRefreshSecondsBeforeExpiry ?? 10;
|
|
222
|
+
const millisecondsBeforeRefresh = secondsBeforeRefresh * 1000;
|
|
223
|
+
const now = new Date().getTime();
|
|
224
|
+
const refreshTime = this.at_exp - millisecondsBeforeRefresh;
|
|
225
|
+
const timeTillRefresh = Math.max(refreshTime - now, 0);
|
|
172
226
|
return setTimeout(async () => {
|
|
173
|
-
let n, a;
|
|
174
227
|
try {
|
|
175
|
-
await this.refreshToken()
|
|
228
|
+
await this.refreshToken();
|
|
229
|
+
this.initAutoRefresh();
|
|
176
230
|
}
|
|
177
|
-
catch (
|
|
178
|
-
|
|
231
|
+
catch (error) {
|
|
232
|
+
this.config.onAutoRefreshFailure?.(error);
|
|
179
233
|
}
|
|
180
|
-
},
|
|
234
|
+
}, timeTillRefresh);
|
|
181
235
|
}
|
|
182
|
-
handlePostRedirect(
|
|
183
|
-
this.isLoggedIn &&
|
|
184
|
-
this.redirectHelper.
|
|
185
|
-
|
|
236
|
+
handlePostRedirect(callback) {
|
|
237
|
+
if (this.isLoggedIn && this.redirectHelper.didRedirect) {
|
|
238
|
+
this.redirectHelper.handlePostRedirect(callback);
|
|
239
|
+
}
|
|
186
240
|
}
|
|
187
241
|
get isLoggedIn() {
|
|
188
|
-
return this.at_exp
|
|
189
|
-
? this.at_exp > /* @__PURE__ */ new Date().getTime()
|
|
190
|
-
: !1;
|
|
242
|
+
return this.at_exp > new Date().getTime();
|
|
191
243
|
}
|
|
192
244
|
/** The moment of access token expiration in milliseconds since epoch. */
|
|
193
245
|
get at_exp() {
|
|
194
|
-
return
|
|
246
|
+
return getAccessTokenExpirationMoment(this.config.accessTokenExpireCookieName, this.config.cookieAdapter);
|
|
195
247
|
}
|
|
196
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* Schedules `onTokenExpiration` at moment of access token expiration.
|
|
250
|
+
* SDKCore is not necessarily reactive like React, Angular, and Vue.
|
|
251
|
+
* so `onTokenExpiration` is for reactive frameworks to hook in and perform actions as on token expiration.
|
|
252
|
+
*/
|
|
197
253
|
scheduleTokenExpiration() {
|
|
198
254
|
clearTimeout(this.tokenExpirationTimeout);
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
255
|
+
const now = new Date().getTime();
|
|
256
|
+
const millisecondsTillExpiration = this.at_exp - now;
|
|
257
|
+
if (millisecondsTillExpiration > 0) {
|
|
258
|
+
this.tokenExpirationTimeout = setTimeout(this.config.onTokenExpiration, millisecondsTillExpiration);
|
|
259
|
+
}
|
|
202
260
|
}
|
|
203
261
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
262
|
+
|
|
263
|
+
/** Sets `app.at_exp` moment cookie so the user will be logged in for 1 hour. */
|
|
264
|
+
function mockIsLoggedIn() {
|
|
265
|
+
const expirationMoment = new Date();
|
|
266
|
+
expirationMoment.setHours(expirationMoment.getHours() + 1);
|
|
267
|
+
const oneHourInTheFutureInMilliseconds = expirationMoment.getTime() / 1000;
|
|
268
|
+
document.cookie = `app.at_exp=${oneHourInTheFutureInMilliseconds}`;
|
|
209
269
|
}
|
|
210
|
-
|
|
211
|
-
|
|
270
|
+
/** Removes the `app.at_exp` cookie. */
|
|
271
|
+
function removeAt_expCookie() {
|
|
272
|
+
document.cookie = 'app.at_exp' + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
|
212
273
|
}
|
|
213
|
-
|
|
214
|
-
|
|
274
|
+
|
|
275
|
+
function mockWindowLocation(vi) {
|
|
276
|
+
const mockedLocation = {
|
|
215
277
|
...window.location,
|
|
216
|
-
assign:
|
|
278
|
+
assign: vi.fn(),
|
|
217
279
|
};
|
|
218
|
-
|
|
280
|
+
vi.spyOn(window, 'location', 'get').mockReturnValue(mockedLocation);
|
|
281
|
+
return mockedLocation;
|
|
219
282
|
}
|
|
220
283
|
|
|
284
|
+
/** An adapter class that supports accessing cookies with SSR */
|
|
285
|
+
class SSRCookieAdapter {
|
|
286
|
+
constructor(isBrowser) {
|
|
287
|
+
this.isBrowser = isBrowser;
|
|
288
|
+
}
|
|
289
|
+
at_exp(cookieName = 'app.at_exp') {
|
|
290
|
+
if (!this.isBrowser) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
const expCookie = document.cookie
|
|
295
|
+
.split('; ')
|
|
296
|
+
.map(c => c.split('='))
|
|
297
|
+
.find(([name]) => name === cookieName);
|
|
298
|
+
return expCookie?.[1];
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
console.error('Error within the SSRCookieAdapter: ', error);
|
|
302
|
+
return -1;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const FUSIONAUTH_SERVICE_CONFIG = new InjectionToken('FUSIONAUTH_SERVICE_CONFIG');
|
|
308
|
+
|
|
221
309
|
/**
|
|
222
310
|
* Service class to use with FusionAuth backend endpoints.
|
|
223
311
|
*/
|
|
224
312
|
class FusionAuthService {
|
|
225
|
-
constructor(config) {
|
|
226
|
-
this.core = new
|
|
313
|
+
constructor(config, platformId) {
|
|
314
|
+
this.core = new SDKCore({
|
|
227
315
|
...config,
|
|
228
316
|
onTokenExpiration: () => {
|
|
229
317
|
this.isLoggedInSubject.next(false);
|
|
230
318
|
},
|
|
319
|
+
cookieAdapter: new SSRCookieAdapter(isPlatformBrowser(platformId)),
|
|
231
320
|
});
|
|
232
321
|
this.isLoggedInSubject = new BehaviorSubject(this.core.isLoggedIn);
|
|
233
322
|
this.isLoggedIn$ = this.isLoggedInSubject.asObservable();
|
|
@@ -305,7 +394,28 @@ class FusionAuthService {
|
|
|
305
394
|
logout() {
|
|
306
395
|
this.core.startLogout();
|
|
307
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Redirects to [self service account management](https://fusionauth.io/docs/lifecycle/manage-users/account-management/)
|
|
399
|
+
* Self service account management is only available in FusionAuth paid plans.
|
|
400
|
+
*/
|
|
401
|
+
manageAccount() {
|
|
402
|
+
this.core.manageAccount();
|
|
403
|
+
}
|
|
404
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthService, deps: [{ token: FUSIONAUTH_SERVICE_CONFIG }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
405
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthService, providedIn: 'root' }); }
|
|
308
406
|
}
|
|
407
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthService, decorators: [{
|
|
408
|
+
type: Injectable,
|
|
409
|
+
args: [{
|
|
410
|
+
providedIn: 'root',
|
|
411
|
+
}]
|
|
412
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
413
|
+
type: Inject,
|
|
414
|
+
args: [FUSIONAUTH_SERVICE_CONFIG]
|
|
415
|
+
}] }, { type: Object, decorators: [{
|
|
416
|
+
type: Inject,
|
|
417
|
+
args: [PLATFORM_ID]
|
|
418
|
+
}] }] });
|
|
309
419
|
|
|
310
420
|
class FusionAuthLoginButtonComponent {
|
|
311
421
|
constructor(fusionAuth) {
|
|
@@ -314,10 +424,10 @@ class FusionAuthLoginButtonComponent {
|
|
|
314
424
|
login() {
|
|
315
425
|
this.fusionAuth.startLogin(this.state);
|
|
316
426
|
}
|
|
317
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.
|
|
318
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.
|
|
427
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthLoginButtonComponent, deps: [{ token: FusionAuthService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
428
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.11", type: FusionAuthLoginButtonComponent, selector: "fa-login", inputs: { state: "state" }, ngImport: i0, template: "<button class=\"fa-button\" (click)=\"login()\">\n <span>Login</span>\n</button>\n", styles: [".fa-button{padding:16px 16px 13px;border-radius:8px;background-color:#083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:18px;font-weight:600;text-align:center;color:#fff;width:400px}.fa-button:hover{cursor:pointer}\n"] }); }
|
|
319
429
|
}
|
|
320
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.
|
|
430
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthLoginButtonComponent, decorators: [{
|
|
321
431
|
type: Component,
|
|
322
432
|
args: [{ selector: 'fa-login', template: "<button class=\"fa-button\" (click)=\"login()\">\n <span>Login</span>\n</button>\n", styles: [".fa-button{padding:16px 16px 13px;border-radius:8px;background-color:#083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:18px;font-weight:600;text-align:center;color:#fff;width:400px}.fa-button:hover{cursor:pointer}\n"] }]
|
|
323
433
|
}], ctorParameters: () => [{ type: FusionAuthService }], propDecorators: { state: [{
|
|
@@ -331,10 +441,10 @@ class FusionAuthLogoutButtonComponent {
|
|
|
331
441
|
logout() {
|
|
332
442
|
this.fusionAuth.logout();
|
|
333
443
|
}
|
|
334
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.
|
|
335
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.
|
|
444
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthLogoutButtonComponent, deps: [{ token: FusionAuthService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
445
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.11", type: FusionAuthLogoutButtonComponent, selector: "fa-logout", ngImport: i0, template: "<button class=\"fa-logout-button\" (click)=\"logout()\">\n <span>logout</span>\n</button>\n", styles: [".fa-logout-button{padding:7px 13px;border-radius:3px;display:block;border:solid 1px #083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:12px;text-align:center;color:#083b94}.fa-logout-button:hover{cursor:pointer}\n"] }); }
|
|
336
446
|
}
|
|
337
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.
|
|
447
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthLogoutButtonComponent, decorators: [{
|
|
338
448
|
type: Component,
|
|
339
449
|
args: [{ selector: 'fa-logout', template: "<button class=\"fa-logout-button\" (click)=\"logout()\">\n <span>logout</span>\n</button>\n", styles: [".fa-logout-button{padding:7px 13px;border-radius:3px;display:block;border:solid 1px #083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:12px;text-align:center;color:#083b94}.fa-logout-button:hover{cursor:pointer}\n"] }]
|
|
340
450
|
}], ctorParameters: () => [{ type: FusionAuthService }] });
|
|
@@ -346,49 +456,66 @@ class FusionAuthRegisterButtonComponent {
|
|
|
346
456
|
register() {
|
|
347
457
|
this.fusionAuth.startRegistration(this.state);
|
|
348
458
|
}
|
|
349
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.
|
|
350
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.
|
|
459
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthRegisterButtonComponent, deps: [{ token: FusionAuthService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
460
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.11", type: FusionAuthRegisterButtonComponent, selector: "fa-register", inputs: { state: "state" }, ngImport: i0, template: "<button class=\"fa-button\" (click)=\"register()\">\n <span>Register Now</span>\n</button>\n", styles: [".fa-button{padding:16px 16px 13px;border-radius:8px;background-color:#083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:18px;font-weight:600;text-align:center;color:#fff;width:400px}.fa-button:hover{cursor:pointer}\n"] }); }
|
|
351
461
|
}
|
|
352
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.
|
|
462
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthRegisterButtonComponent, decorators: [{
|
|
353
463
|
type: Component,
|
|
354
464
|
args: [{ selector: 'fa-register', template: "<button class=\"fa-button\" (click)=\"register()\">\n <span>Register Now</span>\n</button>\n", styles: [".fa-button{padding:16px 16px 13px;border-radius:8px;background-color:#083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:18px;font-weight:600;text-align:center;color:#fff;width:400px}.fa-button:hover{cursor:pointer}\n"] }]
|
|
355
465
|
}], ctorParameters: () => [{ type: FusionAuthService }], propDecorators: { state: [{
|
|
356
466
|
type: Input
|
|
357
467
|
}] } });
|
|
358
468
|
|
|
469
|
+
class FusionAuthAccountButtonComponent {
|
|
470
|
+
constructor(fusionAuth) {
|
|
471
|
+
this.fusionAuth = fusionAuth;
|
|
472
|
+
}
|
|
473
|
+
manageAccount() {
|
|
474
|
+
this.fusionAuth.manageAccount();
|
|
475
|
+
}
|
|
476
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthAccountButtonComponent, deps: [{ token: FusionAuthService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
477
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.11", type: FusionAuthAccountButtonComponent, selector: "fa-account", ngImport: i0, template: "<button class=\"fa-button\" (click)=\"manageAccount()\">\n <span>manage account</span>\n</button>\n", styles: [".fa-button{padding:16px 16px 13px;border-radius:8px;background-color:#083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:18px;font-weight:600;text-align:center;color:#fff;width:400px}.fa-button:hover{cursor:pointer}\n"] }); }
|
|
478
|
+
}
|
|
479
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthAccountButtonComponent, decorators: [{
|
|
480
|
+
type: Component,
|
|
481
|
+
args: [{ selector: 'fa-account', template: "<button class=\"fa-button\" (click)=\"manageAccount()\">\n <span>manage account</span>\n</button>\n", styles: [".fa-button{padding:16px 16px 13px;border-radius:8px;background-color:#083b94;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol;font-size:18px;font-weight:600;text-align:center;color:#fff;width:400px}.fa-button:hover{cursor:pointer}\n"] }]
|
|
482
|
+
}], ctorParameters: () => [{ type: FusionAuthService }] });
|
|
483
|
+
|
|
359
484
|
class FusionAuthModule {
|
|
360
485
|
static forRoot(fusionAuthConfig) {
|
|
361
486
|
return {
|
|
362
487
|
ngModule: FusionAuthModule,
|
|
363
488
|
providers: [
|
|
364
|
-
{
|
|
365
|
-
|
|
366
|
-
useValue: new FusionAuthService(fusionAuthConfig),
|
|
367
|
-
},
|
|
489
|
+
{ provide: FUSIONAUTH_SERVICE_CONFIG, useValue: fusionAuthConfig },
|
|
490
|
+
FusionAuthService,
|
|
368
491
|
],
|
|
369
492
|
};
|
|
370
493
|
}
|
|
371
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.
|
|
372
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.
|
|
494
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
495
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthModule, declarations: [FusionAuthLoginButtonComponent,
|
|
373
496
|
FusionAuthLogoutButtonComponent,
|
|
374
|
-
FusionAuthRegisterButtonComponent
|
|
497
|
+
FusionAuthRegisterButtonComponent,
|
|
498
|
+
FusionAuthAccountButtonComponent], exports: [FusionAuthLoginButtonComponent,
|
|
375
499
|
FusionAuthLogoutButtonComponent,
|
|
376
|
-
FusionAuthRegisterButtonComponent
|
|
377
|
-
|
|
500
|
+
FusionAuthRegisterButtonComponent,
|
|
501
|
+
FusionAuthAccountButtonComponent] }); }
|
|
502
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthModule }); }
|
|
378
503
|
}
|
|
379
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.
|
|
504
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FusionAuthModule, decorators: [{
|
|
380
505
|
type: NgModule,
|
|
381
506
|
args: [{
|
|
382
507
|
declarations: [
|
|
383
508
|
FusionAuthLoginButtonComponent,
|
|
384
509
|
FusionAuthLogoutButtonComponent,
|
|
385
510
|
FusionAuthRegisterButtonComponent,
|
|
511
|
+
FusionAuthAccountButtonComponent,
|
|
386
512
|
],
|
|
387
513
|
imports: [],
|
|
388
514
|
exports: [
|
|
389
515
|
FusionAuthLoginButtonComponent,
|
|
390
516
|
FusionAuthLogoutButtonComponent,
|
|
391
517
|
FusionAuthRegisterButtonComponent,
|
|
518
|
+
FusionAuthAccountButtonComponent,
|
|
392
519
|
],
|
|
393
520
|
}]
|
|
394
521
|
}] });
|
|
@@ -401,5 +528,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.1", ngImpor
|
|
|
401
528
|
* Generated bundle index. Do not edit.
|
|
402
529
|
*/
|
|
403
530
|
|
|
404
|
-
export { FusionAuthLoginButtonComponent, FusionAuthLogoutButtonComponent, FusionAuthModule, FusionAuthRegisterButtonComponent, FusionAuthService };
|
|
531
|
+
export { FusionAuthAccountButtonComponent, FusionAuthLoginButtonComponent, FusionAuthLogoutButtonComponent, FusionAuthModule, FusionAuthRegisterButtonComponent, FusionAuthService };
|
|
405
532
|
//# sourceMappingURL=fusionauth-angular-sdk.mjs.map
|