@schibsted/account-sdk-browser 6.0.0-alpha.1 → 6.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +8 -33
  2. package/dist/RESTClient.d.ts +91 -0
  3. package/dist/SDKError.d.ts +27 -0
  4. package/dist/cache.d.ts +65 -0
  5. package/dist/config.d.ts +86 -0
  6. package/dist/global-registry.d.ts +23 -0
  7. package/dist/globals.d.ts +13 -0
  8. package/dist/identity-s4nofYmB.js +370 -0
  9. package/dist/identity-s4nofYmB.js.map +1 -0
  10. package/dist/identity.d.ts +523 -0
  11. package/dist/identity.js +2 -0
  12. package/dist/index.d.ts +3 -0
  13. package/dist/index.js +4 -0
  14. package/dist/monetization.d.ts +94 -0
  15. package/dist/monetization.js +72 -0
  16. package/dist/monetization.js.map +1 -0
  17. package/{src → dist}/object.d.ts +4 -9
  18. package/dist/popup.d.ts +9 -0
  19. package/{src → dist}/spidTalk.d.ts +4 -6
  20. package/dist/url.d.ts +8 -0
  21. package/dist/validate.d.ts +50 -0
  22. package/dist/version-spE-k97g.js +289 -0
  23. package/dist/version-spE-k97g.js.map +1 -0
  24. package/dist/version.d.ts +2 -0
  25. package/package.json +38 -22
  26. package/src/RESTClient.ts +226 -0
  27. package/src/SDKError.ts +59 -0
  28. package/src/{cache.js → cache.ts} +52 -37
  29. package/src/{config.js → config.ts} +7 -32
  30. package/src/global-registry.ts +39 -0
  31. package/src/globals.ts +10 -0
  32. package/src/{identity.js → identity.ts} +539 -437
  33. package/{index.js → src/index.ts} +1 -3
  34. package/src/{monetization.js → monetization.ts} +77 -48
  35. package/src/{object.js → object.ts} +8 -15
  36. package/src/popup.ts +74 -0
  37. package/src/{spidTalk.js → spidTalk.ts} +10 -12
  38. package/src/{url.js → url.ts} +6 -10
  39. package/src/{validate.js → validate.ts} +26 -42
  40. package/src/{version.js → version.ts} +1 -2
  41. package/identity.d.ts +0 -1
  42. package/identity.js +0 -5
  43. package/index.d.ts +0 -4
  44. package/monetization.d.ts +0 -1
  45. package/monetization.js +0 -5
  46. package/payment.d.ts +0 -1
  47. package/payment.js +0 -5
  48. package/src/RESTClient.d.ts +0 -89
  49. package/src/RESTClient.js +0 -193
  50. package/src/SDKError.d.ts +0 -16
  51. package/src/SDKError.js +0 -55
  52. package/src/cache.d.ts +0 -64
  53. package/src/config.d.ts +0 -34
  54. package/src/global-registry.js +0 -20
  55. package/src/identity.d.ts +0 -679
  56. package/src/monetization.d.ts +0 -80
  57. package/src/payment.d.ts +0 -115
  58. package/src/payment.js +0 -211
  59. package/src/popup.d.ts +0 -10
  60. package/src/popup.js +0 -59
  61. package/src/url.d.ts +0 -10
  62. package/src/validate.d.ts +0 -64
  63. package/src/version.d.ts +0 -2
@@ -2,153 +2,203 @@
2
2
  * See LICENSE.md in the project root.
3
3
  */
4
4
 
5
- 'use strict';
6
-
7
- import { assert, isStr, isNonEmptyString, isObject, isUrl, isStrIn } from './validate.js';
8
- import { cloneDeep } from './object.js';
9
- import { urlMapper } from './url.js';
10
- import { ENDPOINTS, NAMESPACE } from './config.js';
11
- import EventEmitter from 'tiny-emitter';
5
+ import { TinyEmitter } from 'tiny-emitter';
12
6
  import Cache from './cache.js';
7
+ import { ENDPOINTS, NAMESPACE } from './config.js';
8
+ import { registerAndDispatchInGlobal } from './global-registry.js';
9
+ import { cloneDeep } from './object.js';
13
10
  import * as popup from './popup.js';
14
11
  import RESTClient from './RESTClient.js';
15
12
  import SDKError from './SDKError.js';
16
13
  import * as spidTalk from './spidTalk.js';
14
+ import { urlMapper } from './url.js';
15
+ import { assert, isNonEmptyString, isObject, isStr, isStrIn, isUrl } from './validate.js';
17
16
  import version from './version.js';
18
- import { registerGlobal } from './global-registry.js';
19
17
 
20
18
  /**
21
- * @typedef {object} LoginOptions
22
- * @property {string} state - An opaque value used by the client to maintain state between
23
- * the request and callback. It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
24
- * @property {string} [acrValues] - Authentication Context Class Reference Values. If
25
- * omitted, the user will be asked to authenticate using username+password.
26
- * For 2FA (Two-Factor Authentication) possible values are `sms`, `otp` (one time password),
27
- * `password` (will force password confirmation, even if user is already logged in), `eid`. Those values might
28
- * be mixed as space-separated string. To make sure that user has authenticated with 2FA you need
29
- * to verify AMR (Authentication Methods References) claim in ID token.
30
- * Might also be used to ensure additional acr (sms, otp) for already logged-in users.
31
- * Supported value is also 'otp-email' means one time password using email.
32
- * @property {string} [scope] - The OAuth scopes for the tokens. This is a list of
33
- * scopes, separated by space. If the list of scopes contains `openid`, the generated tokens
34
- * includes the id token which can be useful for getting information about the user. Omitting
35
- * scope is allowed, while `invalid_scope` is returned when the client asks for a scope you
36
- * aren’t allowed to request. {@link https://tools.ietf.org/html/rfc6749#section-3.3}
37
- * @property {string} [redirectUri] - Redirect uri that will receive the
38
- * code. Must exactly match a redirectUri from your client in self-service
39
- * @property {boolean} [preferPopup] - Should we try to open a popup window?
40
- * @property {string} [loginHint] - User email or UUID hint
41
- * @property {string} [tag] - Pulse tag
42
- * @property {string} [teaser] - Teaser slug. Teaser with given slug will be displayed
43
- * in place of default teaser
44
- * @property {number|string} [maxAge] - Specifies the allowable elapsed time in seconds since
45
- * the last time the End-User was actively authenticated. If last authentication time is more
46
- * than maxAge seconds in the past, re-authentication will be required. See the OpenID Connect
47
- * spec section 3.1.2.1 for more information
48
- * @property {string} [locale] - Optional parameter to overwrite client locale setting.
49
- * New flows supports nb_NO, fi_FI, sv_SE, en_US
50
- * @property {boolean} [oneStepLogin] - Display username and password on one screen
51
- * @property {string} [prompt] - String that specifies whether the Authorization Server prompts the
52
- * End-User for re-authentication or confirm account screen. Supported values: `select_account` or `login`
53
- * @property {string} [xDomainId] - Identifier for cross-domain tracking in Pulse
54
- * @property {string} [xEnvironmentId] - Environment for cross-domain tracking in Pulse
55
- * @property {string} [originCampaign] - Campaign identifier for tracking in Pulse
19
+ * Options accepted by {@link Identity#login} and related login URL helpers.
56
20
  */
21
+ export type LoginOptions = {
22
+ /**
23
+ * An opaque value used by the client to maintain state between the request and callback.
24
+ * It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
25
+ */
26
+ state: string;
27
+ /**
28
+ * Authentication Context Class Reference Values. If omitted, the user will be asked to
29
+ * authenticate using username+password. For 2FA (Two-Factor Authentication) possible values
30
+ * are `sms`, `otp` (one time password), `password` (will force password confirmation, even if
31
+ * user is already logged in), `eid`. Those values might be mixed as space-separated string.
32
+ * To make sure that user has authenticated with 2FA you need to verify AMR (Authentication
33
+ * Methods References) claim in ID token. Might also be used to ensure additional acr
34
+ * (sms, otp, eid) for already logged in users. Supported value is also 'otp-email' means one
35
+ * time password using email.
36
+ */
37
+ acrValues?: string;
38
+ /**
39
+ * The OAuth scopes for the tokens. This is a list of scopes, separated by space. If the list
40
+ * of scopes contains `openid`, the generated tokens includes the id token which can be useful
41
+ * for getting information about the user. Omitting scope is allowed, while `invalid_scope` is
42
+ * returned when the client asks for a scope you aren't allowed to request.
43
+ * {@link https://tools.ietf.org/html/rfc6749#section-3.3}
44
+ * Defaults to `openid`.
45
+ */
46
+ scope?: string;
47
+ /**
48
+ * Redirect uri that will receive the code. Must exactly match a redirectUri from your client
49
+ * in self-service
50
+ */
51
+ redirectUri?: string;
52
+ /** Should we try to open a popup window? Defaults to `false`. */
53
+ preferPopup?: boolean;
54
+ /** user email or UUID hint */
55
+ loginHint?: string;
56
+ /** Pulse tag */
57
+ tag?: string;
58
+ /** Teaser slug. Teaser with given slug will be displayed in place of default teaser */
59
+ teaser?: string;
60
+ /**
61
+ * Specifies the allowable elapsed time in seconds since the last time the End-User was actively
62
+ * authenticated. If last authentication time is more than maxAge seconds in the past,
63
+ * re-authentication will be required. See the OpenID Connect spec section 3.1.2.1 for more
64
+ * information
65
+ */
66
+ maxAge?: number | string;
67
+ /**
68
+ * Optional parameter to overwrite client locale setting.
69
+ * New flows supports nb_NO, fi_FI, sv_SE, en_US
70
+ */
71
+ locale?: string;
72
+ /** display username and password on one screen. Defaults to `false`. */
73
+ oneStepLogin?: boolean;
74
+ /**
75
+ * String that specifies whether the Authorization Server prompts the End-User for
76
+ * reauthentication or confirm account screen. Supported values: `select_account` or `login`.
77
+ * Defaults to `select_account`.
78
+ */
79
+ prompt?: string;
80
+ /** Identifier for cross-domain tracking in Pulse */
81
+ xDomainId?: string;
82
+ /** Environment for cross-domain tracking in Pulse */
83
+ xEnvironmentId?: string;
84
+ /** Campaign identifier for tracking in Pulse */
85
+ originCampaign?: string;
86
+ };
87
+
57
88
  /**
58
- * @typedef {object} SimplifiedLoginWidgetLoginOptions
59
- * @property {string|function(): (string|Promise<string>)} state - An opaque value used by the client to maintain state between
60
- * the request and callback. It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
61
- * @property {string} [acrValues] - Authentication Context Class Reference Values. If
62
- * omitted, the user will be asked to authenticate using username+password.
63
- * For 2FA (Two-Factor Authentication) possible values are `sms`, `otp` (one time password) and
64
- * `password` (will force password confirmation, even if user is already logged in). Those values might
65
- * be mixed as space-separated string. To make sure that user has authenticated with 2FA you need
66
- * to verify AMR (Authentication Methods References) claim in ID token.
67
- * Might also be used to ensure additional acr (sms, otp) for already logged-in users.
68
- * Supported value is also 'otp-email' means one time password using email.
69
- * @property {string} [scope] - The OAuth scopes for the tokens. This is a list of
70
- * scopes, separated by space. If the list of scopes contains `openid`, the generated tokens
71
- * includes the id token which can be useful for getting information about the user. Omitting
72
- * scope is allowed, while `invalid_scope` is returned when the client asks for a scope you
73
- * aren’t allowed to request. {@link https://tools.ietf.org/html/rfc6749#section-3.3}
74
- * @property {string} [redirectUri] - Redirect uri that will receive the
75
- * code. Must exactly match a redirectUri from your client in self-service
76
- * @property {boolean} [preferPopup] - Should we try to open a popup window?
77
- * @property {string} [loginHint] - User email or UUID hint
78
- * @property {string} [tag] - Pulse tag
79
- * @property {string} [teaser] - Teaser slug. Teaser with given slug will be displayed
80
- * in place of default teaser
81
- * @property {number|string} [maxAge] - Specifies the allowable elapsed time in seconds since
82
- * the last time the End-User was actively authenticated. If last authentication time is more
83
- * than maxAge seconds in the past, re-authentication will be required. See the OpenID Connect
84
- * spec section 3.1.2.1 for more information
85
- * @property {string} [locale] - Optional parameter to overwrite client locale setting.
86
- * New flows supports nb_NO, fi_FI, sv_SE, en_US
87
- * @property {boolean} [oneStepLogin] - Display username and password on one screen
88
- * @property {string} [prompt] - String that specifies whether the Authorization Server prompts the
89
- * End-User for reauthentication or confirm account screen. Supported values: `select_account` or `login`
90
- * @property {string} [xDomainId] - Identifier for cross-domain tracking in Pulse
91
- * @property {string} [xEnvironmentId] - Environment for cross-domain tracking in Pulse
92
- * @property {string} [originCampaign] - Campaign identifier for tracking in Pulse
89
+ * Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;
90
+ * all other fields reuse the `LoginOptions` documentation.
93
91
  */
92
+ export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
93
+ /**
94
+ * An opaque value used by the client to maintain state between the request and callback.
95
+ * It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
96
+ */
97
+ state: string | (() => string | Promise<string>);
98
+ };
94
99
 
95
100
  /**
96
- * @typedef {object} HasSessionSuccessResponse
97
- * @property {boolean} result - Is the user connected to the merchant? (it means that the merchant
98
- * id is in the list of merchants listed of this user in the database)? Example: false
99
- * @property {string} userStatus - Example: 'notConnected' or 'connected'. Deprecated, use
100
- * `Identity.isConnected()`
101
- * @property {string} baseDomain - Example: 'localhost'
102
- * @property {string} id - Example: '58eca10fdbb9f6df72c3368f'. Obsolete
103
- * @property {number} userId - Example: 37162
104
- * @property {string} uuid - Example: 'b3b23aa7-34f2-5d02-a10e-5a3455c6ab2c'
105
- * @property {string} sp_id - Example: 'eyJjbGllbnRfaWQ...'
106
- * @property {number} expiresIn - Example: 30 * 60 * 1000 (for 30 minutes)
107
- * @property {number} serverTime - Example: 1506285759
108
- * @property {string} sig - Example: 'NCdzXaz4ZRb7...' The sig parameter is a concatenation of an
109
- * HMAC SHA-256 signature string, a dot (.) and a base64url encoded JSON object (session).
110
- * {@link http://techdocs.spid.no/sdks/js/response-signature-and-validation/}
111
- * @property {string} displayName - (Only for connected users) Example: 'batman'
112
- * @property {string} givenName - (Only for connected users) Example: 'Bruce'
113
- * @property {string} familyName - (Only for connected users) Example: 'Wayne'
114
- * @property {string} gender - (Only for connected users) Example: 'male', 'female', 'undisclosed'
115
- * @property {string} photo - (Only for connected users) Example:
116
- * 'http://www.srv.com/some/picture.jpg'
117
- * @property {boolean} tracking - (Only for connected users)
118
- * @property {boolean} clientAgreementAccepted - (Only for connected users)
119
- * @property {boolean} defaultAgreementAccepted - (Only for connected users)
120
- * @property {string} pairId
121
- * @property {string} sdrn
101
+ * Successful response returned from {@link Identity#hasSession}.
122
102
  */
103
+ export type HasSessionSuccessResponse = {
104
+ /**
105
+ * Is the user connected to the merchant? (it means that the merchant id is in the list of
106
+ * merchants listed of this user in the database)? Example: false
107
+ */
108
+ result: boolean;
109
+ /** Example: 'notConnected' or 'connected'. Deprecated, use `Identity.isConnected()` */
110
+ userStatus: string;
111
+ /** Example: 'localhost' */
112
+ baseDomain: string;
113
+ /** Example: '58eca10fdbb9f6df72c3368f'. Obsolete */
114
+ id: string;
115
+ /** Example: 37162 */
116
+ userId: number;
117
+ /** Example: 'b3b23aa7-34f2-5d02-a10e-5a3455c6ab2c' */
118
+ uuid: string;
119
+ /** Example: 'eyJjbGllbnRfaWQ...' */
120
+ sp_id: string;
121
+ /** Example: 30 * 60 * 1000 (for 30 minutes) */
122
+ expiresIn: number;
123
+ /** Example: 1506285759 */
124
+ serverTime: number;
125
+ /**
126
+ * Example: 'NCdzXaz4ZRb7...' The sig parameter is a concatenation of an HMAC SHA-256 signature
127
+ * string, a dot (.) and a base64url encoded JSON object (session).
128
+ * {@link http://techdocs.spid.no/sdks/js/response-signature-and-validation/}
129
+ */
130
+ sig: string;
131
+ /** (Only for connected users) Example: 'batman' */
132
+ displayName: string;
133
+ /** (Only for connected users) Example: 'Bruce' */
134
+ givenName: string;
135
+ /** (Only for connected users) Example: 'Wayne' */
136
+ familyName: string;
137
+ /** (Only for connected users) Example: 'male', 'female', 'undisclosed' */
138
+ gender: string;
139
+ /** (Only for connected users) Example: 'http://www.srv.com/some/picture.jpg' */
140
+ photo: string;
141
+ /** (Only for connected users) */
142
+ tracking: boolean;
143
+ /** (Only for connected users) */
144
+ clientAgreementAccepted: boolean;
145
+ /** (Only for connected users) */
146
+ defaultAgreementAccepted: boolean;
147
+ pairId: string;
148
+ sdrn: string;
149
+ };
123
150
 
124
151
  /**
125
- * Emitted when an error happens (useful for debugging)
126
- * @event Identity#error
152
+ * Failure response returned from {@link Identity#hasSession}.
127
153
  */
154
+ export type HasSessionFailureResponse = {
155
+ error: {
156
+ /** Typically an HTTP response code. Example: 401 */
157
+ code: number;
158
+ /** Example: "No session found!" */
159
+ description: string;
160
+ /** Example: "UserException" */
161
+ type: string;
162
+ };
163
+ response: {
164
+ /** Example: "localhost" */
165
+ baseDomain: string;
166
+ /** Time span in milliseconds. Example: 30 * 60 * 1000 (for 30 minutes) */
167
+ expiresIn: number;
168
+ result: boolean;
169
+ /** Server time in seconds since the Unix Epoch. Example: 1506287788 */
170
+ serverTime: number;
171
+ };
172
+ };
128
173
 
129
174
  /**
130
- * @typedef {object} HasSessionFailureResponse
131
- * @property {object} error
132
- * @property {number} error.code - Typically an HTTP response code. Example: 401
133
- * @property {string} error.description - Example: "No session found!"
134
- * @property {string} error.type - Example: "UserException"
135
- * @property {object} response
136
- * @property {string} response.baseDomain - Example: "localhost"
137
- * @property {number} response.expiresIn - Time span in milliseconds. Example: 30 * 60 * 1000 (for 30 minutes)
138
- * @property {boolean} response.result
139
- * @property {number} response.serverTime - Server time in seconds since the Unix Epoch. Example: 1506287788
175
+ * Minimal user information used by the simplified login widget flow.
140
176
  */
177
+ export type SimplifiedLoginData = {
178
+ /** Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login} */
179
+ identifier: string;
180
+ /** Human-readable user identifier */
181
+ display_text: string;
182
+ /** Client name */
183
+ client_name: string;
184
+ };
141
185
 
142
186
  /**
143
- * @typedef {object} SimplifiedLoginData
144
- * @property {string} identifier - Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login}
145
- * @property {string} display_text - Human-readable user identifier
146
- * @property {string} client_name - Client name
187
+ * Configuration options for {@link Identity#showSimplifiedLoginWidget}.
147
188
  */
189
+ export type SimplifiedLoginWidgetOptions = {
190
+ /** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */
191
+ encoding: string;
192
+ /**
193
+ * expected locale of simplified login widget. Should be provided in a short format like 'nb',
194
+ * 'sv'. If not set, a value from the env variable is used.
195
+ */
196
+ locale?: 'nb' | 'sv' | 'fi' | 'da' | 'en';
197
+ };
148
198
 
149
199
  /**
150
- * @typedef {object} SimplifiedLoginWidgetOptions
151
- * @property {string} encoding - expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15
200
+ * Emitted when an error happens (useful for debugging)
201
+ * @event Identity#error
152
202
  */
153
203
 
154
204
  const HAS_SESSION_CACHE_KEY = 'hasSession-cache';
@@ -156,7 +206,7 @@ const SESSION_CALL_BLOCKED_CACHE_KEY = 'sessionCallBlocked-cache';
156
206
  const SESSION_CALL_BLOCKED_TTL = 1000 * 60 * 5;
157
207
 
158
208
  const TAB_ID_KEY = 'tab-id-cache';
159
- const TAB_ID = Math.floor(Math.random() * 100000)
209
+ const TAB_ID = Math.floor(Math.random() * 100000);
160
210
  const TAB_ID_TTL = 1000 * 60 * 60 * 24 * 30;
161
211
 
162
212
  const globalWindow = () => window;
@@ -164,17 +214,41 @@ const globalWindow = () => window;
164
214
  /**
165
215
  * Provides Identity functionalty to a web page
166
216
  */
167
- export class Identity extends EventEmitter {
217
+ export class Identity extends TinyEmitter {
218
+ _sessionInitiatedSent: boolean;
219
+ window: any;
220
+ clientId: string;
221
+ sessionStorageCache: any;
222
+ localStorageCache: any;
223
+ redirectUri: string;
224
+ env: string;
225
+ log?: Function;
226
+ callbackBeforeRedirect: Function;
227
+ _sessionDomain: string;
228
+ _enableSessionCaching: boolean;
229
+ _session: any;
230
+ _spid!: RESTClient;
231
+ _oauthService!: RESTClient;
232
+ _bffService!: RESTClient;
233
+ _sessionService!: RESTClient;
234
+ _globalSessionService!: RESTClient;
235
+ _usedSessionServiceGetSessionEndpoint: any;
236
+ _hasSessionInProgress?: boolean | Promise<any>;
237
+ popup?: Window | null;
238
+ setVarnishCookie?: boolean;
239
+ varnishExpiresIn?: number;
240
+ varnishCookieDomain?: string;
241
+
168
242
  /**
169
- * @param {object} options
170
- * @param {string} options.clientId - Example: "1234567890abcdef12345678"
171
- * @param {string} options.sessionDomain - Example: "https://id.site.com"
172
- * @param {string} options.redirectUri - Example: "https://site.com"
173
- * @param {string} [options.env=PRE] - Schibsted account environment: `PRE`, `PRO`, `PRO_NO`, `PRO_FI` or `PRO_DK`
174
- * @param {function} [options.log] - A function that receives debug log information. If not set,
243
+ * @param options
244
+ * @param options.clientId - Example: "1234567890abcdef12345678"
245
+ * @param options.sessionDomain - Example: "https://id.site.com"
246
+ * @param options.redirectUri - Example: "https://site.com"
247
+ * @param options.env - Schibsted account environment: `PRE` (default), `PRO`, `PRO_NO`, `PRO_FI` or `PRO_DK`
248
+ * @param options.log - A function that receives debug log information. If not set,
175
249
  * no logging will be done
176
- * @param {object} [options.window] - window object
177
- * @param {function} [options.callbackBeforeRedirect] - callback triggered before session refresh redirect happen
250
+ * @param options.window - window object
251
+ * @param options.callbackBeforeRedirect - callback triggered before session refresh redirect happen
178
252
  * @throws {SDKError} - If any of options are invalid
179
253
  */
180
254
  constructor({
@@ -184,13 +258,24 @@ export class Identity extends EventEmitter {
184
258
  env = 'PRE',
185
259
  log,
186
260
  window = globalWindow(),
187
- callbackBeforeRedirect = ()=>{}
261
+ callbackBeforeRedirect = () => {},
262
+ }: {
263
+ clientId: string;
264
+ sessionDomain: string;
265
+ redirectUri: string;
266
+ env?: string;
267
+ log?: Function;
268
+ window?: Window;
269
+ callbackBeforeRedirect?: Function;
188
270
  }) {
189
271
  super();
190
272
  assert(isNonEmptyString(clientId), 'clientId parameter is required');
191
273
  assert(isObject(window), 'The reference to window is missing');
192
274
  assert(!redirectUri || isUrl(redirectUri), 'redirectUri parameter is invalid');
193
- assert(sessionDomain && isUrl(sessionDomain), 'sessionDomain parameter is not a valid URL');
275
+ assert(
276
+ isNonEmptyString(sessionDomain) && isUrl(sessionDomain),
277
+ 'sessionDomain parameter is not a valid URL',
278
+ );
194
279
 
195
280
  spidTalk.emulate(window);
196
281
  this._sessionInitiatedSent = false;
@@ -211,7 +296,10 @@ export class Identity extends EventEmitter {
211
296
  this._session = {};
212
297
 
213
298
  this._setSessionServiceUrl(sessionDomain);
214
- this._usedSessionServiceGetSessionEndpoint = this._sessionService.url.pathname && this._sessionService.url.pathname.length <= 1 ? 'v2/session' : 'session';
299
+ this._usedSessionServiceGetSessionEndpoint =
300
+ this._sessionService.url.pathname && this._sessionService.url.pathname.length <= 1
301
+ ? 'v2/session'
302
+ : 'session';
215
303
 
216
304
  this._setSpidServerUrl(env);
217
305
  this._setBffServerUrl(env);
@@ -220,16 +308,14 @@ export class Identity extends EventEmitter {
220
308
 
221
309
  this._unblockSessionCall();
222
310
 
223
- registerGlobal(window, 'Identity', this);
224
-
311
+ registerAndDispatchInGlobal(window, 'schIdentity', this);
225
312
  }
226
313
 
227
314
  /**
228
315
  * Read tabId from session storage
229
- * @returns {number}
230
316
  * @private
231
317
  */
232
- _getTabId() {
318
+ _getTabId(): number | undefined {
233
319
  if (this._enableSessionCaching) {
234
320
  const tabId = this.sessionStorageCache.get(TAB_ID_KEY);
235
321
  if (!tabId) {
@@ -245,9 +331,8 @@ export class Identity extends EventEmitter {
245
331
  * Checks if getting session is blocked
246
332
  * @private
247
333
  *
248
- * @returns {boolean|void}
249
334
  */
250
- _isSessionCallBlocked(){
335
+ _isSessionCallBlocked(): boolean | void {
251
336
  return this.localStorageCache.get(SESSION_CALL_BLOCKED_CACHE_KEY);
252
337
  }
253
338
 
@@ -255,15 +340,14 @@ export class Identity extends EventEmitter {
255
340
  * Block calls to get session
256
341
  * @private
257
342
  *
258
- * @returns {void}
259
343
  */
260
- _blockSessionCall(){
344
+ _blockSessionCall(): void {
261
345
  const SESSION_CALL_BLOCKED = true;
262
346
 
263
347
  this.localStorageCache.set(
264
348
  SESSION_CALL_BLOCKED_CACHE_KEY,
265
349
  SESSION_CALL_BLOCKED,
266
- SESSION_CALL_BLOCKED_TTL
350
+ SESSION_CALL_BLOCKED_TTL,
267
351
  );
268
352
  }
269
353
 
@@ -271,19 +355,17 @@ export class Identity extends EventEmitter {
271
355
  * Unblocks calls to get session
272
356
  * @private
273
357
  *
274
- * @returns {void}
275
358
  */
276
- _unblockSessionCall(){
359
+ _unblockSessionCall(): void {
277
360
  this.localStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);
278
361
  }
279
362
 
280
363
  /**
281
364
  * Set SPiD server URL
282
365
  * @private
283
- * @param {string} url - real URL or 'PRE' style key
284
- * @returns {void}
366
+ * @param url - real URL or 'PRE' style key
285
367
  */
286
- _setSpidServerUrl(url) {
368
+ _setSpidServerUrl(url: string): void {
287
369
  assert(isStr(url), `url parameter is invalid: ${url}`);
288
370
  this._spid = new RESTClient({
289
371
  serverUrl: urlMapper(url, ENDPOINTS.SPiD),
@@ -295,10 +377,9 @@ export class Identity extends EventEmitter {
295
377
  /**
296
378
  * Set OAuth server URL
297
379
  * @private
298
- * @param {string} url - real URL or 'PRE' style key
299
- * @returns {void}
380
+ * @param url - real URL or 'PRE' style key
300
381
  */
301
- _setOauthServerUrl(url) {
382
+ _setOauthServerUrl(url: string): void {
302
383
  assert(isStr(url), `url parameter is invalid: ${url}`);
303
384
  this._oauthService = new RESTClient({
304
385
  serverUrl: urlMapper(url, ENDPOINTS.SPiD),
@@ -310,10 +391,9 @@ export class Identity extends EventEmitter {
310
391
  /**
311
392
  * Set BFF server URL
312
393
  * @private
313
- * @param {string} url - real URL or 'PRE' style key
314
- * @returns {void}
394
+ * @param url - real URL or 'PRE' style key
315
395
  */
316
- _setBffServerUrl(url) {
396
+ _setBffServerUrl(url: string): void {
317
397
  assert(isStr(url), `url parameter is invalid: ${url}`);
318
398
  this._bffService = new RESTClient({
319
399
  serverUrl: urlMapper(url, ENDPOINTS.BFF),
@@ -325,12 +405,11 @@ export class Identity extends EventEmitter {
325
405
  /**
326
406
  * Set site-specific session-service domain
327
407
  * @private
328
- * @param {string} domain - real URL — (**not** 'PRE' style env key)
329
- * @returns {void}
408
+ * @param domain - real URL — (**not** 'PRE' style env key)
330
409
  */
331
- _setSessionServiceUrl(domain) {
410
+ _setSessionServiceUrl(domain: string): void {
332
411
  assert(isStr(domain), `domain parameter is invalid: ${domain}`);
333
- const client_sdrn = `sdrn:${NAMESPACE[this.env]}:client:${this.clientId}`;
412
+ const client_sdrn = `sdrn:${NAMESPACE[this.env as keyof typeof NAMESPACE]}:client:${this.clientId}`;
334
413
  this._sessionService = new RESTClient({
335
414
  serverUrl: domain,
336
415
  log: this.log,
@@ -341,12 +420,11 @@ export class Identity extends EventEmitter {
341
420
  /**
342
421
  * Set global session-service server URL
343
422
  * @private
344
- * @param {string} url - real URL or 'PRE' style key
345
- * @returns {void}
423
+ * @param url - real URL or 'PRE' style key
346
424
  */
347
- _setGlobalSessionServiceUrl(url) {
425
+ _setGlobalSessionServiceUrl(url: string): void {
348
426
  assert(isStr(url), `url parameter is invalid: ${url}`);
349
- const client_sdrn = `sdrn:${NAMESPACE[this.env]}:client:${this.clientId}`;
427
+ const client_sdrn = `sdrn:${NAMESPACE[this.env as keyof typeof NAMESPACE]}:client:${this.clientId}`;
350
428
  this._globalSessionService = new RESTClient({
351
429
  serverUrl: urlMapper(url, ENDPOINTS.SESSION_SERVICE),
352
430
  log: this.log,
@@ -357,11 +435,10 @@ export class Identity extends EventEmitter {
357
435
  /**
358
436
  * Emits the relevant events based on the previous and new reply from hassession
359
437
  * @private
360
- * @param {object} previous
361
- * @param {object} current
362
- * @returns {void}
438
+ * @param previous
439
+ * @param current
363
440
  */
364
- _emitSessionEvent(previous, current) {
441
+ _emitSessionEvent(previous: any, current: any): void {
365
442
  /**
366
443
  * Emitted when the user is logged in (This happens as a result of calling
367
444
  * {@link Identity#hasSession}, so it is also emitted if the user was previously logged in)
@@ -423,9 +500,8 @@ export class Identity extends EventEmitter {
423
500
  /**
424
501
  * Close this.popup if it exists and is open
425
502
  * @private
426
- * @returns {void}
427
503
  */
428
- _closePopup() {
504
+ _closePopup(): void {
429
505
  if (this.popup) {
430
506
  if (!this.popup.closed) {
431
507
  this.popup.close();
@@ -437,21 +513,19 @@ export class Identity extends EventEmitter {
437
513
  /**
438
514
  * Set the Varnish cookie (`SP_ID`) when hasSession() is called. Note that most browsers require
439
515
  * that you are on a "real domain" for this to work — so, **not** `localhost`
440
- * @param {object} [options]
441
- * @param {number} [options.expiresIn] Override this to set number of seconds before the varnish
516
+ * @param options
517
+ * @param options.expiresIn Override this to set number of seconds before the varnish
442
518
  * cookie expires. The default is to use the same time that hasSession responses are cached for
443
- * @param {string} [options.domain] Override cookie domain. E.g. «vg.no» instead of «www.vg.no»
444
- * @returns {void}
519
+ * @param options.domain Override cookie domain. E.g. «vg.no» instead of «www.vg.no»
445
520
  */
446
- enableVarnishCookie(options) {
521
+ enableVarnishCookie(options?: { expiresIn?: number; domain?: string }): void {
447
522
  let expiresIn = 0;
448
- let domain;
523
+ let domain: string | undefined;
449
524
  if (Number.isInteger(options)) {
450
- expiresIn = options;
451
- }
452
- else if (typeof options == 'object') {
453
- expiresIn = options.expiresIn || expiresIn;
454
- domain = options.domain || domain;
525
+ expiresIn = options as any;
526
+ } else if (typeof options == 'object') {
527
+ expiresIn = (options as any).expiresIn || expiresIn;
528
+ domain = (options as any).domain || domain;
455
529
  }
456
530
 
457
531
  assert(Number.isInteger(expiresIn), `'expiresIn' must be an integer`);
@@ -464,25 +538,26 @@ export class Identity extends EventEmitter {
464
538
  /**
465
539
  * Set the Varnish cookie if configured
466
540
  * @private
467
- * @param {HasSessionSuccessResponse} sessionData
468
- * @returns {void}
541
+ * @param sessionData
469
542
  */
470
- _maybeSetVarnishCookie(sessionData) {
543
+ _maybeSetVarnishCookie(sessionData: HasSessionSuccessResponse): void {
471
544
  if (!this.setVarnishCookie) {
472
545
  return;
473
546
  }
474
547
  const date = new Date();
475
- const validExpires = this.varnishExpiresIn
476
- || typeof sessionData.expiresIn === 'number' && sessionData.expiresIn > 0;
548
+ const validExpires =
549
+ this.varnishExpiresIn ||
550
+ (typeof sessionData.expiresIn === 'number' && sessionData.expiresIn > 0);
477
551
  if (validExpires) {
478
552
  const expires = this.varnishExpiresIn || sessionData.expiresIn;
479
- date.setTime(date.getTime() + (expires * 1000));
553
+ date.setTime(date.getTime() + expires * 1000);
480
554
  } else {
481
555
  date.setTime(0);
482
556
  }
483
557
 
484
558
  // If the domain is missing or of the wrong type, we'll use document.domain
485
- let domain = this.varnishCookieDomain ||
559
+ const domain =
560
+ this.varnishCookieDomain ||
486
561
  (typeof sessionData.baseDomain === 'string'
487
562
  ? sessionData.baseDomain
488
563
  : document.domain) ||
@@ -492,7 +567,7 @@ export class Identity extends EventEmitter {
492
567
  `SP_ID=${sessionData.sp_id}`,
493
568
  `expires=${date.toUTCString()}`,
494
569
  `path=/`,
495
- `domain=.${domain}`
570
+ `domain=.${domain}`,
496
571
  ].join('; ');
497
572
  document.cookie = cookie;
498
573
  }
@@ -500,9 +575,8 @@ export class Identity extends EventEmitter {
500
575
  /**
501
576
  * Clear the Varnish cookie if configured
502
577
  * @private
503
- * @returns {void}
504
578
  */
505
- _maybeClearVarnishCookie() {
579
+ _maybeClearVarnishCookie(): void {
506
580
  if (this.setVarnishCookie) {
507
581
  this._clearVarnishCookie();
508
582
  }
@@ -511,16 +585,14 @@ export class Identity extends EventEmitter {
511
585
  /**
512
586
  * Clear the Varnish cookie
513
587
  * @private
514
- * @returns {void}
515
588
  */
516
- _clearVarnishCookie() {
517
- const baseDomain = this._session && typeof this._session.baseDomain === 'string'
518
- ? this._session.baseDomain
519
- : document.domain;
589
+ _clearVarnishCookie(): void {
590
+ const baseDomain =
591
+ this._session && typeof this._session.baseDomain === 'string'
592
+ ? this._session.baseDomain
593
+ : document.domain;
520
594
 
521
- let domain = this.varnishCookieDomain ||
522
- baseDomain ||
523
- '';
595
+ const domain = this.varnishCookieDomain || baseDomain || '';
524
596
 
525
597
  document.cookie = `SP_ID=nothing; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
526
598
  }
@@ -528,9 +600,8 @@ export class Identity extends EventEmitter {
528
600
  /**
529
601
  * Log used settings and version
530
602
  * @throws {SDKError} - If log method is not provided
531
- * @return {void}
532
603
  */
533
- logSettings() {
604
+ logSettings(): void {
534
605
  if (!this.log && !window.console) {
535
606
  throw new SDKError('You have to provide log method in constructor');
536
607
  }
@@ -542,15 +613,15 @@ export class Identity extends EventEmitter {
542
613
  redirectUri: this.redirectUri,
543
614
  env: this.env,
544
615
  sessionDomain: this._sessionDomain,
545
- sdkVersion: version
546
- }
616
+ sdkVersion: version,
617
+ };
547
618
 
548
619
  log(`Schibsted account SDK for browsers settings: \n${JSON.stringify(settings, null, 2)}`);
549
620
  }
550
621
 
551
622
  /**
552
623
  * @summary Queries the hassession endpoint and returns information about the status of the user
553
- * @description When we send a request to this endpoint, cookies sent along with the request
624
+ * @remarks When we send a request to this endpoint, cookies sent along with the request
554
625
  * determines the status of the user.
555
626
  * @throws {SDKError} - If the call to the hasSession service fails in any way (this will happen
556
627
  * if, say, the user is not logged in)
@@ -562,19 +633,20 @@ export class Identity extends EventEmitter {
562
633
  * @fires Identity#sessionInit
563
634
  * @fires Identity#statusChange
564
635
  * @fires Identity#error
565
- * @return {Promise<HasSessionSuccessResponse|HasSessionFailureResponse>}
566
636
  */
567
- hasSession() {
568
- const isSessionCallBlocked = this._isSessionCallBlocked()
637
+ hasSession(): Promise<HasSessionSuccessResponse | HasSessionFailureResponse> {
638
+ const isSessionCallBlocked = this._isSessionCallBlocked();
569
639
  if (isSessionCallBlocked) {
570
640
  return this._session;
571
641
  }
572
642
 
573
643
  if (this._hasSessionInProgress) {
574
- return this._hasSessionInProgress;
644
+ return this._hasSessionInProgress as Promise<
645
+ HasSessionSuccessResponse | HasSessionFailureResponse
646
+ >;
575
647
  }
576
648
 
577
- const _postProcess = (sessionData) => {
649
+ const _postProcess = (sessionData: any) => {
578
650
  if (sessionData.error) {
579
651
  throw new SDKError('HasSession failed', sessionData.error);
580
652
  }
@@ -584,40 +656,47 @@ export class Identity extends EventEmitter {
584
656
  return sessionData;
585
657
  };
586
658
 
587
- const _checkRedirectionNeed = (sessionData={})=>{
659
+ const _checkRedirectionNeed = (sessionData: any = {}) => {
588
660
  const sessionDataKeys = Object.keys(sessionData);
589
661
 
590
- return sessionDataKeys.length === 1 &&
591
- sessionDataKeys[0] === 'redirectURL';
592
- }
662
+ return sessionDataKeys.length === 1 && sessionDataKeys[0] === 'redirectURL';
663
+ };
593
664
 
594
665
  const _getSession = async () => {
595
666
  if (this._enableSessionCaching) {
596
667
  // Try to resolve from cache (it has a TTL)
597
- let cachedSession = this.sessionStorageCache.get(HAS_SESSION_CACHE_KEY);
668
+ const cachedSession = this.sessionStorageCache.get(HAS_SESSION_CACHE_KEY);
598
669
  if (cachedSession) {
599
670
  return _postProcess(cachedSession);
600
671
  }
601
672
  }
602
673
  let sessionData = null;
603
674
  try {
604
- sessionData = await this._sessionService.get(this._usedSessionServiceGetSessionEndpoint, {tabId: this._getTabId()});
605
- } catch (err) {
675
+ sessionData = await this._sessionService.get(
676
+ this._usedSessionServiceGetSessionEndpoint,
677
+ { tabId: this._getTabId() },
678
+ );
679
+ } catch (err: any) {
606
680
  if (err && err.code === 400 && this._enableSessionCaching) {
607
681
  const expiresIn = 1000 * (err.expiresIn || 300);
608
682
  this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, expiresIn);
683
+ } else if (err && err.code >= 500 && err.code < 600 && this._enableSessionCaching) {
684
+ // Temporary fix: 30 seconds cache to limit number of calls when service is unavailable
685
+ this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, 30 * 1000);
609
686
  }
610
687
  throw err;
611
688
  }
612
689
 
613
- if (sessionData){
690
+ if (sessionData) {
614
691
  // for expiring session and safari browser do full page redirect to gain new session
615
- if(_checkRedirectionNeed(sessionData)){
692
+ if (_checkRedirectionNeed(sessionData)) {
616
693
  this._blockSessionCall();
617
694
 
618
695
  await this.callbackBeforeRedirect();
619
696
 
620
- return this._sessionService.makeUrl(sessionData.redirectURL, {tabId: this._getTabId()});
697
+ return this._sessionService.makeUrl(sessionData.redirectURL, {
698
+ tabId: this._getTabId(),
699
+ });
621
700
  }
622
701
 
623
702
  if (this._enableSessionCaching) {
@@ -628,35 +707,35 @@ export class Identity extends EventEmitter {
628
707
 
629
708
  return _postProcess(sessionData);
630
709
  };
631
- this._hasSessionInProgress = _getSession()
632
- .then(
633
- sessionData => {
634
- this._hasSessionInProgress = false;
635
-
636
- if (isUrl(sessionData)) {
637
- return this.window.location.href = sessionData;
638
- }
710
+ this._hasSessionInProgress = _getSession().then(
711
+ (sessionData) => {
712
+ this._hasSessionInProgress = false;
639
713
 
714
+ if (isUrl(sessionData)) {
715
+ this.window.location.href = sessionData;
640
716
  return sessionData;
641
- },
642
- err => {
643
- this.emit('error', err);
644
- this._hasSessionInProgress = false;
645
- throw new SDKError('HasSession failed', err);
646
717
  }
647
- );
648
718
 
649
- return this._hasSessionInProgress;
719
+ return sessionData;
720
+ },
721
+ (err) => {
722
+ this.emit('error', err);
723
+ this._hasSessionInProgress = false;
724
+ throw new SDKError('HasSession failed', err);
725
+ },
726
+ );
727
+
728
+ return this._hasSessionInProgress as Promise<
729
+ HasSessionSuccessResponse | HasSessionFailureResponse
730
+ >;
650
731
  }
651
732
 
652
733
  /**
653
- * @async
654
734
  * @summary Allows the client app to check if the user is logged in to Schibsted account
655
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
735
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
656
736
  * effect that it might perform an auto-login on the user
657
- * @return {Promise<boolean>}
658
737
  */
659
- async isLoggedIn() {
738
+ async isLoggedIn(): Promise<boolean> {
660
739
  try {
661
740
  const data = await this.hasSession();
662
741
  return 'result' in data;
@@ -667,25 +746,22 @@ export class Identity extends EventEmitter {
667
746
 
668
747
  /**
669
748
  * Removes the cached user session.
670
- * @returns {void}
671
749
  */
672
- clearCachedUserSession() {
750
+ clearCachedUserSession(): void {
673
751
  this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
674
752
  }
675
753
 
676
754
  /**
677
- * @async
678
755
  * @summary Allows the caller to check if the current user is connected to the client_id in
679
756
  * Schibsted account. Being connected means that the user has agreed for their account to be
680
757
  * used by your web app and have accepted the required terms
681
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
758
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
682
759
  * effect that it might perform an auto-login on the user
683
760
  * @summary Check if the user is connected to the client_id
684
- * @return {Promise<boolean>}
685
761
  */
686
- async isConnected() {
762
+ async isConnected(): Promise<boolean> {
687
763
  try {
688
- const data = await this.hasSession();
764
+ const data = (await this.hasSession()) as any;
689
765
  // if data is not an object, the promise will fail.
690
766
  // if the result is present, it's boolean. But if it's not, it should be assumed false.
691
767
  return !!data.result;
@@ -695,16 +771,14 @@ export class Identity extends EventEmitter {
695
771
  }
696
772
 
697
773
  /**
698
- * @async
699
774
  * @summary Returns information about the user
700
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
775
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
701
776
  * effect that it might perform an auto-login on the user
702
777
  * @throws {SDKError} If the user isn't connected to the merchant
703
778
  * @throws {SDKError} If we couldn't get the user
704
- * @return {Promise<HasSessionSuccessResponse>}
705
779
  */
706
- async getUser() {
707
- const user = await this.hasSession();
780
+ async getUser(): Promise<HasSessionSuccessResponse> {
781
+ const user = (await this.hasSession()) as any;
708
782
  if (!user.result) {
709
783
  throw new SDKError('The user is not connected to this merchant');
710
784
  }
@@ -712,7 +786,6 @@ export class Identity extends EventEmitter {
712
786
  }
713
787
 
714
788
  /**
715
- * @async
716
789
  * @summary
717
790
  * In Schibsted account, there are multiple ways of identifying a user; the `userId`,
718
791
  * `uuid` and `externalId` used for identifying a user-merchant pair (see {@link Identity#getExternalId}).
@@ -721,13 +794,13 @@ export class Identity extends EventEmitter {
721
794
  * duplicates. The `userId` was introduced early, so many sites still need to use them for
722
795
  * legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of
723
796
  * Schibsted components depending on the numeric `userId` — it would be a good identifier to use
724
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
797
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
725
798
  * effect that it might perform an auto-login on the user
726
799
  * @throws {SDKError} If the user isn't connected to the merchant
727
- * @return {Promise<string>} The `userId` field (not to be confused with the `uuid`)
800
+ * @return The `userId` field (not to be confused with the `uuid`)
728
801
  */
729
- async getUserId() {
730
- const user = await this.hasSession();
802
+ async getUserId(): Promise<string> {
803
+ const user = (await this.hasSession()) as any;
731
804
  if (user.userId && user.result) {
732
805
  return user.userId;
733
806
  }
@@ -735,7 +808,6 @@ export class Identity extends EventEmitter {
735
808
  }
736
809
 
737
810
  /**
738
- * @async
739
811
  * @function
740
812
  * @summary
741
813
  * Retrieves the external identifier (`externalId`) for the authenticated user.
@@ -748,58 +820,55 @@ export class Identity extends EventEmitter {
748
820
  * meaning the same user's ID will differ between merchants.
749
821
  * Additionally, this identifier is bound to the external party provided as argument.
750
822
  *
751
- * @param {string} externalParty
752
- * @param {string|null} optionalSuffix
753
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
823
+ * @param externalParty
824
+ * @param optionalSuffix
825
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
754
826
  * effect that it might perform an auto-login on the user
755
827
  * @throws {SDKError} If the `pairId` is missing in user session.
756
828
  * @throws {SDKError} If the `externalParty` is not defined
757
- * @return {Promise<string>} The merchant- and 3rd-party-specific `externalId`
829
+ * @return The merchant- and 3rd-party-specific `externalId`
758
830
  */
759
- async getExternalId(externalParty, optionalSuffix = "") {
760
- const { pairId } = await this.hasSession();
831
+ async getExternalId(externalParty: string, optionalSuffix: string = ''): Promise<string> {
832
+ const { pairId } = (await this.hasSession()) as any;
761
833
 
762
- if (!pairId)
763
- throw new SDKError('pairId missing in user session!');
834
+ if (!pairId) throw new SDKError('pairId missing in user session!');
764
835
 
765
- if(!externalParty || externalParty.length === 0) {
836
+ if (!externalParty || externalParty.length === 0) {
766
837
  throw new SDKError('externalParty cannot be empty');
767
838
  }
768
- const _toHexDigest = (hashBuffer) =>{
839
+ const _toHexDigest = (hashBuffer: any) => {
769
840
  // convert buffer to byte array
770
841
  const hashArray = Array.from(new Uint8Array(hashBuffer));
771
842
  // convert bytes to hex string
772
- return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
773
- }
843
+ return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
844
+ };
774
845
 
775
- const _getSha256Digest = (data) => {
846
+ const _getSha256Digest = (data: any) => {
776
847
  return crypto.subtle.digest('SHA-256', data);
777
- }
848
+ };
778
849
 
779
- const _hashMessage = async (message) => {
850
+ const _hashMessage = async (message: any) => {
780
851
  const msgUint8 = new TextEncoder().encode(message);
781
- return _getSha256Digest(msgUint8).then( (it) => _toHexDigest(it));
782
- }
852
+ return _getSha256Digest(msgUint8).then((it: any) => _toHexDigest(it));
853
+ };
783
854
 
784
- const _constructMessage = (pairId, externalParty, optionalSuffix) => {
855
+ const _constructMessage = (pairId: any, externalParty: any, optionalSuffix: any) => {
785
856
  return optionalSuffix
786
857
  ? `${pairId}:${externalParty}:${optionalSuffix}`
787
858
  : `${pairId}:${externalParty}`;
788
- }
859
+ };
789
860
 
790
- return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix))
861
+ return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix));
791
862
  }
792
863
 
793
864
  /**
794
- * @async
795
865
  * @summary Enables brands to programmatically get the current the SDRN based on the user's session.
796
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
866
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
797
867
  * effect that it might perform an auto-login on the user
798
868
  * @throws {SDKError} If the SDRN is missing in user session object.
799
- * @returns {Promise<string>}
800
869
  */
801
- async getUserSDRN() {
802
- const { sdrn } = await this.hasSession();
870
+ async getUserSDRN(): Promise<string> {
871
+ const { sdrn } = (await this.hasSession()) as any;
803
872
  if (sdrn) {
804
873
  return sdrn;
805
874
  }
@@ -807,20 +876,19 @@ export class Identity extends EventEmitter {
807
876
  }
808
877
 
809
878
  /**
810
- * @async
811
879
  * @summary In Schibsted account, there are two ways of identifying a user; the `userId` and the
812
880
  * `uuid`. There are reasons for them both existing. The `userId` is a numeric identifier, but
813
881
  * since Schibsted account is deployed separately in Norway and Sweden, there are a lot of
814
882
  * duplicates. The `userId` was introduced early, so many sites still need to use them for
815
883
  * legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of
816
884
  * Schibsted components depending on the numeric `userId` — it would be a good identifier to use
817
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
885
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
818
886
  * effect that it might perform an auto-login on the user
819
887
  * @throws {SDKError} If the user isn't connected to the merchant
820
- * @return {Promise<string>} The `uuid` field (not to be confused with the `userId`)
888
+ * @return The `uuid` field (not to be confused with the `userId`)
821
889
  */
822
- async getUserUuid() {
823
- const user = await this.hasSession();
890
+ async getUserUuid(): Promise<string> {
891
+ const user = (await this.hasSession()) as any;
824
892
  if (user.uuid && user.result) {
825
893
  return user.uuid;
826
894
  }
@@ -828,16 +896,14 @@ export class Identity extends EventEmitter {
828
896
  }
829
897
 
830
898
  /**
831
- * @async
832
899
  * @summary Get basic information about any user currently logged-in to their Schibsted account
833
900
  * in this browser. Can be used to provide context in a continue-as prompt.
834
- * @description This function relies on the global Schibsted account user session cookie, which
901
+ * @remarks This function relies on the global Schibsted account user session cookie, which
835
902
  * is a third-party cookie and hence might be blocked by the browser (for example due to ITP in
836
903
  * Safari). So there's no guarantee any data is returned, even though a user is logged-in in
837
904
  * the current browser.
838
- * @return {Promise<SimplifiedLoginData|null>}
839
905
  */
840
- async getUserContextData() {
906
+ async getUserContextData(): Promise<SimplifiedLoginData | null> {
841
907
  try {
842
908
  return await this._globalSessionService.get('user-context');
843
909
  } catch (_) {
@@ -852,23 +918,23 @@ export class Identity extends EventEmitter {
852
918
  * @summary Perform a login, either using a full-page redirect or a popup
853
919
  * @see https://tools.ietf.org/html/rfc6749#section-4.1.1
854
920
  *
855
- * @param {LoginOptions} options
856
- * @param {string} options.state
857
- * @param {string} [options.acrValues]
858
- * @param {string} [options.scope=openid]
859
- * @param {string} [options.redirectUri]
860
- * @param {boolean} [options.preferPopup=false]
861
- * @param {string} [options.loginHint]
862
- * @param {string} [options.tag]
863
- * @param {string} [options.teaser]
864
- * @param {number|string} [options.maxAge]
865
- * @param {string} [options.locale]
866
- * @param {boolean} [options.oneStepLogin=false]
867
- * @param {string} [options.prompt=select_account]
868
- * @param {string} [options.xDomainId]
869
- * @param {string} [options.xEnvironmentId]
870
- * @param {string} [options.originCampaign]
871
- * @return {Window|null} - Reference to popup window if created (or `null` otherwise)
921
+ * @param options
922
+ * @param options.state
923
+ * @param options.acrValues
924
+ * @param options.scope
925
+ * @param options.redirectUri
926
+ * @param options.preferPopup
927
+ * @param options.loginHint
928
+ * @param options.tag
929
+ * @param options.teaser
930
+ * @param options.maxAge
931
+ * @param options.locale
932
+ * @param options.oneStepLogin
933
+ * @param options.prompt
934
+ * @param options.xDomainId
935
+ * @param options.xEnvironmentId
936
+ * @param options.originCampaign
937
+ * @return - Reference to popup window if created (or `null` otherwise)
872
938
  */
873
939
  login({
874
940
  state,
@@ -885,8 +951,8 @@ export class Identity extends EventEmitter {
885
951
  prompt = 'select_account',
886
952
  xDomainId = '',
887
953
  xEnvironmentId = '',
888
- originCampaign = ''
889
- }) {
954
+ originCampaign = '',
955
+ }: LoginOptions): Window | null {
890
956
  this._closePopup();
891
957
  this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
892
958
  const url = this.loginUrl({
@@ -903,12 +969,14 @@ export class Identity extends EventEmitter {
903
969
  prompt,
904
970
  xDomainId,
905
971
  xEnvironmentId,
906
- originCampaign
972
+ originCampaign,
907
973
  });
908
974
 
909
975
  if (preferPopup) {
910
- this.popup =
911
- popup.open(this.window, url, 'Schibsted account', { width: 360, height: 570 });
976
+ this.popup = popup.open(this.window, url, 'Schibsted account', {
977
+ width: 360,
978
+ height: 570,
979
+ });
912
980
  if (this.popup) {
913
981
  return this.popup;
914
982
  }
@@ -918,15 +986,14 @@ export class Identity extends EventEmitter {
918
986
  }
919
987
 
920
988
  /**
921
- * @async
922
989
  * @summary Retrieve the sp_id (Varnish ID)
923
- * @description This function calls {@link Identity#hasSession} internally and thus has the side
990
+ * @remarks This function calls {@link Identity#hasSession} internally and thus has the side
924
991
  * effect that it might perform an auto-login on the user
925
- * @return {Promise<string|null>} - The sp_id string or null (if the server didn't return it)
992
+ * @return - The sp_id string or null (if the server didn't return it)
926
993
  */
927
- async getSpId() {
994
+ async getSpId(): Promise<string | null> {
928
995
  try {
929
- const user = await this.hasSession();
996
+ const user = (await this.hasSession()) as any;
930
997
  return user.sp_id || null;
931
998
  } catch (_) {
932
999
  return null;
@@ -935,11 +1002,10 @@ export class Identity extends EventEmitter {
935
1002
 
936
1003
  /**
937
1004
  * @summary Logs the user out from the Identity platform
938
- * @param {string} redirectUri - Where to redirect the browser after logging out of Schibsted
1005
+ * @param redirectUri - Where to redirect the browser after logging out of Schibsted
939
1006
  * account
940
- * @return {void}
941
1007
  */
942
- logout(redirectUri = this.redirectUri) {
1008
+ logout(redirectUri: string = this.redirectUri): void {
943
1009
  this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
944
1010
  this._maybeClearVarnishCookie();
945
1011
  this.emit('logout');
@@ -948,39 +1014,42 @@ export class Identity extends EventEmitter {
948
1014
 
949
1015
  /**
950
1016
  * Generates the link to the new login page that'll be used in the popup or redirect flow
951
- * @param {LoginOptions} options
952
- * @param {string} options.state
953
- * @param {string} [options.acrValues]
954
- * @param {string} [options.scope=openid]
955
- * @param {string} [options.redirectUri]
956
- * @param {string} [options.loginHint]
957
- * @param {string} [options.tag]
958
- * @param {string} [options.teaser]
959
- * @param {number|string} [options.maxAge]
960
- * @param {string} [options.locale]
961
- * @param {boolean} [options.oneStepLogin=false]
962
- * @param {string} [options.prompt=select_account]
963
- * @param {string} [options.xDomainId]
964
- * @param {string} [options.xEnvironmentId]
965
- * @param {string} [options.originCampaign]
966
- * @return {string} - The url
1017
+ * @param options
1018
+ * @param options.state
1019
+ * @param options.acrValues
1020
+ * @param options.scope
1021
+ * @param options.redirectUri
1022
+ * @param options.loginHint
1023
+ * @param options.tag
1024
+ * @param options.teaser
1025
+ * @param options.maxAge
1026
+ * @param options.locale
1027
+ * @param options.oneStepLogin
1028
+ * @param options.prompt
1029
+ * @param options.xDomainId
1030
+ * @param options.xEnvironmentId
1031
+ * @param options.originCampaign
1032
+ * @return - The url
967
1033
  */
968
- loginUrl({
969
- state,
970
- acrValues = '',
971
- scope = 'openid',
972
- redirectUri = this.redirectUri,
973
- loginHint = '',
974
- tag = '',
975
- teaser = '',
976
- maxAge = '',
977
- locale = '',
978
- oneStepLogin = false,
979
- prompt = 'select_account',
980
- xDomainId = '',
981
- xEnvironmentId = '',
982
- originCampaign = ''
983
- }) {
1034
+ loginUrl(
1035
+ {
1036
+ state,
1037
+ acrValues = '',
1038
+ scope = 'openid',
1039
+ redirectUri = this.redirectUri,
1040
+ loginHint = '',
1041
+ tag = '',
1042
+ teaser = '',
1043
+ maxAge = '',
1044
+ locale = '',
1045
+ oneStepLogin = false,
1046
+ prompt = 'select_account',
1047
+ xDomainId = '',
1048
+ xEnvironmentId = '',
1049
+ originCampaign = '',
1050
+ }: LoginOptions,
1051
+ ..._args: any[]
1052
+ ): string {
984
1053
  if (typeof arguments[0] !== 'object') {
985
1054
  // backward compatibility
986
1055
  state = arguments[0];
@@ -992,13 +1061,26 @@ export class Identity extends EventEmitter {
992
1061
  teaser = arguments[6] || teaser;
993
1062
  maxAge = isNaN(arguments[7]) ? maxAge : arguments[7];
994
1063
  }
995
- const isValidAcrValue = (acrValue) => isStrIn(acrValue, ['password', 'otp', 'sms', 'eid-dk', 'eid-no', 'eid-se', 'eid-fi', 'eid'], true);
996
- assert(!acrValues || isStrIn(acrValues, ['', 'otp-email'], true) || acrValues.split(' ').every(isValidAcrValue),
997
- `The acrValues parameter is not acceptable: ${acrValues}`);
998
- assert(isUrl(redirectUri),
999
- `loginUrl(): redirectUri must be a valid url but is ${redirectUri}`);
1000
- assert(isNonEmptyString(state),
1001
- `the state parameter should be a non empty string but it is ${state}`);
1064
+ const isValidAcrValue = (acrValue: any) =>
1065
+ isStrIn(
1066
+ acrValue,
1067
+ ['password', 'otp', 'sms', 'eid-dk', 'eid-no', 'eid-se', 'eid-fi', 'eid'],
1068
+ true,
1069
+ );
1070
+ assert(
1071
+ !acrValues ||
1072
+ isStrIn(acrValues, ['', 'otp-email'], true) ||
1073
+ acrValues.split(' ').every(isValidAcrValue),
1074
+ `The acrValues parameter is not acceptable: ${acrValues}`,
1075
+ );
1076
+ assert(
1077
+ isUrl(redirectUri as string),
1078
+ `loginUrl(): redirectUri must be a valid url but is ${redirectUri}`,
1079
+ );
1080
+ assert(
1081
+ isNonEmptyString(state),
1082
+ `the state parameter should be a non empty string but it is ${state}`,
1083
+ );
1002
1084
 
1003
1085
  return this._oauthService.makeUrl('oauth/authorize', {
1004
1086
  response_type: 'code',
@@ -1015,16 +1097,16 @@ export class Identity extends EventEmitter {
1015
1097
  prompt: acrValues ? '' : prompt,
1016
1098
  x_domain_id: xDomainId,
1017
1099
  x_env_id: xEnvironmentId,
1018
- utm_campaign: originCampaign
1100
+ utm_campaign: originCampaign,
1019
1101
  });
1020
1102
  }
1021
1103
 
1022
1104
  /**
1023
1105
  * The url for logging the user out
1024
- * @param {string} [redirectUri=this.redirectUri]
1025
- * @return {string} url
1106
+ * @param redirectUri
1107
+ * @return url
1026
1108
  */
1027
- logoutUrl(redirectUri = this.redirectUri) {
1109
+ logoutUrl(redirectUri: string = this.redirectUri): string {
1028
1110
  assert(isUrl(redirectUri), `logoutUrl(): redirectUri is invalid`);
1029
1111
  const params = { redirect_uri: redirectUri };
1030
1112
  return this._sessionService.makeUrl('logout', params);
@@ -1032,25 +1114,23 @@ export class Identity extends EventEmitter {
1032
1114
 
1033
1115
  /**
1034
1116
  * The account summary page url
1035
- * @param {string} [redirectUri=this.redirectUri]
1036
- * @return {string}
1117
+ * @param redirectUri
1037
1118
  */
1038
- accountUrl(redirectUri = this.redirectUri) {
1119
+ accountUrl(redirectUri: string = this.redirectUri): string {
1039
1120
  return this._spid.makeUrl('profile-pages', {
1040
1121
  response_type: 'code',
1041
- redirect_uri: redirectUri
1122
+ redirect_uri: redirectUri,
1042
1123
  });
1043
1124
  }
1044
1125
 
1045
1126
  /**
1046
1127
  * The phone editing page url
1047
- * @param {string} [redirectUri=this.redirectUri]
1048
- * @return {string}
1128
+ * @param redirectUri
1049
1129
  */
1050
- phonesUrl(redirectUri = this.redirectUri) {
1130
+ phonesUrl(redirectUri: string = this.redirectUri): string {
1051
1131
  return this._spid.makeUrl('profile-pages/about-you/phone', {
1052
1132
  response_type: 'code',
1053
- redirect_uri: redirectUri
1133
+ redirect_uri: redirectUri,
1054
1134
  });
1055
1135
  }
1056
1136
 
@@ -1059,95 +1139,117 @@ export class Identity extends EventEmitter {
1059
1139
  * widget will be display is up to you. Preferred way would be to show it once per user,
1060
1140
  * and store that info in localStorage. Widget will be display only if user is logged in to SSO.
1061
1141
  *
1062
- * @async
1063
- * @param {SimplifiedLoginWidgetLoginOptions} loginParams - the same as `options` param for login function. Login will be called on user
1142
+ * @param loginParams - the same as `options` param for login function. Login will be called on user
1064
1143
  * continue action. `state` might be string or async function.
1065
- * @param {SimplifiedLoginWidgetOptions} [options] - additional configuration of Simplified Login Widget
1144
+ * @param options - additional configuration of Simplified Login Widget
1066
1145
  * @fires Identity#simplifiedLoginOpened
1067
1146
  * @fires Identity#simplifiedLoginCancelled
1068
- * @return {Promise<boolean|SDKError>} - will resolve to true if widget will be display. Otherwise, will throw SDKError
1147
+ * @return - will resolve to true if widget will be display. Otherwise, will throw SDKError
1069
1148
  */
1070
- async showSimplifiedLoginWidget(loginParams, options) {
1149
+ async showSimplifiedLoginWidget(
1150
+ loginParams: SimplifiedLoginWidgetLoginOptions,
1151
+ options?: SimplifiedLoginWidgetOptions,
1152
+ ): Promise<boolean | SDKError> {
1071
1153
  // getUserContextData doesn't throw exception
1072
1154
  const userData = await this.getUserContextData();
1073
1155
 
1074
- const queryParams = { client_id: this.clientId };
1156
+ const queryParams: Record<string, string> = { client_id: this.clientId };
1075
1157
  if (options && options.encoding) {
1076
1158
  queryParams.encoding = options.encoding;
1077
1159
  }
1078
1160
  const widgetUrl = this._bffService.makeUrl('simplified-login-widget', queryParams, false);
1079
1161
 
1080
- const prepareLoginParams = async (loginPrams) => {
1162
+ const prepareLoginParams = async (loginPrams: any) => {
1081
1163
  if (typeof loginPrams.state === 'function') {
1082
1164
  loginPrams.state = await loginPrams.state();
1083
1165
  }
1084
1166
 
1085
1167
  return loginPrams;
1086
- }
1087
-
1088
- return new Promise(
1089
- (resolve, reject) => {
1090
- if (!userData || !userData.display_text || !userData.identifier) {
1091
- return reject(new SDKError('Missing user data'));
1092
- }
1093
-
1094
- const initialParams = {
1095
- displayText: userData.display_text,
1096
- env: this.env,
1097
- clientName: userData.client_name,
1098
- clientId: this.clientId,
1099
- providerId: userData.provider_id,
1100
- windowWidth: () => window.innerWidth,
1101
- windowOnResize: (f) => {
1102
- window.onresize = f;
1103
- },
1104
- };
1105
-
1106
- if (options && options.locale) {
1107
- initialParams.locale = options.locale;
1108
- }
1109
-
1110
- const loginHandler = async () => {
1111
- this.login(Object.assign(await prepareLoginParams(loginParams), {loginHint: userData.identifier}));
1112
- };
1168
+ };
1113
1169
 
1114
- const loginNotYouHandler = async () => {
1115
- this.login(Object.assign(await prepareLoginParams(loginParams), {loginHint: userData.identifier, prompt: 'login'}));
1116
- };
1170
+ return new Promise((resolve, reject) => {
1171
+ if (!userData || !userData.display_text || !userData.identifier) {
1172
+ return reject(new SDKError('Missing user data'));
1173
+ }
1117
1174
 
1118
- const initHandler = () => {
1119
- /**
1120
- * Emitted when the simplified login widget is displayed on the screen
1121
- * @event Identity#simplifiedLoginOpened
1122
- */
1123
- this.emit('simplifiedLoginOpened');
1124
- }
1175
+ const initialParams: Record<string, any> = {
1176
+ displayText: userData.display_text,
1177
+ env: this.env,
1178
+ clientName: userData.client_name,
1179
+ clientId: this.clientId,
1180
+ providerId: (userData as any).provider_id,
1181
+ windowWidth: () => window.innerWidth,
1182
+ windowOnResize: (f: () => void) => {
1183
+ window.onresize = f;
1184
+ },
1185
+ };
1125
1186
 
1126
- const cancelLoginHandler = () => {
1127
- /**
1128
- * Emitted when the user closes the simplified login widget
1129
- * @event Identity#simplifiedLoginCancelled
1130
- */
1131
- this.emit('simplifiedLoginCancelled');
1132
- }
1187
+ if (options && options.locale) {
1188
+ initialParams.locale = options.locale;
1189
+ }
1133
1190
 
1134
- if (window.openSimplifiedLoginWidget) {
1135
- window.openSimplifiedLoginWidget(initialParams, loginHandler, loginNotYouHandler, initHandler, cancelLoginHandler);
1136
- return resolve(true);
1137
- }
1191
+ const loginHandler = async () => {
1192
+ this.login(
1193
+ Object.assign(await prepareLoginParams(loginParams), {
1194
+ loginHint: userData.identifier,
1195
+ }) as LoginOptions,
1196
+ );
1197
+ };
1198
+
1199
+ const loginNotYouHandler = async () => {
1200
+ this.login(
1201
+ Object.assign(await prepareLoginParams(loginParams), {
1202
+ loginHint: userData.identifier,
1203
+ prompt: 'login',
1204
+ }) as LoginOptions,
1205
+ );
1206
+ };
1207
+
1208
+ const initHandler = () => {
1209
+ /**
1210
+ * Emitted when the simplified login widget is displayed on the screen
1211
+ * @event Identity#simplifiedLoginOpened
1212
+ */
1213
+ this.emit('simplifiedLoginOpened');
1214
+ };
1215
+
1216
+ const cancelLoginHandler = () => {
1217
+ /**
1218
+ * Emitted when the user closes the simplified login widget
1219
+ * @event Identity#simplifiedLoginCancelled
1220
+ */
1221
+ this.emit('simplifiedLoginCancelled');
1222
+ };
1223
+
1224
+ if ((window as any).openSimplifiedLoginWidget) {
1225
+ (window as any).openSimplifiedLoginWidget(
1226
+ initialParams,
1227
+ loginHandler,
1228
+ loginNotYouHandler,
1229
+ initHandler,
1230
+ cancelLoginHandler,
1231
+ );
1232
+ return resolve(true);
1233
+ }
1138
1234
 
1139
- const simplifiedLoginWidget = document.createElement("script");
1140
- simplifiedLoginWidget.type = "text/javascript";
1141
- simplifiedLoginWidget.src = widgetUrl;
1142
- simplifiedLoginWidget.onload = () => {
1143
- window.openSimplifiedLoginWidget(initialParams, loginHandler, loginNotYouHandler, initHandler, cancelLoginHandler);
1144
- resolve(true);
1145
- };
1146
- simplifiedLoginWidget.onerror = () => {
1147
- reject(new SDKError('Error when loading simplified login widget content'));
1148
- };
1149
- document.getElementsByTagName('body')[0].appendChild(simplifiedLoginWidget);
1150
- });
1235
+ const simplifiedLoginWidget = document.createElement('script');
1236
+ simplifiedLoginWidget.type = 'text/javascript';
1237
+ simplifiedLoginWidget.src = widgetUrl;
1238
+ simplifiedLoginWidget.onload = () => {
1239
+ (window as any).openSimplifiedLoginWidget(
1240
+ initialParams,
1241
+ loginHandler,
1242
+ loginNotYouHandler,
1243
+ initHandler,
1244
+ cancelLoginHandler,
1245
+ );
1246
+ resolve(true);
1247
+ };
1248
+ simplifiedLoginWidget.onerror = () => {
1249
+ reject(new SDKError('Error when loading simplified login widget content'));
1250
+ };
1251
+ document.getElementsByTagName('body')[0].appendChild(simplifiedLoginWidget);
1252
+ });
1151
1253
  }
1152
1254
  }
1153
1255