@schibsted/account-sdk-browser 6.0.0-alpha.4 → 6.0.0-alpha.6
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 +272 -224
- package/dist/account-sdk.d.ts +18 -0
- package/dist/account.d.ts +134 -3
- package/dist/globals.d.ts +0 -4
- package/dist/identity.d.ts +39 -83
- package/dist/index.d.ts +2 -1
- package/dist/index.js +286 -338
- package/dist/index.js.map +1 -1
- package/dist/monetization.d.ts +6 -25
- package/dist/sdk-error.d.ts +2 -0
- package/dist/types/account.d.ts +33 -3
- package/dist/types/common.d.ts +7 -1
- package/dist/types/identity.d.ts +0 -18
- package/dist/types/login.d.ts +16 -11
- package/dist/types/monetization.d.ts +6 -1
- package/dist/types/session.d.ts +28 -3
- package/dist/version.d.ts +1 -1
- package/package.json +1 -4
- package/src/account-sdk.ts +18 -0
- package/src/account.ts +154 -15
- package/src/globals.ts +0 -4
- package/src/identity.ts +125 -273
- package/src/index.ts +2 -2
- package/src/monetization.ts +15 -51
- package/src/sdk-error.ts +2 -0
- package/src/types/account.ts +36 -13
- package/src/types/common.ts +7 -1
- package/src/types/identity.ts +0 -29
- package/src/types/login.ts +16 -11
- package/src/types/monetization.ts +6 -1
- package/src/types/session.ts +28 -3
- package/src/version.ts +1 -1
- package/dist/global-registry.d.ts +0 -23
- package/dist/types/monetization-guards.d.ts +0 -2
- package/dist/types/session-guards.d.ts +0 -36
- package/src/global-registry.ts +0 -39
- package/src/types/monetization-guards.ts +0 -35
- package/src/types/session-guards.ts +0 -89
package/src/identity.ts
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { TinyEmitter } from 'tiny-emitter';
|
|
6
5
|
import Cache from './cache.js';
|
|
7
6
|
import { ENDPOINTS } from './config.js';
|
|
8
|
-
import { registerAndDispatchInGlobal } from './global-registry.js';
|
|
9
7
|
import { cloneDeep } from './object.js';
|
|
10
8
|
import * as popup from './popup.js';
|
|
11
9
|
import type RESTClient from './rest-client.js';
|
|
@@ -20,6 +18,7 @@ import {
|
|
|
20
18
|
normalizeSessionResponse,
|
|
21
19
|
} from './session-response.js';
|
|
22
20
|
import * as spidTalk from './spid-talk.js';
|
|
21
|
+
import type { AccountEventName } from './types/account.js';
|
|
23
22
|
import type { LogFunction } from './types/common.js';
|
|
24
23
|
import type {
|
|
25
24
|
IdentityBeforeRedirectCallback,
|
|
@@ -45,16 +44,6 @@ import { urlMapper } from './url.js';
|
|
|
45
44
|
import { assert, isNonEmptyString, isObject, isStr, isStrIn, isUrl } from './validate.js';
|
|
46
45
|
import version from './version.js';
|
|
47
46
|
|
|
48
|
-
export { isConnectedSessionResponse, isSessionSuccessResponse } from './session-response.js';
|
|
49
|
-
export type {
|
|
50
|
-
ConnectedSessionResponse,
|
|
51
|
-
SessionFailureResponse,
|
|
52
|
-
SessionObjectResponse,
|
|
53
|
-
SessionResponse,
|
|
54
|
-
SessionSuccessResponse,
|
|
55
|
-
SessionUserId,
|
|
56
|
-
} from './types/session.js';
|
|
57
|
-
|
|
58
47
|
declare global {
|
|
59
48
|
interface Window {
|
|
60
49
|
openSimplifiedLoginWidget?: OpenSimplifiedLoginWidget;
|
|
@@ -74,34 +63,44 @@ const globalWindow = () => window;
|
|
|
74
63
|
/**
|
|
75
64
|
* Provides Identity functionalty to a web page
|
|
76
65
|
*/
|
|
77
|
-
export class Identity
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
66
|
+
export class Identity {
|
|
67
|
+
// Event bus
|
|
68
|
+
private readonly eventTarget = new EventTarget();
|
|
69
|
+
|
|
70
|
+
// Configuration
|
|
71
|
+
private readonly window: Window;
|
|
72
|
+
private readonly clientId: string;
|
|
73
|
+
private readonly redirectUri: string;
|
|
74
|
+
private readonly env: string;
|
|
75
|
+
private readonly log?: LogFunction;
|
|
76
|
+
private readonly callbackBeforeRedirect: IdentityBeforeRedirectCallback;
|
|
77
|
+
|
|
78
|
+
// Caches
|
|
79
|
+
private readonly sessionStorageCache: Cache;
|
|
80
|
+
private readonly localStorageCache: Cache;
|
|
81
|
+
private enableSessionCaching: boolean;
|
|
82
|
+
|
|
83
|
+
// REST clients
|
|
84
|
+
private readonly spid: RESTClient;
|
|
85
|
+
private readonly oauthService: RESTClient;
|
|
86
|
+
private readonly bffService: RESTClient;
|
|
87
|
+
private readonly sessionService: RESTClient;
|
|
88
|
+
private readonly globalSessionService: RESTClient;
|
|
89
|
+
private readonly usedSessionServiceGetSessionEndpoint: 'v2/session' | 'session';
|
|
90
|
+
|
|
91
|
+
// Session state
|
|
89
92
|
/**
|
|
90
93
|
* @internal Starts as `{}` before the first `hasSession()` call, then stores the latest
|
|
91
94
|
* object response from hasSession().
|
|
92
95
|
*/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
popup?: Window | null;
|
|
102
|
-
setVarnishCookie?: boolean;
|
|
103
|
-
varnishExpiresIn?: number;
|
|
104
|
-
varnishCookieDomain?: string;
|
|
96
|
+
private session: SessionObjectResponse;
|
|
97
|
+
private hasSessionInProgress?: false | Promise<SessionResponse>;
|
|
98
|
+
|
|
99
|
+
// Popup & Varnish cookie state
|
|
100
|
+
private popup?: Window | null;
|
|
101
|
+
private setVarnishCookie?: boolean;
|
|
102
|
+
private varnishExpiresIn?: number;
|
|
103
|
+
private varnishCookieDomain?: string;
|
|
105
104
|
|
|
106
105
|
/**
|
|
107
106
|
* @param options
|
|
@@ -124,7 +123,6 @@ export class Identity extends TinyEmitter {
|
|
|
124
123
|
window = globalWindow(),
|
|
125
124
|
callbackBeforeRedirect = () => {},
|
|
126
125
|
}: IdentityOptions) {
|
|
127
|
-
super();
|
|
128
126
|
assert(isNonEmptyString(clientId), 'clientId parameter is required');
|
|
129
127
|
assert(isObject(window), 'The reference to window is missing');
|
|
130
128
|
assert(!redirectUri || isUrl(redirectUri), 'redirectUri parameter is invalid');
|
|
@@ -135,64 +133,66 @@ export class Identity extends TinyEmitter {
|
|
|
135
133
|
assert(isStr(env), `env parameter is invalid: ${env}`);
|
|
136
134
|
|
|
137
135
|
spidTalk.emulate(window);
|
|
138
|
-
this._sessionInitiatedSent = false;
|
|
139
136
|
this.window = window;
|
|
140
137
|
this.clientId = clientId;
|
|
141
|
-
this.sessionStorageCache = new Cache(() => this.window && this.window.sessionStorage);
|
|
142
|
-
this.localStorageCache = new Cache(() => this.window && this.window.localStorage);
|
|
143
138
|
this.redirectUri = redirectUri;
|
|
144
139
|
this.env = env;
|
|
145
140
|
this.log = log;
|
|
146
141
|
this.callbackBeforeRedirect = callbackBeforeRedirect;
|
|
147
|
-
this._sessionDomain = sessionDomain;
|
|
148
142
|
|
|
143
|
+
this.sessionStorageCache = new Cache(() => this.window && this.window.sessionStorage);
|
|
144
|
+
this.localStorageCache = new Cache(() => this.window && this.window.localStorage);
|
|
149
145
|
// Internal hack: set to false to always refresh from hassession
|
|
150
|
-
this.
|
|
146
|
+
this.enableSessionCaching = true;
|
|
151
147
|
|
|
152
|
-
|
|
153
|
-
this._session = {};
|
|
148
|
+
this.session = {};
|
|
154
149
|
|
|
155
150
|
const accountClientParams = { client_id: this.clientId, redirect_uri: this.redirectUri };
|
|
156
151
|
const clientSdrn = buildClientSdrn(this.env, this.clientId);
|
|
157
152
|
|
|
158
|
-
this.
|
|
159
|
-
serverUrl:
|
|
153
|
+
this.spid = createAccountRestClient({
|
|
154
|
+
serverUrl: urlMapper(env, ENDPOINTS.SPiD),
|
|
160
155
|
log: this.log,
|
|
161
|
-
defaultParams:
|
|
162
|
-
client_sdrn: clientSdrn,
|
|
163
|
-
redirect_uri: this.redirectUri,
|
|
164
|
-
sdk_version: version,
|
|
165
|
-
},
|
|
156
|
+
defaultParams: accountClientParams,
|
|
166
157
|
});
|
|
167
|
-
this.
|
|
168
|
-
this._sessionService.url.pathname && this._sessionService.url.pathname.length <= 1
|
|
169
|
-
? 'v2/session'
|
|
170
|
-
: 'session';
|
|
171
|
-
|
|
172
|
-
this._spid = createAccountRestClient({
|
|
158
|
+
this.oauthService = createAccountRestClient({
|
|
173
159
|
serverUrl: urlMapper(env, ENDPOINTS.SPiD),
|
|
174
160
|
log: this.log,
|
|
175
161
|
defaultParams: accountClientParams,
|
|
176
162
|
});
|
|
177
|
-
this.
|
|
163
|
+
this.bffService = createAccountRestClient({
|
|
178
164
|
serverUrl: urlMapper(env, ENDPOINTS.BFF),
|
|
179
165
|
log: this.log,
|
|
180
166
|
defaultParams: accountClientParams,
|
|
181
167
|
});
|
|
182
|
-
this.
|
|
183
|
-
serverUrl:
|
|
168
|
+
this.sessionService = createAccountRestClient({
|
|
169
|
+
serverUrl: sessionDomain,
|
|
184
170
|
log: this.log,
|
|
185
|
-
defaultParams:
|
|
171
|
+
defaultParams: {
|
|
172
|
+
client_sdrn: clientSdrn,
|
|
173
|
+
redirect_uri: this.redirectUri,
|
|
174
|
+
sdk_version: version,
|
|
175
|
+
},
|
|
186
176
|
});
|
|
187
|
-
this.
|
|
177
|
+
this.globalSessionService = createAccountRestClient({
|
|
188
178
|
serverUrl: urlMapper(env, ENDPOINTS.SESSION_SERVICE),
|
|
189
179
|
log: this.log,
|
|
190
180
|
defaultParams: { client_sdrn: clientSdrn, sdk_version: version },
|
|
191
181
|
});
|
|
182
|
+
this.usedSessionServiceGetSessionEndpoint =
|
|
183
|
+
this.sessionService.url.pathname && this.sessionService.url.pathname.length <= 1
|
|
184
|
+
? 'v2/session'
|
|
185
|
+
: 'session';
|
|
192
186
|
|
|
193
187
|
this._unblockSessionCall();
|
|
188
|
+
}
|
|
194
189
|
|
|
195
|
-
|
|
190
|
+
addEventListener(type: AccountEventName, listener: EventListener): void {
|
|
191
|
+
this.eventTarget.addEventListener(type, listener);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
removeEventListener(type: AccountEventName, listener: EventListener): void {
|
|
195
|
+
this.eventTarget.removeEventListener(type, listener);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/**
|
|
@@ -200,7 +200,7 @@ export class Identity extends TinyEmitter {
|
|
|
200
200
|
* @private
|
|
201
201
|
*/
|
|
202
202
|
_getTabId(): number | undefined {
|
|
203
|
-
if (this.
|
|
203
|
+
if (this.enableSessionCaching) {
|
|
204
204
|
const tabId = this.sessionStorageCache.get(TAB_ID_KEY);
|
|
205
205
|
if (typeof tabId !== 'number') {
|
|
206
206
|
this.sessionStorageCache.set(TAB_ID_KEY, TAB_ID, TAB_ID_TTL);
|
|
@@ -244,80 +244,6 @@ export class Identity extends TinyEmitter {
|
|
|
244
244
|
this.localStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
/**
|
|
248
|
-
* Emits the relevant events based on the previous and new reply from hasSession
|
|
249
|
-
* @private
|
|
250
|
-
* @param previous
|
|
251
|
-
* @param current
|
|
252
|
-
*/
|
|
253
|
-
_emitSessionEvent(previous: object, current: object): void {
|
|
254
|
-
const previousUserId = isSessionSuccessResponse(previous) ? previous.userId : undefined;
|
|
255
|
-
const currentUserId = isSessionSuccessResponse(current) ? current.userId : undefined;
|
|
256
|
-
const previousUserStatus = isSessionSuccessResponse(previous)
|
|
257
|
-
? previous.userStatus
|
|
258
|
-
: undefined;
|
|
259
|
-
const currentUserStatus = isSessionSuccessResponse(current)
|
|
260
|
-
? current.userStatus
|
|
261
|
-
: undefined;
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Emitted when the user is logged in (This happens as a result of calling
|
|
265
|
-
* {@link Identity#hasSession}, so it is also emitted if the user was previously logged in)
|
|
266
|
-
* @event Identity#login
|
|
267
|
-
*/
|
|
268
|
-
if (currentUserId) {
|
|
269
|
-
this.emit('login', current);
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Emitted when the user logged out
|
|
273
|
-
* @event Identity#logout
|
|
274
|
-
*/
|
|
275
|
-
if (previousUserId && !currentUserId) {
|
|
276
|
-
this.emit('logout', current);
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Emitted when the user is changed. This happens as a result of calling
|
|
280
|
-
* {@link Identity#hasSession}, and is emitted if there was a user both before and after
|
|
281
|
-
* this invocation, and the userId has now changed
|
|
282
|
-
* @event Identity#userChange
|
|
283
|
-
*/
|
|
284
|
-
if (previousUserId && currentUserId && previousUserId !== currentUserId) {
|
|
285
|
-
this.emit('userChange', current);
|
|
286
|
-
}
|
|
287
|
-
if (previousUserId || currentUserId) {
|
|
288
|
-
/**
|
|
289
|
-
* Emitted when the session is changed. More accurately, this event is emitted if there
|
|
290
|
-
* was a logged-in user either before or after {@link Identity#hasSession} was called.
|
|
291
|
-
* In practice, this means the event is emitted a lot
|
|
292
|
-
* @event Identity#sessionChange
|
|
293
|
-
*/
|
|
294
|
-
this.emit('sessionChange', current);
|
|
295
|
-
} else {
|
|
296
|
-
/**
|
|
297
|
-
* Emitted when there is no logged-in user. More specifically, it means that there was
|
|
298
|
-
* no logged-in user neither before nor after {@link Identity#hasSession} was called
|
|
299
|
-
* @event Identity#notLoggedin
|
|
300
|
-
*/
|
|
301
|
-
this.emit('notLoggedin', current);
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Emitted when the session is first created
|
|
305
|
-
* @event Identity#sessionInit
|
|
306
|
-
*/
|
|
307
|
-
if (currentUserId && !this._sessionInitiatedSent) {
|
|
308
|
-
this._sessionInitiatedSent = true;
|
|
309
|
-
this.emit('sessionInit', current);
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Emitted when the user status changes. This happens as a result of calling
|
|
313
|
-
* {@link Identity#hasSession}
|
|
314
|
-
* @event Identity#statusChange
|
|
315
|
-
*/
|
|
316
|
-
if (previousUserStatus !== currentUserStatus) {
|
|
317
|
-
this.emit('statusChange', current);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
247
|
/**
|
|
322
248
|
* Close this.popup if it exists and is open
|
|
323
249
|
* @private
|
|
@@ -406,10 +332,10 @@ export class Identity extends TinyEmitter {
|
|
|
406
332
|
*/
|
|
407
333
|
_clearVarnishCookie(): void {
|
|
408
334
|
const baseDomain =
|
|
409
|
-
this.
|
|
410
|
-
isSessionSuccessResponse(this.
|
|
411
|
-
typeof this.
|
|
412
|
-
? this.
|
|
335
|
+
this.session &&
|
|
336
|
+
isSessionSuccessResponse(this.session) &&
|
|
337
|
+
typeof this.session.baseDomain === 'string'
|
|
338
|
+
? this.session.baseDomain
|
|
413
339
|
: this.window.location.hostname;
|
|
414
340
|
|
|
415
341
|
const domain = this.varnishCookieDomain || baseDomain || '';
|
|
@@ -417,53 +343,23 @@ export class Identity extends TinyEmitter {
|
|
|
417
343
|
document.cookie = `SP_ID=nothing; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
|
|
418
344
|
}
|
|
419
345
|
|
|
420
|
-
/**
|
|
421
|
-
* Log used settings and version
|
|
422
|
-
* @throws {SDKError} - If log method is not provided
|
|
423
|
-
*/
|
|
424
|
-
logSettings(): void {
|
|
425
|
-
if (!this.log && !window.console) {
|
|
426
|
-
throw new SDKError('You have to provide log method in constructor');
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const log = this.log || console.log;
|
|
430
|
-
|
|
431
|
-
const settings = {
|
|
432
|
-
clientId: this.clientId,
|
|
433
|
-
redirectUri: this.redirectUri,
|
|
434
|
-
env: this.env,
|
|
435
|
-
sessionDomain: this._sessionDomain,
|
|
436
|
-
sdkVersion: version,
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
log(`Schibsted account SDK for browsers settings: \n${JSON.stringify(settings, null, 2)}`);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
346
|
/**
|
|
443
347
|
* @summary Queries the hassession endpoint and returns information about the status of the user
|
|
444
348
|
* @remarks When we send a request to this endpoint, cookies sent along with the request
|
|
445
349
|
* determines the status of the user.
|
|
446
350
|
* @throws {SDKError} - If the call to the hasSession service fails in any way (this will happen
|
|
447
351
|
* if, say, the user is not logged in)
|
|
448
|
-
* @fires Identity#login
|
|
449
|
-
* @fires Identity#logout
|
|
450
|
-
* @fires Identity#userChange
|
|
451
|
-
* @fires Identity#sessionChange
|
|
452
|
-
* @fires Identity#notLoggedin
|
|
453
|
-
* @fires Identity#sessionInit
|
|
454
|
-
* @fires Identity#statusChange
|
|
455
|
-
* @fires Identity#error
|
|
456
352
|
*/
|
|
457
353
|
hasSession(): Promise<SessionResponse> {
|
|
458
354
|
const isSessionCallBlocked = this._isSessionCallBlocked();
|
|
459
355
|
|
|
460
356
|
if (isSessionCallBlocked) {
|
|
461
|
-
const sessionData = normalizeSessionResponse(this.
|
|
357
|
+
const sessionData = normalizeSessionResponse(this.session);
|
|
462
358
|
return Promise.resolve(isRedirectSessionPayload(sessionData) ? {} : sessionData);
|
|
463
359
|
}
|
|
464
360
|
|
|
465
|
-
if (this.
|
|
466
|
-
return this.
|
|
361
|
+
if (this.hasSessionInProgress) {
|
|
362
|
+
return this.hasSessionInProgress;
|
|
467
363
|
}
|
|
468
364
|
|
|
469
365
|
const _postProcess = (sessionData: SessionObjectResponse): SessionObjectResponse => {
|
|
@@ -474,8 +370,7 @@ export class Identity extends TinyEmitter {
|
|
|
474
370
|
throw new SDKError('HasSession failed', errorObject);
|
|
475
371
|
}
|
|
476
372
|
this._maybeSetVarnishCookie(sessionData);
|
|
477
|
-
this.
|
|
478
|
-
this._session = sessionData;
|
|
373
|
+
this.session = sessionData;
|
|
479
374
|
return sessionData;
|
|
480
375
|
};
|
|
481
376
|
|
|
@@ -485,7 +380,7 @@ export class Identity extends TinyEmitter {
|
|
|
485
380
|
};
|
|
486
381
|
|
|
487
382
|
const _getSession = async (): Promise<SessionResponse> => {
|
|
488
|
-
if (this.
|
|
383
|
+
if (this.enableSessionCaching) {
|
|
489
384
|
// Try to resolve from cache (it has a TTL)
|
|
490
385
|
const cachedSession = _getCachedSession();
|
|
491
386
|
if (cachedSession) {
|
|
@@ -497,14 +392,14 @@ export class Identity extends TinyEmitter {
|
|
|
497
392
|
}
|
|
498
393
|
let sessionData: NormalizedSessionPayload | null = null;
|
|
499
394
|
try {
|
|
500
|
-
sessionData = await this.
|
|
501
|
-
this.
|
|
395
|
+
sessionData = await this.sessionService.get(
|
|
396
|
+
this.usedSessionServiceGetSessionEndpoint,
|
|
502
397
|
{ tabId: this._getTabId() },
|
|
503
398
|
normalizeSessionResponse,
|
|
504
399
|
);
|
|
505
400
|
} catch (err: unknown) {
|
|
506
401
|
const cacheableError = isObject(err) ? err : undefined;
|
|
507
|
-
if (cacheableError?.code === 400 && this.
|
|
402
|
+
if (cacheableError?.code === 400 && this.enableSessionCaching) {
|
|
508
403
|
const errorExpiresIn =
|
|
509
404
|
typeof cacheableError.expiresIn === 'number'
|
|
510
405
|
? cacheableError.expiresIn
|
|
@@ -516,7 +411,7 @@ export class Identity extends TinyEmitter {
|
|
|
516
411
|
typeof cacheableError.code === 'number' &&
|
|
517
412
|
cacheableError.code >= 500 &&
|
|
518
413
|
cacheableError.code < 600 &&
|
|
519
|
-
this.
|
|
414
|
+
this.enableSessionCaching
|
|
520
415
|
) {
|
|
521
416
|
// Temporary fix: 30 seconds cache to limit number of calls when service is unavailable
|
|
522
417
|
this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, 30 * 1000);
|
|
@@ -531,13 +426,13 @@ export class Identity extends TinyEmitter {
|
|
|
531
426
|
|
|
532
427
|
await this.callbackBeforeRedirect();
|
|
533
428
|
|
|
534
|
-
const redirectUrl = this.
|
|
429
|
+
const redirectUrl = this.sessionService.makeUrl(sessionData.redirectURL, {
|
|
535
430
|
tabId: this._getTabId(),
|
|
536
431
|
});
|
|
537
432
|
return redirectUrl;
|
|
538
433
|
}
|
|
539
434
|
|
|
540
|
-
if (this.
|
|
435
|
+
if (this.enableSessionCaching) {
|
|
541
436
|
const expiresIn =
|
|
542
437
|
1000 *
|
|
543
438
|
(isSessionSuccessResponse(sessionData)
|
|
@@ -549,22 +444,21 @@ export class Identity extends TinyEmitter {
|
|
|
549
444
|
|
|
550
445
|
return _postProcess(sessionData ?? {});
|
|
551
446
|
};
|
|
552
|
-
this.
|
|
447
|
+
this.hasSessionInProgress = _getSession().then(
|
|
553
448
|
(sessionData) => {
|
|
554
|
-
this.
|
|
449
|
+
this.hasSessionInProgress = false;
|
|
555
450
|
if (typeof sessionData === 'string') {
|
|
556
451
|
this.window.location.href = sessionData;
|
|
557
452
|
}
|
|
558
453
|
return sessionData;
|
|
559
454
|
},
|
|
560
455
|
(err) => {
|
|
561
|
-
this.
|
|
562
|
-
this._hasSessionInProgress = false;
|
|
456
|
+
this.hasSessionInProgress = false;
|
|
563
457
|
throw new SDKError('HasSession failed', err);
|
|
564
458
|
},
|
|
565
459
|
);
|
|
566
460
|
|
|
567
|
-
return this.
|
|
461
|
+
return this.hasSessionInProgress;
|
|
568
462
|
}
|
|
569
463
|
|
|
570
464
|
/**
|
|
@@ -581,6 +475,16 @@ export class Identity extends TinyEmitter {
|
|
|
581
475
|
}
|
|
582
476
|
}
|
|
583
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Enables or disables caching for subsequent session lookups.
|
|
480
|
+
*
|
|
481
|
+
* Changing this setting does not remove an existing cached session. Use
|
|
482
|
+
* {@link Identity#clearCachedUserSession} to clear the cache explicitly.
|
|
483
|
+
*/
|
|
484
|
+
setSessionCachingEnabled(enabled: boolean): void {
|
|
485
|
+
this.enableSessionCaching = enabled;
|
|
486
|
+
}
|
|
487
|
+
|
|
584
488
|
/**
|
|
585
489
|
* Removes the cached user session.
|
|
586
490
|
*/
|
|
@@ -618,11 +522,9 @@ export class Identity extends TinyEmitter {
|
|
|
618
522
|
}
|
|
619
523
|
return cloneDeep(user);
|
|
620
524
|
}
|
|
621
|
-
|
|
622
525
|
/**
|
|
623
526
|
* @summary
|
|
624
|
-
* In Schibsted account, there are multiple ways of identifying a user; the `userId
|
|
625
|
-
* `uuid` and `externalId` used for identifying a user-merchant pair (see {@link Identity#getExternalId}).
|
|
527
|
+
* In Schibsted account, there are multiple ways of identifying a user; the `userId` or `uuid`.
|
|
626
528
|
* There are reasons for them all to exist. The `userId` is a numeric identifier, but
|
|
627
529
|
* since Schibsted account is deployed separately in Norway and Sweden, there are a lot of
|
|
628
530
|
* duplicates. The `userId` was introduced early, so many sites still need to use them for
|
|
@@ -641,65 +543,6 @@ export class Identity extends TinyEmitter {
|
|
|
641
543
|
throw new SDKError('The user is not connected to this merchant');
|
|
642
544
|
}
|
|
643
545
|
|
|
644
|
-
/**
|
|
645
|
-
* @function
|
|
646
|
-
* @summary
|
|
647
|
-
* Retrieves the external identifier (`externalId`) for the authenticated user.
|
|
648
|
-
*
|
|
649
|
-
* In Schibsted Account there are multiple ways of identifying users, however for integrations with
|
|
650
|
-
* third-parties it's recommended to use `externalId` as it does not disclose
|
|
651
|
-
* any critical data whilst allowing for user identification.
|
|
652
|
-
*
|
|
653
|
-
* `externalId` is merchant-scoped using a pairwise identifier (`pairId`),
|
|
654
|
-
* meaning the same user's ID will differ between merchants.
|
|
655
|
-
* Additionally, this identifier is bound to the external party provided as argument.
|
|
656
|
-
*
|
|
657
|
-
* @param externalParty
|
|
658
|
-
* @param optionalSuffix
|
|
659
|
-
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
660
|
-
* effect that it might perform an auto-login on the user
|
|
661
|
-
* @throws {SDKError} If the `pairId` is missing in user session.
|
|
662
|
-
* @throws {SDKError} If the `externalParty` is not defined
|
|
663
|
-
* @return The merchant- and 3rd-party-specific `externalId`
|
|
664
|
-
*/
|
|
665
|
-
async getExternalId(externalParty: string, optionalSuffix: string = ''): Promise<string> {
|
|
666
|
-
const user = await this.hasSession();
|
|
667
|
-
const pairId = isSessionSuccessResponse(user) ? user.pairId : undefined;
|
|
668
|
-
|
|
669
|
-
if (!pairId) throw new SDKError('pairId missing in user session!');
|
|
670
|
-
|
|
671
|
-
if (!externalParty || externalParty.length === 0) {
|
|
672
|
-
throw new SDKError('externalParty cannot be empty');
|
|
673
|
-
}
|
|
674
|
-
const _toHexDigest = (hashBuffer: ArrayBuffer) => {
|
|
675
|
-
// convert buffer to byte array
|
|
676
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
677
|
-
// convert bytes to hex string
|
|
678
|
-
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
const _getSha256Digest = (data: BufferSource) => {
|
|
682
|
-
return crypto.subtle.digest('SHA-256', data);
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
const _hashMessage = async (message: string) => {
|
|
686
|
-
const msgUint8 = new TextEncoder().encode(message);
|
|
687
|
-
return _getSha256Digest(msgUint8).then((it) => _toHexDigest(it));
|
|
688
|
-
};
|
|
689
|
-
|
|
690
|
-
const _constructMessage = (
|
|
691
|
-
pairId: string,
|
|
692
|
-
externalParty: string,
|
|
693
|
-
optionalSuffix: string,
|
|
694
|
-
) => {
|
|
695
|
-
return optionalSuffix
|
|
696
|
-
? `${pairId}:${externalParty}:${optionalSuffix}`
|
|
697
|
-
: `${pairId}:${externalParty}`;
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix));
|
|
701
|
-
}
|
|
702
|
-
|
|
703
546
|
/**
|
|
704
547
|
* @summary Enables brands to programmatically get the current the SDRN based on the user's session.
|
|
705
548
|
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
@@ -744,7 +587,7 @@ export class Identity extends TinyEmitter {
|
|
|
744
587
|
*/
|
|
745
588
|
async getUserContextData(): Promise<SimplifiedLoginData | null> {
|
|
746
589
|
try {
|
|
747
|
-
return await this.
|
|
590
|
+
return await this.globalSessionService.get('user-context', undefined, (value) =>
|
|
748
591
|
isObject(value) && isStr(value.identifier)
|
|
749
592
|
? {
|
|
750
593
|
identifier: value.identifier,
|
|
@@ -782,6 +625,7 @@ export class Identity extends TinyEmitter {
|
|
|
782
625
|
* @param options.xDomainId
|
|
783
626
|
* @param options.xEnvironmentId
|
|
784
627
|
* @param options.originCampaign
|
|
628
|
+
* @fires Identity#login
|
|
785
629
|
* @return - Reference to popup window if created (or `null` otherwise)
|
|
786
630
|
*/
|
|
787
631
|
login({
|
|
@@ -825,11 +669,25 @@ export class Identity extends TinyEmitter {
|
|
|
825
669
|
width: 360,
|
|
826
670
|
height: 570,
|
|
827
671
|
});
|
|
672
|
+
|
|
828
673
|
if (this.popup) {
|
|
674
|
+
this.eventTarget.dispatchEvent(
|
|
675
|
+
new CustomEvent('login', {
|
|
676
|
+
detail: { url, method: 'popup' },
|
|
677
|
+
}),
|
|
678
|
+
);
|
|
679
|
+
|
|
829
680
|
return this.popup;
|
|
830
681
|
}
|
|
831
682
|
}
|
|
683
|
+
|
|
684
|
+
this.eventTarget.dispatchEvent(
|
|
685
|
+
new CustomEvent('login', {
|
|
686
|
+
detail: { url, method: 'default' },
|
|
687
|
+
}),
|
|
688
|
+
);
|
|
832
689
|
this.window.location.href = url;
|
|
690
|
+
|
|
833
691
|
return null;
|
|
834
692
|
}
|
|
835
693
|
|
|
@@ -854,14 +712,19 @@ export class Identity extends TinyEmitter {
|
|
|
854
712
|
|
|
855
713
|
/**
|
|
856
714
|
* @summary Logs the user out from the Identity platform
|
|
857
|
-
* @param redirectUri - Where to redirect the browser after logging out of Schibsted
|
|
858
|
-
*
|
|
715
|
+
* @param redirectUri - Where to redirect the browser after logging out of Schibsted account
|
|
716
|
+
* @fires Identity#logout
|
|
859
717
|
*/
|
|
860
718
|
logout(redirectUri: string = this.redirectUri): void {
|
|
861
719
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
862
720
|
this._maybeClearVarnishCookie();
|
|
863
|
-
this.
|
|
864
|
-
this.
|
|
721
|
+
const url = this.logoutUrl(redirectUri);
|
|
722
|
+
this.eventTarget.dispatchEvent(
|
|
723
|
+
new CustomEvent('logout', {
|
|
724
|
+
detail: { url },
|
|
725
|
+
}),
|
|
726
|
+
);
|
|
727
|
+
this.window.location.href = url;
|
|
865
728
|
}
|
|
866
729
|
|
|
867
730
|
/**
|
|
@@ -920,7 +783,7 @@ export class Identity extends TinyEmitter {
|
|
|
920
783
|
`the state parameter should be a non empty string but it is ${state}`,
|
|
921
784
|
);
|
|
922
785
|
|
|
923
|
-
return this.
|
|
786
|
+
return this.oauthService.makeUrl('oauth/authorize', {
|
|
924
787
|
response_type: 'code',
|
|
925
788
|
redirect_uri: redirectUri,
|
|
926
789
|
scope,
|
|
@@ -947,7 +810,7 @@ export class Identity extends TinyEmitter {
|
|
|
947
810
|
logoutUrl(redirectUri: string = this.redirectUri): string {
|
|
948
811
|
assert(isUrl(redirectUri), `logoutUrl(): redirectUri is invalid`);
|
|
949
812
|
const params = { redirect_uri: redirectUri };
|
|
950
|
-
return this.
|
|
813
|
+
return this.sessionService.makeUrl('logout', params);
|
|
951
814
|
}
|
|
952
815
|
|
|
953
816
|
/**
|
|
@@ -955,18 +818,7 @@ export class Identity extends TinyEmitter {
|
|
|
955
818
|
* @param redirectUri
|
|
956
819
|
*/
|
|
957
820
|
accountUrl(redirectUri: string = this.redirectUri): string {
|
|
958
|
-
return this.
|
|
959
|
-
response_type: 'code',
|
|
960
|
-
redirect_uri: redirectUri,
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
/**
|
|
965
|
-
* The phone editing page url
|
|
966
|
-
* @param redirectUri
|
|
967
|
-
*/
|
|
968
|
-
phonesUrl(redirectUri: string = this.redirectUri): string {
|
|
969
|
-
return this._spid.makeUrl('profile-pages/about-you/phone', {
|
|
821
|
+
return this.spid.makeUrl('profile-pages', {
|
|
970
822
|
response_type: 'code',
|
|
971
823
|
redirect_uri: redirectUri,
|
|
972
824
|
});
|
|
@@ -996,7 +848,7 @@ export class Identity extends TinyEmitter {
|
|
|
996
848
|
if (options && options.encoding) {
|
|
997
849
|
queryParams.encoding = options.encoding;
|
|
998
850
|
}
|
|
999
|
-
const widgetUrl = this.
|
|
851
|
+
const widgetUrl = this.bffService.makeUrl('simplified-login-widget', queryParams, false);
|
|
1000
852
|
|
|
1001
853
|
const prepareLoginParams = async (
|
|
1002
854
|
loginParams: SimplifiedLoginWidgetLoginOptions,
|
|
@@ -1056,11 +908,11 @@ export class Identity extends TinyEmitter {
|
|
|
1056
908
|
* Emitted when the simplified login widget is displayed on the screen
|
|
1057
909
|
* @event Identity#simplifiedLoginOpened
|
|
1058
910
|
*/
|
|
1059
|
-
this.
|
|
911
|
+
this.eventTarget.dispatchEvent(new Event('simplifiedLoginOpened'));
|
|
1060
912
|
};
|
|
1061
913
|
|
|
1062
914
|
const cancelLoginHandler = () => {
|
|
1063
|
-
this.
|
|
915
|
+
this.eventTarget.dispatchEvent(new Event('simplifiedLoginCancelled'));
|
|
1064
916
|
};
|
|
1065
917
|
|
|
1066
918
|
if (hasOpenSimplifiedLoginWidget(window)) {
|
package/src/index.ts
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
export { Account } from './account.js';
|
|
6
6
|
export { createAccountSdk, getAccountSdk } from './account-sdk.js';
|
|
7
|
+
export * from './globals.js';
|
|
7
8
|
export { default as SDKError } from './sdk-error.js';
|
|
8
9
|
|
|
9
10
|
/* public available types */
|
|
10
11
|
export type {
|
|
11
12
|
AccountConfig,
|
|
12
|
-
|
|
13
|
+
AccountEventListener,
|
|
13
14
|
AccountEventName,
|
|
14
|
-
AccountSessionEventName,
|
|
15
15
|
} from './types/account.js';
|
|
16
16
|
export type { AccountEnvironment, LogFunction } from './types/common.js';
|
|
17
17
|
export type {
|