@schibsted/account-sdk-browser 6.0.0-alpha.2 → 6.0.0-alpha.4
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 +39 -39
- package/dist/account-sdk.d.ts +4 -0
- package/dist/account.d.ts +30 -0
- package/dist/global-registry.d.ts +1 -1
- package/dist/globals.d.ts +2 -0
- package/dist/has-access-response.d.ts +2 -0
- package/dist/identity.d.ts +37 -237
- package/dist/index.d.ts +8 -3
- package/dist/index.js +862 -4
- package/dist/index.js.map +1 -0
- package/dist/monetization.d.ts +7 -43
- package/dist/resolve-browser-window.d.ts +1 -0
- package/dist/{RESTClient.d.ts → rest-client.d.ts} +22 -11
- package/dist/rest-clients.d.ts +10 -0
- package/dist/session-response.d.ts +30 -0
- package/dist/types/account.d.ts +13 -0
- package/dist/types/common.d.ts +22 -0
- package/dist/types/identity.d.ts +41 -0
- package/dist/types/login.d.ts +120 -0
- package/dist/types/monetization-guards.d.ts +2 -0
- package/dist/types/monetization.d.ts +21 -0
- package/dist/types/session-guards.d.ts +36 -0
- package/dist/types/session.d.ts +124 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -9
- package/src/account-sdk.ts +74 -0
- package/src/account.ts +153 -0
- package/src/cache.ts +1 -1
- package/src/global-registry.ts +1 -1
- package/src/globals.ts +2 -0
- package/src/has-access-response.ts +35 -0
- package/src/identity.ts +269 -423
- package/src/index.ts +28 -3
- package/src/monetization.ts +31 -68
- package/src/object.ts +1 -1
- package/src/resolve-browser-window.ts +11 -0
- package/src/{RESTClient.ts → rest-client.ts} +55 -28
- package/src/rest-clients.ts +30 -0
- package/src/session-response.ts +79 -0
- package/src/types/account.ts +27 -0
- package/src/types/common.ts +26 -0
- package/src/types/identity.ts +55 -0
- package/src/types/login.ts +145 -0
- package/src/types/monetization-guards.ts +35 -0
- package/src/types/monetization.ts +24 -0
- package/src/types/session-guards.ts +89 -0
- package/src/types/session.ts +147 -0
- package/src/validate.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/identity-s4nofYmB.js +0 -370
- package/dist/identity-s4nofYmB.js.map +0 -1
- package/dist/identity.js +0 -2
- package/dist/monetization.js +0 -72
- package/dist/monetization.js.map +0 -1
- package/dist/version-spE-k97g.js +0 -289
- package/dist/version-spE-k97g.js.map +0 -1
- /package/dist/{SDKError.d.ts → sdk-error.d.ts} +0 -0
- /package/dist/{spidTalk.d.ts → spid-talk.d.ts} +0 -0
- /package/src/{SDKError.ts → sdk-error.ts} +0 -0
- /package/src/{spidTalk.ts → spid-talk.ts} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options accepted by {@link Identity#login} and related login URL helpers.
|
|
3
|
+
*/
|
|
4
|
+
export type LoginOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* An opaque value used by the client to maintain state between the request and callback.
|
|
7
|
+
* It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
|
|
8
|
+
*/
|
|
9
|
+
state: string;
|
|
10
|
+
/**
|
|
11
|
+
* Authentication Context Class Reference Values. If omitted, the user will be asked to
|
|
12
|
+
* authenticate using username+password. For 2FA (Two-Factor Authentication) possible values
|
|
13
|
+
* are `sms`, `otp` (one time password), `password` (will force password confirmation, even if
|
|
14
|
+
* user is already logged in), `eid`. Those values might be mixed as space-separated string.
|
|
15
|
+
* To make sure that user has authenticated with 2FA you need to verify AMR (Authentication
|
|
16
|
+
* Methods References) claim in ID token. Might also be used to ensure additional acr
|
|
17
|
+
* (sms, otp, eid) for already logged in users. Supported value is also 'otp-email' means one
|
|
18
|
+
* time password using email.
|
|
19
|
+
*/
|
|
20
|
+
acrValues?: 'password' | 'otp' | 'sms' | 'eid-dk' | 'eid-no' | 'eid-se' | 'eid-fi' | 'eid' | 'otp-email' | (string & {});
|
|
21
|
+
/**
|
|
22
|
+
* The OAuth scopes for the tokens. This is a list of scopes, separated by space. If the list
|
|
23
|
+
* of scopes contains `openid`, the generated tokens includes the id token which can be useful
|
|
24
|
+
* for getting information about the user. Omitting scope is allowed, while `invalid_scope` is
|
|
25
|
+
* returned when the client asks for a scope you aren't allowed to request.
|
|
26
|
+
* {@link https://tools.ietf.org/html/rfc6749#section-3.3}
|
|
27
|
+
* Defaults to `openid`.
|
|
28
|
+
*/
|
|
29
|
+
scope?: 'openid' | (string & {});
|
|
30
|
+
/**
|
|
31
|
+
* Redirect uri that will receive the code. Must exactly match a redirectUri from your client
|
|
32
|
+
* in self-service
|
|
33
|
+
*/
|
|
34
|
+
redirectUri?: string;
|
|
35
|
+
/** Should we try to open a popup window? Defaults to `false`. */
|
|
36
|
+
preferPopup?: boolean;
|
|
37
|
+
/** user email or UUID hint */
|
|
38
|
+
loginHint?: string;
|
|
39
|
+
/** Pulse tag */
|
|
40
|
+
tag?: string;
|
|
41
|
+
/** Teaser slug. Teaser with given slug will be displayed in place of default teaser */
|
|
42
|
+
teaser?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Specifies the allowable elapsed time in seconds since the last time the End-User was actively
|
|
45
|
+
* authenticated. If last authentication time is more than maxAge seconds in the past,
|
|
46
|
+
* re-authentication will be required. See the OpenID Connect spec section 3.1.2.1 for more
|
|
47
|
+
* information. Prefer a number of seconds; strings remain accepted for legacy callers.
|
|
48
|
+
*/
|
|
49
|
+
maxAge?: number | string;
|
|
50
|
+
/**
|
|
51
|
+
* Optional parameter to overwrite client locale setting.
|
|
52
|
+
* New flows supports nb_NO, fi_FI, sv_SE, en_US
|
|
53
|
+
*/
|
|
54
|
+
locale?: 'nb_NO' | 'fi_FI' | 'sv_SE' | 'en_US';
|
|
55
|
+
/** display username and password on one screen. Defaults to `false`. */
|
|
56
|
+
oneStepLogin?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* String that specifies whether the Authorization Server prompts the End-User for
|
|
59
|
+
* reauthentication or confirm account screen. Supported values: `select_account` or `login`.
|
|
60
|
+
* Defaults to `select_account`.
|
|
61
|
+
*/
|
|
62
|
+
prompt?: 'select_account' | 'login';
|
|
63
|
+
/** Identifier for cross-domain tracking in Pulse */
|
|
64
|
+
xDomainId?: string;
|
|
65
|
+
/** Environment for cross-domain tracking in Pulse */
|
|
66
|
+
xEnvironmentId?: string;
|
|
67
|
+
/** Campaign identifier for tracking in Pulse */
|
|
68
|
+
originCampaign?: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;
|
|
72
|
+
* all other fields reuse the `LoginOptions` documentation.
|
|
73
|
+
*/
|
|
74
|
+
export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
|
|
75
|
+
/**
|
|
76
|
+
* An opaque value used by the client to maintain state between the request and callback.
|
|
77
|
+
* It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
|
|
78
|
+
*/
|
|
79
|
+
state: string | (() => string | Promise<string>);
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Minimal user information used by the simplified login widget flow.
|
|
83
|
+
*/
|
|
84
|
+
export type SimplifiedLoginData = {
|
|
85
|
+
/** Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login} */
|
|
86
|
+
identifier: string;
|
|
87
|
+
/** Human-readable user identifier */
|
|
88
|
+
display_text: string;
|
|
89
|
+
/** Client name */
|
|
90
|
+
client_name: string;
|
|
91
|
+
/** Provider id used by the simplified login widget when supplied by the backend. */
|
|
92
|
+
provider_id?: string;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Configuration options for {@link Identity#showSimplifiedLoginWidget}.
|
|
96
|
+
*/
|
|
97
|
+
export type SimplifiedLoginWidgetOptions = {
|
|
98
|
+
/** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */
|
|
99
|
+
encoding?: string;
|
|
100
|
+
/**
|
|
101
|
+
* expected locale of simplified login widget. Should be provided in a short format like 'nb',
|
|
102
|
+
* 'sv'. If not set, a value from the env variable is used.
|
|
103
|
+
*/
|
|
104
|
+
locale?: 'nb' | 'sv' | 'fi' | 'da' | 'en';
|
|
105
|
+
};
|
|
106
|
+
export type SimplifiedLoginWidgetInitialParams = {
|
|
107
|
+
displayText: string;
|
|
108
|
+
env: string;
|
|
109
|
+
clientName: string;
|
|
110
|
+
clientId: string;
|
|
111
|
+
providerId?: string;
|
|
112
|
+
locale?: SimplifiedLoginWidgetOptions['locale'];
|
|
113
|
+
windowWidth: () => number;
|
|
114
|
+
windowOnResize: (handler: () => void) => void;
|
|
115
|
+
};
|
|
116
|
+
export type SimplifiedLoginWidgetHandler = () => void | Promise<void>;
|
|
117
|
+
export type OpenSimplifiedLoginWidget = (initialParams: SimplifiedLoginWidgetInitialParams, loginHandler: SimplifiedLoginWidgetHandler, loginNotYouHandler: SimplifiedLoginWidgetHandler, initHandler: SimplifiedLoginWidgetHandler, cancelLoginHandler: SimplifiedLoginWidgetHandler) => unknown;
|
|
118
|
+
export declare const hasOpenSimplifiedLoginWidget: (targetWindow: Window) => targetWindow is Window & {
|
|
119
|
+
openSimplifiedLoginWidget: OpenSimplifiedLoginWidget;
|
|
120
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AccountBaseConfig } from './common';
|
|
2
|
+
import { SessionUserId } from './session';
|
|
3
|
+
/**
|
|
4
|
+
* Result returned by the Session Service `/hasAccess` endpoint, describing whether the user
|
|
5
|
+
* is entitled to a requested set of products/features.
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export interface HasAccessResult {
|
|
9
|
+
/** Whether the user is entitled to at least one of the requested products/features. */
|
|
10
|
+
entitled: boolean;
|
|
11
|
+
/** How long this result stays valid, in seconds, before the cache entry expires. */
|
|
12
|
+
ttl: number;
|
|
13
|
+
allowedFeatures: string[];
|
|
14
|
+
userId: SessionUserId;
|
|
15
|
+
uuid: string;
|
|
16
|
+
sig: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Options accepted by the {@link Monetization} constructor.
|
|
20
|
+
*/
|
|
21
|
+
export type MonetizationOptions = Pick<AccountBaseConfig, 'clientId' | 'env' | 'window'> & Partial<Pick<AccountBaseConfig, 'redirectUri' | 'sessionDomain'>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ConnectedSessionResponse, ConnectedSessionWithUserIdResponse, SessionFailureResponse, SessionResponse, SessionSuccessResponse, UnrecognizedSessionResponse } from './session.js';
|
|
2
|
+
type SessionObjectResponse = SessionSuccessResponse | SessionFailureResponse | UnrecognizedSessionResponse;
|
|
3
|
+
type RedirectSessionPayload = {
|
|
4
|
+
redirectURL: string;
|
|
5
|
+
};
|
|
6
|
+
export type NormalizedSessionPayload = SessionObjectResponse | RedirectSessionPayload;
|
|
7
|
+
export declare function isSessionSuccessResponse(value: unknown): value is SessionSuccessResponse;
|
|
8
|
+
export declare function isConnectedSessionResponse(value: unknown): value is ConnectedSessionResponse;
|
|
9
|
+
export declare function isSessionFailureResponse(value: unknown): value is SessionFailureResponse;
|
|
10
|
+
export declare function isRedirectSessionPayload(value: unknown): value is RedirectSessionPayload;
|
|
11
|
+
export declare function isConnectedSessionWithUserIdResponse(value: SessionResponse): value is ConnectedSessionWithUserIdResponse;
|
|
12
|
+
/**
|
|
13
|
+
* Converts an unknown Session Service `hasSession` payload into one of the shapes the SDK knows how
|
|
14
|
+
* to handle.
|
|
15
|
+
*
|
|
16
|
+
* This function is intentionally tolerant because `hasSession()` historically resolved unknown
|
|
17
|
+
* object payloads instead of rejecting them. The SDK relies on that behavior for backwards
|
|
18
|
+
* compatibility with clients that check the raw response themselves.
|
|
19
|
+
*
|
|
20
|
+
* The normal cases are:
|
|
21
|
+
* - regular success payloads with a boolean `result`;
|
|
22
|
+
* - failure payloads wrapped as `{ error, response? }`;
|
|
23
|
+
* - Safari/session-refresh redirect payloads shaped as `{ redirectURL }`.
|
|
24
|
+
*
|
|
25
|
+
* Any other object is preserved as an unrecognized response so callers can still receive it.
|
|
26
|
+
* Non-object values are normalized to `{}`, matching the old "empty response" fallback used by
|
|
27
|
+
* `hasSession()` and cached-session reads.
|
|
28
|
+
*
|
|
29
|
+
* This is used both for network responses parsed by `RESTClient` and for values restored from the
|
|
30
|
+
* session cache, so the rest of the Identity flow can switch on typed guards instead of repeatedly
|
|
31
|
+
* re-validating unknown data.
|
|
32
|
+
*
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function normalizeSessionResponse(value: unknown): NormalizedSessionPayload;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User identifier returned by Session Service responses.
|
|
3
|
+
*
|
|
4
|
+
* Session Service historically returned numeric ids, while some integrations and tests use
|
|
5
|
+
* string ids. SDK convenience methods normalize this where they promise a string.
|
|
6
|
+
*/
|
|
7
|
+
export type SessionUserId = number | string;
|
|
8
|
+
/**
|
|
9
|
+
* Successful response returned from {@link Identity#hasSession}.
|
|
10
|
+
*
|
|
11
|
+
* `result` means the has-session call itself succeeded. `result: true` means the user is
|
|
12
|
+
* connected to the merchant; `result: false` means a session may exist, but the user is not
|
|
13
|
+
* connected to this client.
|
|
14
|
+
*/
|
|
15
|
+
export type SessionSuccessResponse = {
|
|
16
|
+
/** Response status code. Example: 200. */
|
|
17
|
+
code?: number;
|
|
18
|
+
/** Response type. Example: 'OK'. */
|
|
19
|
+
type?: string;
|
|
20
|
+
/** Human-readable response description. Example: 'OK'. */
|
|
21
|
+
description?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Is the user connected to the merchant? This means the merchant id is in the list of
|
|
24
|
+
* merchants connected to this user.
|
|
25
|
+
*/
|
|
26
|
+
result: boolean;
|
|
27
|
+
/** Connection status string. Deprecated; use `Identity.isConnected()`. Example: 'connected'. */
|
|
28
|
+
userStatus?: string;
|
|
29
|
+
/** Cookie base domain used as the `SP_ID` cookie domain fallback. Example: 'spid.no'. */
|
|
30
|
+
baseDomain?: string;
|
|
31
|
+
/** Legacy session id. Obsolete. Example: '58eca10fdbb9f6df72c3368f'. */
|
|
32
|
+
id?: string;
|
|
33
|
+
/** A numeric user id which is unique per realm (country). Example: 37162 */
|
|
34
|
+
userId?: SessionUserId;
|
|
35
|
+
/** Globally unique user id. Example: 'b3b23aa7-34f2-5d02-a10e-5a3455c6ab2c' */
|
|
36
|
+
uuid?: string;
|
|
37
|
+
/** Session token used for the `SP_ID` cookie. Example: 'eyJjbGllbnRfaWQ...'. */
|
|
38
|
+
sp_id?: string;
|
|
39
|
+
/** Session response TTL in seconds. Example: 300. */
|
|
40
|
+
expiresIn?: number;
|
|
41
|
+
/** Server time as a Unix timestamp in seconds. Example: 1506285759. */
|
|
42
|
+
serverTime?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Example: 'NCdzXaz4ZRb7...' The sig parameter is a concatenation of an HMAC SHA-256
|
|
45
|
+
* signature string, a dot (.) and a base64url encoded JSON object (session).
|
|
46
|
+
* {@link http://techdocs.spid.no/sdks/js/response-signature-and-validation/}
|
|
47
|
+
*/
|
|
48
|
+
sig?: string;
|
|
49
|
+
/** User display name. Example: 'batman'. */
|
|
50
|
+
displayName?: string;
|
|
51
|
+
/** User given name. Example: 'Bruce'. */
|
|
52
|
+
givenName?: string;
|
|
53
|
+
/** User family name. Example: 'Wayne'. */
|
|
54
|
+
familyName?: string;
|
|
55
|
+
/** User gender value. Example: 'male', 'female', 'undisclosed'. */
|
|
56
|
+
gender?: string;
|
|
57
|
+
/** User profile photo URL. Example: 'http://www.srv.com/some/picture.jpg' . */
|
|
58
|
+
photo?: string;
|
|
59
|
+
/** Whether tracking is enabled for this session. Example: true. */
|
|
60
|
+
tracking?: boolean;
|
|
61
|
+
/** Whether the client agreement is accepted. Example: true. */
|
|
62
|
+
clientAgreementAccepted?: boolean;
|
|
63
|
+
/** Whether the default agreement is accepted. Example: true. */
|
|
64
|
+
defaultAgreementAccepted?: boolean;
|
|
65
|
+
/** Pairwise user id for this client. Example: 'b2a23caa...'. */
|
|
66
|
+
pairId?: string;
|
|
67
|
+
/** User SDRN. Example: 'sdrn:spid.no:user:12345'. */
|
|
68
|
+
sdrn?: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Successful has-session response for a user connected to the merchant.
|
|
72
|
+
*/
|
|
73
|
+
export type ConnectedSessionResponse = SessionSuccessResponse & {
|
|
74
|
+
result: true;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Connected session response that also carries a usable user id.
|
|
78
|
+
*/
|
|
79
|
+
export type ConnectedSessionWithUserIdResponse = ConnectedSessionResponse & {
|
|
80
|
+
userId: SessionUserId;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Failure payload returned by Session Service.
|
|
84
|
+
*
|
|
85
|
+
* API and network failures usually reject with {@link SDKError}; this shape represents a failure
|
|
86
|
+
* payload when one is returned by Session Service and reaches the has-session flow.
|
|
87
|
+
*/
|
|
88
|
+
export type SessionFailureResponse = {
|
|
89
|
+
/** Failure payload returned by Session Service. Usually an object, but tests also pass strings. */
|
|
90
|
+
error: string | number | boolean | object;
|
|
91
|
+
response?: {
|
|
92
|
+
/** Response status code. Example: 404. */
|
|
93
|
+
code: number;
|
|
94
|
+
/** Response type. Example: 'NOT_FOUND'. */
|
|
95
|
+
type: string;
|
|
96
|
+
/** Human-readable response description. Example: 'No session found'. */
|
|
97
|
+
description: string;
|
|
98
|
+
/** Cookie base domain used as the `SP_ID` cookie domain fallback. Example: 'spid.no'. */
|
|
99
|
+
baseDomain?: string;
|
|
100
|
+
/** Time span in milliseconds. Example: 30 * 60 * 1000 (for 30 minutes) */
|
|
101
|
+
expiresIn?: number;
|
|
102
|
+
result?: boolean;
|
|
103
|
+
/** Server time in seconds since the Unix Epoch. Example: 1506287788 */
|
|
104
|
+
serverTime?: number;
|
|
105
|
+
[key: string]: string | number | boolean | object | null | undefined;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Object response that does not match one of the SDK-known has-session shapes.
|
|
110
|
+
*
|
|
111
|
+
* This intentionally includes `{}`. Historically `hasSession()` could resolve an empty object or
|
|
112
|
+
* other object payloads that callers inspected themselves, so the SDK preserves those responses.
|
|
113
|
+
*/
|
|
114
|
+
export type UnrecognizedSessionResponse = object;
|
|
115
|
+
export type RedirectSessionResponse = string;
|
|
116
|
+
export type SessionObjectResponse = SessionSuccessResponse | SessionFailureResponse | UnrecognizedSessionResponse;
|
|
117
|
+
export type RedirectSessionPayload = {
|
|
118
|
+
redirectURL: string;
|
|
119
|
+
};
|
|
120
|
+
export type NormalizedSessionPayload = SessionObjectResponse | RedirectSessionPayload;
|
|
121
|
+
/**
|
|
122
|
+
* Public response union returned from {@link Identity#hasSession}.
|
|
123
|
+
*/
|
|
124
|
+
export type SessionResponse = SessionSuccessResponse | SessionFailureResponse | UnrecognizedSessionResponse | RedirectSessionResponse;
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const version = "6.0.0-alpha.
|
|
1
|
+
declare const version = "6.0.0-alpha.4";
|
|
2
2
|
export default version;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schibsted/account-sdk-browser",
|
|
3
|
-
"version": "6.0.0-alpha.
|
|
3
|
+
"version": "6.0.0-alpha.4",
|
|
4
4
|
"description": "Schibsted account SDK for browsers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,14 +8,6 @@
|
|
|
8
8
|
".": {
|
|
9
9
|
"default": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts"
|
|
11
|
-
},
|
|
12
|
-
"./identity": {
|
|
13
|
-
"default": "./dist/identity.js",
|
|
14
|
-
"types": "./dist/identity.d.ts"
|
|
15
|
-
},
|
|
16
|
-
"./monetization": {
|
|
17
|
-
"default": "./dist/monetization.js",
|
|
18
|
-
"types": "./dist/monetization.d.ts"
|
|
19
11
|
}
|
|
20
12
|
},
|
|
21
13
|
"scripts": {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.
|
|
2
|
+
* See LICENSE.md in the project root.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Account } from './account.js';
|
|
6
|
+
import { resolveBrowserWindow } from './resolve-browser-window.js';
|
|
7
|
+
import type { AccountConfig } from './types/account.js';
|
|
8
|
+
|
|
9
|
+
const ACCOUNT_READY_EVENT = 'schAccount:ready';
|
|
10
|
+
const GET_ACCOUNT_SDK_TIMEOUT_MS = 4000;
|
|
11
|
+
|
|
12
|
+
let pendingAccountPromise: Promise<Account> | undefined;
|
|
13
|
+
|
|
14
|
+
const createUnavailableError = (): Error =>
|
|
15
|
+
new Error('Schibsted Account SDK is not available in this browser context');
|
|
16
|
+
|
|
17
|
+
const createTimeoutError = (): Error =>
|
|
18
|
+
new Error(`Schibsted Account SDK was not initialized within ${GET_ACCOUNT_SDK_TIMEOUT_MS} ms`);
|
|
19
|
+
|
|
20
|
+
export function createAccountSdk(config: AccountConfig): Account {
|
|
21
|
+
return new Account(config);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getAccountSdk(): Promise<Account> {
|
|
25
|
+
const browserWindow = resolveBrowserWindow();
|
|
26
|
+
|
|
27
|
+
if (!browserWindow) {
|
|
28
|
+
const error = createUnavailableError();
|
|
29
|
+
console.error(error.message);
|
|
30
|
+
return Promise.reject(error);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (browserWindow.schAccount) {
|
|
34
|
+
return Promise.resolve(browserWindow.schAccount);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (pendingAccountPromise) {
|
|
38
|
+
return pendingAccountPromise;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pendingAccountPromise = new Promise<Account>((resolve, reject) => {
|
|
42
|
+
let timeoutId: number | undefined;
|
|
43
|
+
|
|
44
|
+
const cleanup = () => {
|
|
45
|
+
browserWindow.removeEventListener(ACCOUNT_READY_EVENT, resolveRegisteredAccount);
|
|
46
|
+
if (timeoutId !== undefined) {
|
|
47
|
+
browserWindow.clearTimeout(timeoutId);
|
|
48
|
+
}
|
|
49
|
+
pendingAccountPromise = undefined;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const resolveRegisteredAccount = () => {
|
|
53
|
+
const account = browserWindow.schAccount;
|
|
54
|
+
if (!account) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
cleanup();
|
|
59
|
+
resolve(account);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
browserWindow.addEventListener(ACCOUNT_READY_EVENT, resolveRegisteredAccount);
|
|
63
|
+
timeoutId = browserWindow.setTimeout(() => {
|
|
64
|
+
const error = createTimeoutError();
|
|
65
|
+
console.error(error.message);
|
|
66
|
+
cleanup();
|
|
67
|
+
reject(error);
|
|
68
|
+
}, GET_ACCOUNT_SDK_TIMEOUT_MS);
|
|
69
|
+
|
|
70
|
+
resolveRegisteredAccount();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return pendingAccountPromise;
|
|
74
|
+
}
|
package/src/account.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.
|
|
2
|
+
* See LICENSE.md in the project root.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { registerAndDispatchInGlobal } from './global-registry.js';
|
|
6
|
+
import Identity from './identity.js';
|
|
7
|
+
import Monetization from './monetization.js';
|
|
8
|
+
import { resolveBrowserWindow } from './resolve-browser-window.js';
|
|
9
|
+
import SDKError from './sdk-error.js';
|
|
10
|
+
import type { AccountConfig, AccountEventHandler, AccountEventName } from './types/account.js';
|
|
11
|
+
import type {
|
|
12
|
+
LoginOptions,
|
|
13
|
+
SimplifiedLoginData,
|
|
14
|
+
SimplifiedLoginWidgetLoginOptions,
|
|
15
|
+
SimplifiedLoginWidgetOptions,
|
|
16
|
+
} from './types/login.js';
|
|
17
|
+
import type { HasAccessResult } from './types/monetization.js';
|
|
18
|
+
import type { ConnectedSessionResponse, SessionResponse, SessionUserId } from './types/session.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Unified client-side interface for a configured Schibsted Account integration.
|
|
22
|
+
*/
|
|
23
|
+
export class Account {
|
|
24
|
+
#identity: Identity;
|
|
25
|
+
#monetization: Monetization;
|
|
26
|
+
|
|
27
|
+
constructor(config: AccountConfig) {
|
|
28
|
+
const browserWindow = resolveBrowserWindow(config.window);
|
|
29
|
+
|
|
30
|
+
if (!browserWindow) {
|
|
31
|
+
throw new SDKError('Schibsted Account SDK is not available in this browser context');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (browserWindow.schAccount) {
|
|
35
|
+
throw new SDKError('Schibsted Account SDK has already been initialized');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const { log, callbackBeforeRedirect, varnish } = config;
|
|
39
|
+
const sharedConfig = {
|
|
40
|
+
clientId: config.clientId,
|
|
41
|
+
redirectUri: config.redirectUri,
|
|
42
|
+
sessionDomain: config.sessionDomain,
|
|
43
|
+
env: config.env,
|
|
44
|
+
window: browserWindow,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
this.#identity = new Identity({
|
|
48
|
+
...sharedConfig,
|
|
49
|
+
log,
|
|
50
|
+
callbackBeforeRedirect,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (varnish) {
|
|
54
|
+
if (typeof varnish !== 'object' || Array.isArray(varnish)) {
|
|
55
|
+
throw new SDKError('Account varnish config must be an object');
|
|
56
|
+
}
|
|
57
|
+
this.#identity.enableVarnishCookie(varnish);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.#monetization = new Monetization(sharedConfig);
|
|
61
|
+
|
|
62
|
+
registerAndDispatchInGlobal(browserWindow, 'schAccount', this);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
hasSession(): Promise<SessionResponse> {
|
|
66
|
+
return this.#identity.hasSession();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isLoggedIn(): Promise<boolean> {
|
|
70
|
+
return this.#identity.isLoggedIn();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
isConnected(): Promise<boolean> {
|
|
74
|
+
return this.#identity.isConnected();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getUser(): Promise<ConnectedSessionResponse> {
|
|
78
|
+
return this.#identity.getUser();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getUserId(): Promise<string> {
|
|
82
|
+
return this.#identity.getUserId();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getUserSDRN(): Promise<string> {
|
|
86
|
+
return this.#identity.getUserSDRN();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getUserContextData(): Promise<SimplifiedLoginData | null> {
|
|
90
|
+
return this.#identity.getUserContextData();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getSpId(): Promise<string | null> {
|
|
94
|
+
return this.#identity.getSpId();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
login(options: LoginOptions): Window | null {
|
|
98
|
+
return this.#identity.login(options);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
logout(redirectUri?: string): void {
|
|
102
|
+
this.#identity.logout(redirectUri);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
loginUrl(options: LoginOptions): string {
|
|
106
|
+
return this.#identity.loginUrl(options);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
accountUrl(redirectUri?: string): string {
|
|
110
|
+
return this.#identity.accountUrl(redirectUri);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
showSimplifiedLoginWidget(
|
|
114
|
+
loginParams: SimplifiedLoginWidgetLoginOptions,
|
|
115
|
+
options?: SimplifiedLoginWidgetOptions,
|
|
116
|
+
): Promise<boolean> {
|
|
117
|
+
return this.#identity.showSimplifiedLoginWidget(loginParams, options);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
clearCachedUserSession(): void {
|
|
121
|
+
this.#identity.clearCachedUserSession();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
hasAccess(productIds: string[], userId: SessionUserId): Promise<HasAccessResult | null> {
|
|
125
|
+
return this.#monetization.hasAccess(productIds, userId);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {
|
|
129
|
+
this.#monetization.clearCachedAccessResult(productIds, userId);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
on(event: AccountEventName, callback: AccountEventHandler, ctx?: unknown): this {
|
|
133
|
+
if (event === 'hasAccess') {
|
|
134
|
+
this.#monetization.on(event, callback, ctx);
|
|
135
|
+
} else {
|
|
136
|
+
this.#identity.on(event, callback, ctx);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
off(event: AccountEventName, callback?: AccountEventHandler): this {
|
|
143
|
+
if (event === 'hasAccess') {
|
|
144
|
+
this.#monetization.off(event, callback);
|
|
145
|
+
} else {
|
|
146
|
+
this.#identity.off(event, callback);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export default Account;
|
package/src/cache.ts
CHANGED
package/src/global-registry.ts
CHANGED
|
@@ -3,7 +3,7 @@ import './globals.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Names of the SDK instance properties that can be registered on the global {@link Window} object.
|
|
5
5
|
*/
|
|
6
|
-
type Property = 'schIdentity' | 'schMonetization';
|
|
6
|
+
type Property = 'schAccount' | 'schIdentity' | 'schMonetization';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Registers an SDK instance on the global {@link Window} object's given property and dispatches a ready event.
|
package/src/globals.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { Account } from './account.js';
|
|
1
2
|
import type { Identity } from './identity.js';
|
|
2
3
|
import type { Monetization } from './monetization.js';
|
|
3
4
|
|
|
4
5
|
declare global {
|
|
5
6
|
interface Window {
|
|
7
|
+
schAccount?: Account;
|
|
6
8
|
schIdentity?: Identity;
|
|
7
9
|
schMonetization?: Monetization;
|
|
8
10
|
SPiD?: { Talk?: { response?: (callbackName: string, data: unknown) => unknown } };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.
|
|
2
|
+
* See LICENSE.md in the project root.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import SDKError from './sdk-error.js';
|
|
6
|
+
import type { HasAccessResult } from './types/monetization.js';
|
|
7
|
+
import { isObject, isStr } from './validate.js';
|
|
8
|
+
|
|
9
|
+
export function parseHasAccessResult(value: unknown): HasAccessResult {
|
|
10
|
+
if (!isObject(value)) {
|
|
11
|
+
throw new SDKError('Invalid hasAccess response');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { entitled, ttl, allowedFeatures, userId, uuid, sig } = value;
|
|
15
|
+
|
|
16
|
+
if (
|
|
17
|
+
typeof entitled !== 'boolean' ||
|
|
18
|
+
typeof ttl !== 'number' ||
|
|
19
|
+
!Array.isArray(allowedFeatures) ||
|
|
20
|
+
(typeof userId !== 'number' && typeof userId !== 'string') ||
|
|
21
|
+
!isStr(uuid) ||
|
|
22
|
+
!isStr(sig)
|
|
23
|
+
) {
|
|
24
|
+
throw new SDKError('Invalid hasAccess response');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
entitled,
|
|
29
|
+
ttl,
|
|
30
|
+
allowedFeatures: allowedFeatures.filter(isStr),
|
|
31
|
+
userId,
|
|
32
|
+
uuid,
|
|
33
|
+
sig,
|
|
34
|
+
};
|
|
35
|
+
}
|