@schibsted/account-sdk-browser 6.0.0-alpha.5 → 6.0.0-alpha.7

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.
@@ -2,6 +2,8 @@
2
2
  * Custom error class thrown by all SDK methods on failure.
3
3
  *
4
4
  * All rejected promises from API calls reject with an instance of this class.
5
+ *
6
+ * @group Errors
5
7
  */
6
8
  export default class SDKError extends Error {
7
9
  /** HTTP status code from the server error payload;
@@ -1,5 +1,10 @@
1
1
  import { AccountBaseConfig, LogFunction } from './common';
2
2
  import { IdentityBeforeRedirectCallback, VarnishCookieOptions } from './identity';
3
+ /**
4
+ * Configuration used to create an {@link Account} instance.
5
+ *
6
+ * @group Configuration
7
+ */
3
8
  export type AccountConfig = AccountBaseConfig & {
4
9
  /** Receives debug log information. If not set, no logging will be done. */
5
10
  log?: LogFunction;
@@ -8,14 +13,31 @@ export type AccountConfig = AccountBaseConfig & {
8
13
  /** Optional Varnish cookie setup applied during Account initialization. */
9
14
  varnish?: VarnishCookieOptions;
10
15
  };
16
+ type LoginEventDetail = {
17
+ url: string;
18
+ method: 'popup' | 'default';
19
+ };
20
+ type LogoutEventDetail = {
21
+ url: string;
22
+ };
23
+ export type AccountEventMap = {
24
+ /** Emitted with the login URL and method when `login()` initiates a login flow. */
25
+ login: CustomEvent<LoginEventDetail>;
26
+ /** Emitted with the logout URL when `logout()` is called. */
27
+ logout: CustomEvent<LogoutEventDetail>;
28
+ /** Emitted when the simplified login widget is displayed. */
29
+ simplifiedLoginOpened: Event;
30
+ /** Emitted when the simplified login widget is closed. */
31
+ simplifiedLoginCancelled: Event;
32
+ };
33
+ /** Account event names emitted by the SDK. */
34
+ export type AccountEventName = keyof AccountEventMap;
11
35
  /**
12
- * Identity events emitted by the SDK.
36
+ * Native event listener used by Account event subscriptions.
37
+ *
38
+ * Payload-bearing events are `CustomEvent` instances and expose their payload through `detail`.
13
39
  *
14
- * - `login`: emitted when `hasSession()` resolves with a logged-in user payload.
15
- * - `logout`: emitted when a previously logged-in user is no longer logged in, or when
16
- * `logout()` is called.
17
- * - `simplifiedLoginOpened`: emitted when the simplified login widget is displayed.
18
- * - `simplifiedLoginCancelled`: emitted when the simplified login widget is closed.
40
+ * @group Events
19
41
  */
20
- export type AccountEventName = 'login' | 'logout' | 'simplifiedLoginOpened' | 'simplifiedLoginCancelled';
21
- export type AccountEventHandler = (...args: unknown[]) => void;
42
+ export type AccountEventListener<EventName extends AccountEventName = AccountEventName> = (event: AccountEventMap[EventName]) => void;
43
+ export {};
@@ -1,13 +1,19 @@
1
1
  /**
2
2
  * Log callback used by the SDK for debug output.
3
3
  * Receives a pre-formatted log line.
4
- * @internal
4
+ *
5
+ * @group Configuration
5
6
  */
6
7
  export type LogFunction = (message: string) => void;
7
8
  /**
8
9
  * Supported Schibsted account environment keys.
10
+ *
11
+ * @group Configuration
9
12
  */
10
13
  export type AccountEnvironment = 'LOCAL' | 'DEV' | 'PRE' | 'PRO' | 'PRO_NO' | 'PRO_FI' | 'PRO_DK';
14
+ /**
15
+ * Shared Account configuration fields.
16
+ */
11
17
  export type AccountBaseConfig = {
12
18
  /** Mandatory client id. Example: "1234567890abcdef12345678" */
13
19
  clientId: string;
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Options accepted by {@link Identity#login} and related login URL helpers.
2
+ * Options accepted by {@link Account#login} and related login URL helpers.
3
+ *
4
+ * @group Login & Widget
3
5
  */
4
6
  export type LoginOptions = {
5
7
  /**
@@ -8,14 +10,11 @@ export type LoginOptions = {
8
10
  */
9
11
  state: string;
10
12
  /**
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.
13
+ * Authentication Context Class Reference values. If omitted, the default account flow is used.
14
+ * Supported values include `password`, `otp`, `sms`, `otp-email`, `eid`, `eid-no`, `eid-se`,
15
+ * `eid-fi`, and `eid-dk`. Values other than `otp-email` may be combined as a space-separated
16
+ * string. Verify the AMR (Authentication Methods References) claim in the ID token on your
17
+ * backend if you need to enforce a completed authentication method.
19
18
  */
20
19
  acrValues?: 'password' | 'otp' | 'sms' | 'eid-dk' | 'eid-no' | 'eid-se' | 'eid-fi' | 'eid' | 'otp-email' | (string & {});
21
20
  /**
@@ -70,6 +69,8 @@ export type LoginOptions = {
70
69
  /**
71
70
  * Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;
72
71
  * all other fields reuse the `LoginOptions` documentation.
72
+ *
73
+ * @group Login & Widget
73
74
  */
74
75
  export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
75
76
  /**
@@ -80,9 +81,11 @@ export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
80
81
  };
81
82
  /**
82
83
  * Minimal user information used by the simplified login widget flow.
84
+ *
85
+ * @group Login & Widget
83
86
  */
84
87
  export type SimplifiedLoginData = {
85
- /** Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login} */
88
+ /** Deprecated: User UUID used as `loginHint` for {@link Account#login}. */
86
89
  identifier: string;
87
90
  /** Human-readable user identifier */
88
91
  display_text: string;
@@ -92,7 +95,9 @@ export type SimplifiedLoginData = {
92
95
  provider_id?: string;
93
96
  };
94
97
  /**
95
- * Configuration options for {@link Identity#showSimplifiedLoginWidget}.
98
+ * Configuration options for {@link Account#showSimplifiedLoginWidget}.
99
+ *
100
+ * @group Login & Widget
96
101
  */
97
102
  export type SimplifiedLoginWidgetOptions = {
98
103
  /** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */
@@ -3,16 +3,21 @@ import { SessionUserId } from './session';
3
3
  /**
4
4
  * Result returned by the Session Service `/hasAccess` endpoint, describing whether the user
5
5
  * is entitled to a requested set of products/features.
6
- * @internal
6
+ *
7
+ * @group Access Checks
7
8
  */
8
9
  export interface HasAccessResult {
9
10
  /** Whether the user is entitled to at least one of the requested products/features. */
10
11
  entitled: boolean;
11
12
  /** How long this result stays valid, in seconds, before the cache entry expires. */
12
13
  ttl: number;
14
+ /** Feature ids the user is allowed to access. */
13
15
  allowedFeatures: string[];
16
+ /** User id the access result belongs to. */
14
17
  userId: SessionUserId;
18
+ /** Globally unique user id the access result belongs to. */
15
19
  uuid: string;
20
+ /** Signed response payload. */
16
21
  sig: string;
17
22
  }
18
23
  /**
@@ -3,14 +3,18 @@
3
3
  *
4
4
  * Session Service historically returned numeric ids, while some integrations and tests use
5
5
  * string ids. SDK convenience methods normalize this where they promise a string.
6
+ *
7
+ * @group Session
6
8
  */
7
9
  export type SessionUserId = number | string;
8
10
  /**
9
- * Successful response returned from {@link Identity#hasSession}.
11
+ * Successful response returned from {@link Account#hasSession}.
10
12
  *
11
13
  * `result` means the has-session call itself succeeded. `result: true` means the user is
12
14
  * connected to the merchant; `result: false` means a session may exist, but the user is not
13
15
  * connected to this client.
16
+ *
17
+ * @group Session
14
18
  */
15
19
  export type SessionSuccessResponse = {
16
20
  /** Response status code. Example: 200. */
@@ -24,7 +28,7 @@ export type SessionSuccessResponse = {
24
28
  * merchants connected to this user.
25
29
  */
26
30
  result: boolean;
27
- /** Connection status string. Deprecated; use `Identity.isConnected()`. Example: 'connected'. */
31
+ /** Connection status string. Deprecated; use `Account.isConnected()`. Example: 'connected'. */
28
32
  userStatus?: string;
29
33
  /** Cookie base domain used as the `SP_ID` cookie domain fallback. Example: 'spid.no'. */
30
34
  baseDomain?: string;
@@ -69,12 +73,16 @@ export type SessionSuccessResponse = {
69
73
  };
70
74
  /**
71
75
  * Successful has-session response for a user connected to the merchant.
76
+ *
77
+ * @group Session
72
78
  */
73
79
  export type ConnectedSessionResponse = SessionSuccessResponse & {
74
80
  result: true;
75
81
  };
76
82
  /**
77
83
  * Connected session response that also carries a usable user id.
84
+ *
85
+ * @group Session
78
86
  */
79
87
  export type ConnectedSessionWithUserIdResponse = ConnectedSessionResponse & {
80
88
  userId: SessionUserId;
@@ -84,6 +92,8 @@ export type ConnectedSessionWithUserIdResponse = ConnectedSessionResponse & {
84
92
  *
85
93
  * API and network failures usually reject with {@link SDKError}; this shape represents a failure
86
94
  * payload when one is returned by Session Service and reaches the has-session flow.
95
+ *
96
+ * @group Session
87
97
  */
88
98
  export type SessionFailureResponse = {
89
99
  /** Failure payload returned by Session Service. Usually an object, but tests also pass strings. */
@@ -110,15 +120,30 @@ export type SessionFailureResponse = {
110
120
  *
111
121
  * This intentionally includes `{}`. Historically `hasSession()` could resolve an empty object or
112
122
  * other object payloads that callers inspected themselves, so the SDK preserves those responses.
123
+ *
124
+ * @group Session
113
125
  */
114
126
  export type UnrecognizedSessionResponse = object;
127
+ /**
128
+ * Redirect URL returned by `hasSession()` when Session Service needs a full-page session refresh.
129
+ *
130
+ * @group Session
131
+ */
115
132
  export type RedirectSessionResponse = string;
116
133
  export type SessionObjectResponse = SessionSuccessResponse | SessionFailureResponse | UnrecognizedSessionResponse;
117
134
  export type RedirectSessionPayload = {
118
135
  redirectURL: string;
119
136
  };
137
+ /**
138
+ * Internal shape returned by `normalizeSessionResponse()` before `hasSession()` post-processing.
139
+ *
140
+ * It includes regular Session Service object responses and redirect responses used for full-page
141
+ * session refresh.
142
+ */
120
143
  export type NormalizedSessionPayload = SessionObjectResponse | RedirectSessionPayload;
121
144
  /**
122
- * Public response union returned from {@link Identity#hasSession}.
145
+ * Public response union returned from {@link Account#hasSession}.
146
+ *
147
+ * @group Session
123
148
  */
124
149
  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.5";
1
+ declare const version = "6.0.0-alpha.7";
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.5",
3
+ "version": "6.0.0-alpha.7",
4
4
  "description": "Schibsted account SDK for browsers",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -28,9 +28,6 @@
28
28
  },
29
29
  "author": "",
30
30
  "license": "MIT",
31
- "dependencies": {
32
- "tiny-emitter": "^2.1.0"
33
- },
34
31
  "devDependencies": {
35
32
  "@biomejs/biome": "2.4.15",
36
33
  "@vitest/coverage-v8": "^4.1.7",
@@ -17,10 +17,28 @@ const createUnavailableError = (): Error =>
17
17
  const createTimeoutError = (): Error =>
18
18
  new Error(`Schibsted Account SDK was not initialized within ${GET_ACCOUNT_SDK_TIMEOUT_MS} ms`);
19
19
 
20
+ /**
21
+ * Creates and registers the single Account SDK instance for the current browser window.
22
+ *
23
+ * The created instance is stored on `window.schAccount` and the SDK emits
24
+ * `schAccount:ready` with the instance in `event.detail.instance`.
25
+ *
26
+ * @param config - Client, redirect, environment, and Session Service configuration.
27
+ * @throws {SDKError} If the SDK cannot run in the current browser context, if an Account instance
28
+ * has already been initialized, or if configuration validation fails.
29
+ * @group Core API
30
+ */
20
31
  export function createAccountSdk(config: AccountConfig): Account {
21
32
  return new Account(config);
22
33
  }
23
34
 
35
+ /**
36
+ * Resolves the Account SDK instance registered by `createAccountSdk()`.
37
+ *
38
+ * If the instance already exists, the promise resolves immediately. Otherwise it waits for
39
+ * `schAccount:ready` and rejects if initialization does not happen within the SDK timeout.
40
+ * @group Core API
41
+ */
24
42
  export function getAccountSdk(): Promise<Account> {
25
43
  const browserWindow = resolveBrowserWindow();
26
44
 
package/src/account.ts CHANGED
@@ -6,7 +6,7 @@ import Identity from './identity.js';
6
6
  import Monetization from './monetization.js';
7
7
  import { resolveBrowserWindow } from './resolve-browser-window.js';
8
8
  import SDKError from './sdk-error.js';
9
- import type { AccountConfig, AccountEventHandler, AccountEventName } from './types/account.js';
9
+ import type { AccountConfig, AccountEventListener, AccountEventName } from './types/account.js';
10
10
  import type {
11
11
  LoginOptions,
12
12
  SimplifiedLoginData,
@@ -18,6 +18,12 @@ import type { ConnectedSessionResponse, SessionResponse, SessionUserId } from '.
18
18
 
19
19
  /**
20
20
  * Unified client-side interface for a configured Schibsted Account integration.
21
+ *
22
+ * Create an instance with `createAccountSdk()` unless you explicitly need to construct it
23
+ * yourself. The instance coordinates identity, login, session, and access-check features for one
24
+ * configured client.
25
+ *
26
+ * @group Core API
21
27
  */
22
28
  export class Account {
23
29
  #identity: Identity;
@@ -64,58 +70,150 @@ export class Account {
64
70
  );
65
71
  }
66
72
 
73
+ /**
74
+ * Queries Session Service and returns the current browser session state.
75
+ *
76
+ * This call may trigger a full-page session refresh redirect. Configure
77
+ * `callbackBeforeRedirect` if your app needs to persist state before that navigation.
78
+ *
79
+ * @throws {SDKError} If the Session Service call fails.
80
+ */
67
81
  hasSession(): Promise<SessionResponse> {
68
82
  return this.#identity.hasSession();
69
83
  }
70
84
 
85
+ /**
86
+ * Checks whether the browser currently has a Schibsted Account session.
87
+ *
88
+ * Returns `false` instead of throwing when the session lookup fails.
89
+ */
71
90
  isLoggedIn(): Promise<boolean> {
72
91
  return this.#identity.isLoggedIn();
73
92
  }
74
93
 
94
+ /**
95
+ * Checks whether the current user is connected to the configured client.
96
+ *
97
+ * A user can be logged in to Schibsted Account without being connected to your client, for
98
+ * example before accepting required terms.
99
+ */
75
100
  isConnected(): Promise<boolean> {
76
101
  return this.#identity.isConnected();
77
102
  }
78
103
 
104
+ /**
105
+ * Returns the connected user session data.
106
+ *
107
+ * @throws {SDKError} If the user is not connected to the configured client.
108
+ */
79
109
  getUser(): Promise<ConnectedSessionResponse> {
80
110
  return this.#identity.getUser();
81
111
  }
82
112
 
113
+ /**
114
+ * Returns the realm-specific Schibsted Account user id as a string.
115
+ *
116
+ * Use `getUserUuid()` when you need the globally unique user id.
117
+ *
118
+ * @throws {SDKError} If the user is not connected to the configured client.
119
+ */
83
120
  getUserId(): Promise<string> {
84
121
  return this.#identity.getUserId();
85
122
  }
86
123
 
124
+ /**
125
+ * Returns the globally unique user id from the current session.
126
+ *
127
+ * @throws {SDKError} If the user is not connected to the configured client.
128
+ */
87
129
  getUserUuid(): Promise<string> {
88
130
  return this.#identity.getUserUuid();
89
131
  }
90
132
 
133
+ /**
134
+ * Returns the user SDRN from the current session.
135
+ *
136
+ * @throws {SDKError} If the SDRN is missing from the session response.
137
+ */
91
138
  getUserSDRN(): Promise<string> {
92
139
  return this.#identity.getUserSDRN();
93
140
  }
94
141
 
142
+ /**
143
+ * Returns minimal user context for simplified login prompts.
144
+ *
145
+ * Returns `null` if the global account session cannot be read.
146
+ */
95
147
  getUserContextData(): Promise<SimplifiedLoginData | null> {
96
148
  return this.#identity.getUserContextData();
97
149
  }
98
150
 
151
+ /**
152
+ * Returns the Varnish `sp_id` value from the current session when present.
153
+ */
99
154
  getSpId(): Promise<string | null> {
100
155
  return this.#identity.getSpId();
101
156
  }
102
157
 
158
+ /**
159
+ * Starts the login flow with either a full-page redirect or a popup.
160
+ *
161
+ * Call this from a user gesture when `preferPopup` is enabled, otherwise browser popup blockers
162
+ * may block the popup and the SDK will fall back to redirect navigation.
163
+ *
164
+ * @param options - Login URL parameters.
165
+ * @returns A popup window reference when a popup is opened; otherwise `null`.
166
+ */
103
167
  login(options: LoginOptions): Window | null {
104
168
  return this.#identity.login(options);
105
169
  }
106
170
 
171
+ /**
172
+ * Logs the user out from the brand Session Service session and redirects the browser.
173
+ *
174
+ * @param redirectUri - Where Session Service should redirect the browser after logout.
175
+ */
107
176
  logout(redirectUri?: string): void {
108
177
  this.#identity.logout(redirectUri);
109
178
  }
110
179
 
180
+ /**
181
+ * Builds the login URL without navigating the browser.
182
+ *
183
+ * @param options - Login URL parameters.
184
+ */
111
185
  loginUrl(options: LoginOptions): string {
112
186
  return this.#identity.loginUrl(options);
113
187
  }
114
188
 
189
+ /**
190
+ * Builds the logout URL without navigating the browser.
191
+ *
192
+ * @param redirectUri - Where Session Service should redirect the browser after logout.
193
+ */
194
+ logoutUrl(redirectUri?: string): string {
195
+ return this.#identity.logoutUrl(redirectUri);
196
+ }
197
+
198
+ /**
199
+ * Builds the Schibsted Account profile page URL.
200
+ *
201
+ * @param redirectUri - Where the account page should redirect the browser afterwards.
202
+ */
115
203
  accountUrl(redirectUri?: string): string {
116
204
  return this.#identity.accountUrl(redirectUri);
117
205
  }
118
206
 
207
+ /**
208
+ * Loads and displays the simplified login widget when user context is available.
209
+ *
210
+ * Your application decides how often to call this method. The `state` field in `loginParams`
211
+ * may be a string or a function that resolves to a string.
212
+ * Widget open and cancel events can be observed with `on()`.
213
+ *
214
+ * @returns `true` when the widget was displayed.
215
+ * @throws {SDKError} If user context data is missing or the widget script cannot be loaded.
216
+ */
119
217
  showSimplifiedLoginWidget(
120
218
  loginParams: SimplifiedLoginWidgetLoginOptions,
121
219
  options?: SimplifiedLoginWidgetOptions,
@@ -123,26 +221,78 @@ export class Account {
123
221
  return this.#identity.showSimplifiedLoginWidget(loginParams, options);
124
222
  }
125
223
 
224
+ /**
225
+ * Enables or disables caching for subsequent session lookups.
226
+ *
227
+ * Changing this setting does not remove an existing cached session.
228
+ */
229
+ setSessionCachingEnabled(enabled: boolean): void {
230
+ this.#identity.setSessionCachingEnabled(enabled);
231
+ }
232
+
233
+ /**
234
+ * Removes the cached Session Service user session response.
235
+ */
126
236
  clearCachedUserSession(): void {
127
237
  this.#identity.clearCachedUserSession();
128
238
  }
129
239
 
240
+ /**
241
+ * Checks whether a user has access to any of the requested products or features.
242
+ *
243
+ * Results are cached according to the TTL returned by Session Service.
244
+ *
245
+ * @param productIds - Product or feature ids to check.
246
+ * @param userId - Current user id, usually from `getUserId()`.
247
+ * @returns Access data, or `null` when the user is not entitled.
248
+ * @throws {SDKError} If `sessionDomain` is missing, input is invalid, or the request fails.
249
+ */
130
250
  hasAccess(productIds: string[], userId: SessionUserId): Promise<HasAccessResult | null> {
131
251
  return this.#monetization.hasAccess(productIds, userId);
132
252
  }
133
253
 
254
+ /**
255
+ * Removes a cached access-check result.
256
+ *
257
+ * @param productIds - Product or feature ids used for the cached lookup.
258
+ * @param userId - User id used for the cached lookup.
259
+ */
134
260
  clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {
135
261
  this.#monetization.clearCachedAccessResult(productIds, userId);
136
262
  }
137
263
 
138
- on(event: AccountEventName, callback: AccountEventHandler, ctx?: unknown): this {
139
- this.#identity.on(event, callback, ctx);
264
+ /**
265
+ * Subscribes to Account events.
266
+ *
267
+ * Supported event names are defined by {@link AccountEventName}.
268
+ *
269
+ * @param event - Event name.
270
+ * @param listener - Listener that receives an `Event` or `CustomEvent`.
271
+ */
272
+ on<EventName extends AccountEventName>(
273
+ event: EventName,
274
+ listener: AccountEventListener<EventName>,
275
+ ): this;
276
+ on(event: AccountEventName, listener: EventListener): this {
277
+ this.#identity.addEventListener(event, listener);
140
278
 
141
279
  return this;
142
280
  }
143
281
 
144
- off(event: AccountEventName, callback?: AccountEventHandler): this {
145
- this.#identity.off(event, callback);
282
+ /**
283
+ * Unsubscribes from Account events.
284
+ *
285
+ * Supported event names are defined by {@link AccountEventName}.
286
+ *
287
+ * @param event - Event name.
288
+ * @param listener - Listener to remove.
289
+ */
290
+ off<EventName extends AccountEventName>(
291
+ event: EventName,
292
+ listener: AccountEventListener<EventName>,
293
+ ): this;
294
+ off(event: AccountEventName, listener: EventListener): this {
295
+ this.#identity.removeEventListener(event, listener);
146
296
 
147
297
  return this;
148
298
  }