@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.
@@ -2,18 +2,14 @@
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
- import { ENDPOINTS } from './config.js';
8
- import { registerAndDispatchInGlobal } from './global-registry.js';
9
6
  import { parseHasAccessResult } from './has-access-response.js';
10
- import type { SessionUserId } from './identity.js';
11
7
  import type RESTClient from './rest-client.js';
12
8
  import { buildClientSdrn, createAccountRestClient } from './rest-clients.js';
13
9
  import SDKError from './sdk-error.js';
14
10
  import * as spidTalk from './spid-talk.js';
15
11
  import type { HasAccessResult, MonetizationOptions } from './types/monetization.js';
16
- import { urlMapper } from './url.js';
12
+ import type { SessionUserId } from './types/session.js';
17
13
  import { assert, isNonEmptyString, isStr, isUrl } from './validate.js';
18
14
  import version from './version.js';
19
15
 
@@ -22,14 +18,10 @@ const globalWindow = () => window;
22
18
  /**
23
19
  * Provides features related to monetization
24
20
  */
25
- export class Monetization extends TinyEmitter {
26
- cache: Cache;
27
- clientId: string;
28
- env: string;
29
- redirectUri?: string;
30
- _spid: RESTClient;
31
- _sessionService?: RESTClient;
32
- private pendingHasAccessRequests: Record<string, Promise<HasAccessResult>>;
21
+ export class Monetization {
22
+ private readonly cache: Cache;
23
+ private readonly sessionService?: RESTClient;
24
+ private readonly pendingHasAccessRequests: Record<string, Promise<HasAccessResult>>;
33
25
 
34
26
  /**
35
27
  * @param options - Monetization configuration
@@ -42,33 +34,25 @@ export class Monetization extends TinyEmitter {
42
34
  sessionDomain,
43
35
  window = globalWindow(),
44
36
  }: MonetizationOptions) {
45
- super();
46
37
  spidTalk.emulate(window);
47
38
  assert(isNonEmptyString(clientId), 'clientId parameter is required');
48
39
  assert(isStr(env), `env parameter is invalid: ${env}`);
40
+ const clientSdrn = buildClientSdrn(env, clientId);
49
41
 
50
42
  this.cache = new Cache(() => window && window.sessionStorage);
51
- this.clientId = clientId;
52
- this.env = env;
53
- this.redirectUri = redirectUri;
54
43
  this.pendingHasAccessRequests = {};
55
- this._spid = createAccountRestClient({
56
- serverUrl: urlMapper(env, ENDPOINTS.SPiD),
57
- defaultParams: { client_id: this.clientId, redirect_uri: this.redirectUri },
58
- });
59
44
 
60
45
  if (sessionDomain) {
61
46
  assert(isUrl(sessionDomain), 'sessionDomain parameter is not a valid URL');
62
- this._sessionService = createAccountRestClient({
47
+ this.sessionService = createAccountRestClient({
63
48
  serverUrl: sessionDomain,
64
49
  defaultParams: {
65
- client_sdrn: buildClientSdrn(this.env, this.clientId),
66
- redirect_uri: this.redirectUri,
50
+ client_sdrn: clientSdrn,
51
+ redirect_uri: redirectUri,
67
52
  sdk_version: version,
68
53
  },
69
54
  });
70
55
  }
71
- registerAndDispatchInGlobal(window, 'schMonetization', this);
72
56
  }
73
57
 
74
58
  /**
@@ -81,7 +65,7 @@ export class Monetization extends TinyEmitter {
81
65
  * doesn't have access to any of the given products/features)
82
66
  */
83
67
  async hasAccess(productIds: string[], userId: SessionUserId): Promise<HasAccessResult | null> {
84
- if (!this._sessionService) {
68
+ if (!this.sessionService) {
85
69
  throw new SDKError(`hasAccess can only be called if 'sessionDomain' is configured`);
86
70
  }
87
71
  if (!userId) {
@@ -92,11 +76,11 @@ export class Monetization extends TinyEmitter {
92
76
  }
93
77
 
94
78
  const sortedIds = [...productIds].sort();
95
- const cacheKey = this._accessCacheKey(sortedIds, userId);
79
+ const cacheKey = this.accessCacheKey(sortedIds, userId);
96
80
  let data = this.cache.get(cacheKey) as HasAccessResult | null;
97
81
  if (!data) {
98
82
  if (!this.pendingHasAccessRequests[cacheKey]) {
99
- this.pendingHasAccessRequests[cacheKey] = this._sessionService.get(
83
+ this.pendingHasAccessRequests[cacheKey] = this.sessionService.get(
100
84
  `/hasAccess/${sortedIds.join(',')}`,
101
85
  undefined,
102
86
  parseHasAccessResult,
@@ -117,7 +101,7 @@ export class Monetization extends TinyEmitter {
117
101
  if (!data.entitled) {
118
102
  return null;
119
103
  }
120
- this.emit('hasAccess', { ids: sortedIds, data });
104
+
121
105
  return data;
122
106
  }
123
107
 
@@ -127,7 +111,7 @@ export class Monetization extends TinyEmitter {
127
111
  * @param userId - id of currently logged in user
128
112
  */
129
113
  clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {
130
- this.cache.delete(this._accessCacheKey(productIds, userId));
114
+ this.cache.delete(this.accessCacheKey(productIds, userId));
131
115
  }
132
116
 
133
117
  /**
@@ -136,29 +120,9 @@ export class Monetization extends TinyEmitter {
136
120
  * @param productIds - which products/features to check
137
121
  * @param userId - id of currently logged in user
138
122
  */
139
- private _accessCacheKey(productIds: string[], userId: SessionUserId): string {
123
+ private accessCacheKey(productIds: string[], userId: SessionUserId): string {
140
124
  return `prd_${[...productIds].sort()}_${userId}`;
141
125
  }
142
-
143
- /**
144
- * Get the url for the end user to review the subscriptions
145
- * @param redirectUri
146
- * @returns - The url to the subscriptions review page
147
- */
148
- subscriptionsUrl(redirectUri: string = this.redirectUri ?? ''): string {
149
- assert(isUrl(redirectUri), `subscriptionsUrl(): redirectUri is invalid`);
150
- return this._spid.makeUrl('account/subscriptions', { redirect_uri: redirectUri });
151
- }
152
-
153
- /**
154
- * Get the url for the end user to review the products
155
- * @param redirectUri
156
- * @returns - The url to the products review page
157
- */
158
- productsUrl(redirectUri: string = this.redirectUri ?? ''): string {
159
- assert(isUrl(redirectUri), `productsUrl(): redirectUri is invalid`);
160
- return this._spid.makeUrl('account/products', { redirect_uri: redirectUri });
161
- }
162
126
  }
163
127
 
164
128
  export default Monetization;
package/src/sdk-error.ts CHANGED
@@ -14,6 +14,8 @@ const STRINGIFY_TYPES = ['boolean', 'number', 'string'];
14
14
  * Custom error class thrown by all SDK methods on failure.
15
15
  *
16
16
  * All rejected promises from API calls reject with an instance of this class.
17
+ *
18
+ * @group Errors
17
19
  */
18
20
  export default class SDKError extends Error {
19
21
  /** HTTP status code from the server error payload;
@@ -1,6 +1,11 @@
1
1
  import type { AccountBaseConfig, LogFunction } from './common';
2
2
  import type { IdentityBeforeRedirectCallback, VarnishCookieOptions } from './identity';
3
3
 
4
+ /**
5
+ * Configuration used to create an {@link Account} instance.
6
+ *
7
+ * @group Configuration
8
+ */
4
9
  export type AccountConfig = AccountBaseConfig & {
5
10
  /** Receives debug log information. If not set, no logging will be done. */
6
11
  log?: LogFunction;
@@ -10,18 +15,36 @@ export type AccountConfig = AccountBaseConfig & {
10
15
  varnish?: VarnishCookieOptions;
11
16
  };
12
17
 
13
- export type AccountSessionEventName =
14
- | 'login'
15
- | 'logout'
16
- | 'userChange'
17
- | 'sessionChange'
18
- | 'notLoggedin'
19
- | 'sessionInit'
20
- | 'statusChange'
21
- | 'error'
22
- | 'simplifiedLoginOpened'
23
- | 'simplifiedLoginCancelled';
18
+ type LoginEventDetail = {
19
+ url: string;
20
+ method: 'popup' | 'default';
21
+ };
22
+
23
+ type LogoutEventDetail = {
24
+ url: string;
25
+ };
26
+
27
+ export type AccountEventMap = {
28
+ /** Emitted with the login URL and method when `login()` initiates a login flow. */
29
+ login: CustomEvent<LoginEventDetail>;
30
+ /** Emitted with the logout URL when `logout()` is called. */
31
+ logout: CustomEvent<LogoutEventDetail>;
32
+ /** Emitted when the simplified login widget is displayed. */
33
+ simplifiedLoginOpened: Event;
34
+ /** Emitted when the simplified login widget is closed. */
35
+ simplifiedLoginCancelled: Event;
36
+ };
24
37
 
25
- export type AccountEventName = AccountSessionEventName | 'hasAccess';
38
+ /** Account event names emitted by the SDK. */
39
+ export type AccountEventName = keyof AccountEventMap;
26
40
 
27
- export type AccountEventHandler = (...args: unknown[]) => void;
41
+ /**
42
+ * Native event listener used by Account event subscriptions.
43
+ *
44
+ * Payload-bearing events are `CustomEvent` instances and expose their payload through `detail`.
45
+ *
46
+ * @group Events
47
+ */
48
+ export type AccountEventListener<EventName extends AccountEventName = AccountEventName> = (
49
+ event: AccountEventMap[EventName],
50
+ ) => void;
@@ -3,15 +3,21 @@
3
3
  /**
4
4
  * Log callback used by the SDK for debug output.
5
5
  * Receives a pre-formatted log line.
6
- * @internal
6
+ *
7
+ * @group Configuration
7
8
  */
8
9
  export type LogFunction = (message: string) => void;
9
10
 
10
11
  /**
11
12
  * Supported Schibsted account environment keys.
13
+ *
14
+ * @group Configuration
12
15
  */
13
16
  export type AccountEnvironment = 'LOCAL' | 'DEV' | 'PRE' | 'PRO' | 'PRO_NO' | 'PRO_FI' | 'PRO_DK';
14
17
 
18
+ /**
19
+ * Shared Account configuration fields.
20
+ */
15
21
  export type AccountBaseConfig = {
16
22
  /** Mandatory client id. Example: "1234567890abcdef12345678" */
17
23
  clientId: string;
@@ -15,35 +15,6 @@ export type IdentityOptions = AccountBaseConfig & {
15
15
  callbackBeforeRedirect?: IdentityBeforeRedirectCallback;
16
16
  };
17
17
 
18
- /**
19
- * Identity events emitted by the SDK.
20
- *
21
- * - `login`: emitted when `hasSession()` resolves with a logged-in user payload.
22
- * - `logout`: emitted when a previously logged-in user is no longer logged in, or when
23
- * `logout()` is called.
24
- * - `userChange`: emitted when the current session user id changes.
25
- * - `sessionChange`: emitted when either the previous or current `hasSession()` payload contains
26
- * a logged-in user.
27
- * - `notLoggedin`: emitted when neither the previous nor current `hasSession()` payload contains
28
- * a logged-in user.
29
- * - `sessionInit`: emitted once for the first logged-in session payload.
30
- * - `statusChange`: emitted when the session `userStatus` changes.
31
- * - `error`: emitted when `hasSession()` fails.
32
- * - `simplifiedLoginOpened`: emitted when the simplified login widget is displayed.
33
- * - `simplifiedLoginCancelled`: emitted when the simplified login widget is closed.
34
- */
35
- export type IdentityEventName =
36
- | 'login'
37
- | 'logout'
38
- | 'userChange'
39
- | 'sessionChange'
40
- | 'notLoggedin'
41
- | 'sessionInit'
42
- | 'statusChange'
43
- | 'error'
44
- | 'simplifiedLoginOpened'
45
- | 'simplifiedLoginCancelled';
46
-
47
18
  /**
48
19
  * Options for {@link Identity#enableVarnishCookie}.
49
20
  */
@@ -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?:
21
20
  | 'password'
@@ -81,6 +80,8 @@ export type LoginOptions = {
81
80
  /**
82
81
  * Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;
83
82
  * all other fields reuse the `LoginOptions` documentation.
83
+ *
84
+ * @group Login & Widget
84
85
  */
85
86
  export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
86
87
  /**
@@ -92,9 +93,11 @@ export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
92
93
 
93
94
  /**
94
95
  * Minimal user information used by the simplified login widget flow.
96
+ *
97
+ * @group Login & Widget
95
98
  */
96
99
  export type SimplifiedLoginData = {
97
- /** Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login} */
100
+ /** Deprecated: User UUID used as `loginHint` for {@link Account#login}. */
98
101
  identifier: string;
99
102
  /** Human-readable user identifier */
100
103
  display_text: string;
@@ -105,7 +108,9 @@ export type SimplifiedLoginData = {
105
108
  };
106
109
 
107
110
  /**
108
- * Configuration options for {@link Identity#showSimplifiedLoginWidget}.
111
+ * Configuration options for {@link Account#showSimplifiedLoginWidget}.
112
+ *
113
+ * @group Login & Widget
109
114
  */
110
115
  export type SimplifiedLoginWidgetOptions = {
111
116
  /** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */
@@ -4,16 +4,21 @@ import type { SessionUserId } from './session';
4
4
  /**
5
5
  * Result returned by the Session Service `/hasAccess` endpoint, describing whether the user
6
6
  * is entitled to a requested set of products/features.
7
- * @internal
7
+ *
8
+ * @group Access Checks
8
9
  */
9
10
  export interface HasAccessResult {
10
11
  /** Whether the user is entitled to at least one of the requested products/features. */
11
12
  entitled: boolean;
12
13
  /** How long this result stays valid, in seconds, before the cache entry expires. */
13
14
  ttl: number;
15
+ /** Feature ids the user is allowed to access. */
14
16
  allowedFeatures: string[];
17
+ /** User id the access result belongs to. */
15
18
  userId: SessionUserId;
19
+ /** Globally unique user id the access result belongs to. */
16
20
  uuid: string;
21
+ /** Signed response payload. */
17
22
  sig: string;
18
23
  }
19
24
 
@@ -7,17 +7,21 @@
7
7
  *
8
8
  * Session Service historically returned numeric ids, while some integrations and tests use
9
9
  * string ids. SDK convenience methods normalize this where they promise a string.
10
+ *
11
+ * @group Session
10
12
  */
11
13
  export type SessionUserId = number | string;
12
14
 
13
15
  // Session Service object payloads.
14
16
 
15
17
  /**
16
- * Successful response returned from {@link Identity#hasSession}.
18
+ * Successful response returned from {@link Account#hasSession}.
17
19
  *
18
20
  * `result` means the has-session call itself succeeded. `result: true` means the user is
19
21
  * connected to the merchant; `result: false` means a session may exist, but the user is not
20
22
  * connected to this client.
23
+ *
24
+ * @group Session
21
25
  */
22
26
  export type SessionSuccessResponse = {
23
27
  /** Response status code. Example: 200. */
@@ -31,7 +35,7 @@ export type SessionSuccessResponse = {
31
35
  * merchants connected to this user.
32
36
  */
33
37
  result: boolean;
34
- /** Connection status string. Deprecated; use `Identity.isConnected()`. Example: 'connected'. */
38
+ /** Connection status string. Deprecated; use `Account.isConnected()`. Example: 'connected'. */
35
39
  userStatus?: string;
36
40
  /** Cookie base domain used as the `SP_ID` cookie domain fallback. Example: 'spid.no'. */
37
41
  baseDomain?: string;
@@ -77,6 +81,8 @@ export type SessionSuccessResponse = {
77
81
 
78
82
  /**
79
83
  * Successful has-session response for a user connected to the merchant.
84
+ *
85
+ * @group Session
80
86
  */
81
87
  export type ConnectedSessionResponse = SessionSuccessResponse & {
82
88
  result: true;
@@ -84,6 +90,8 @@ export type ConnectedSessionResponse = SessionSuccessResponse & {
84
90
 
85
91
  /**
86
92
  * Connected session response that also carries a usable user id.
93
+ *
94
+ * @group Session
87
95
  */
88
96
  export type ConnectedSessionWithUserIdResponse = ConnectedSessionResponse & {
89
97
  userId: SessionUserId;
@@ -94,6 +102,8 @@ export type ConnectedSessionWithUserIdResponse = ConnectedSessionResponse & {
94
102
  *
95
103
  * API and network failures usually reject with {@link SDKError}; this shape represents a failure
96
104
  * payload when one is returned by Session Service and reaches the has-session flow.
105
+ *
106
+ * @group Session
97
107
  */
98
108
  export type SessionFailureResponse = {
99
109
  /** Failure payload returned by Session Service. Usually an object, but tests also pass strings. */
@@ -121,9 +131,16 @@ export type SessionFailureResponse = {
121
131
  *
122
132
  * This intentionally includes `{}`. Historically `hasSession()` could resolve an empty object or
123
133
  * other object payloads that callers inspected themselves, so the SDK preserves those responses.
134
+ *
135
+ * @group Session
124
136
  */
125
137
  export type UnrecognizedSessionResponse = object;
126
138
 
139
+ /**
140
+ * Redirect URL returned by `hasSession()` when Session Service needs a full-page session refresh.
141
+ *
142
+ * @group Session
143
+ */
127
144
  export type RedirectSessionResponse = string;
128
145
 
129
146
  export type SessionObjectResponse =
@@ -135,10 +152,18 @@ export type RedirectSessionPayload = {
135
152
  redirectURL: string;
136
153
  };
137
154
 
155
+ /**
156
+ * Internal shape returned by `normalizeSessionResponse()` before `hasSession()` post-processing.
157
+ *
158
+ * It includes regular Session Service object responses and redirect responses used for full-page
159
+ * session refresh.
160
+ */
138
161
  export type NormalizedSessionPayload = SessionObjectResponse | RedirectSessionPayload;
139
162
 
140
163
  /**
141
- * Public response union returned from {@link Identity#hasSession}.
164
+ * Public response union returned from {@link Account#hasSession}.
165
+ *
166
+ * @group Session
142
167
  */
143
168
  export type SessionResponse =
144
169
  | SessionSuccessResponse
package/src/version.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  // Version is bumped automatically by release-please. See release-please-config.json.
2
2
 
3
- const version = '6.0.0-alpha.4'; // x-release-please-version
3
+ const version = '6.0.0-alpha.6'; // x-release-please-version
4
4
  export default version;
@@ -1,23 +0,0 @@
1
- /**
2
- * Names of the SDK instance properties that can be registered on the global {@link Window} object.
3
- */
4
- type Property = 'schAccount' | 'schIdentity' | 'schMonetization';
5
- /**
6
- * Registers an SDK instance on the global {@link Window} object's given property and dispatches a ready event.
7
- *
8
- * The dispatched event is a {@link CustomEvent} fired on `global` (i.e. `window`) with:
9
- * - name: `${property}:ready` (e.g. `"schIdentity:ready"` or `"schMonetization:ready"`)
10
- * - `detail.instance`: the registered SDK instance
11
- *
12
- * @typeParam T - Constrained to {@link Property}; inferred from the `property` argument.
13
- * @param global - The `Window` object to register on.
14
- * @param property - The window property name to assign the instance to, 'schIdentity' or 'schMonetization'.
15
- * @param instance - The SDK instance to register. Must be non-nullable.
16
- *
17
- * @example
18
- * registerAndDispatchInGlobal(window, 'schIdentity', identityInstance);
19
- * / window.schIdentity === identityInstance
20
- * / CustomEvent 'schIdentity:ready' has been dispatched on window
21
- */
22
- export declare const registerAndDispatchInGlobal: <T extends Property>(global: Window, property: T, instance: NonNullable<Window[T]>) => void;
23
- export {};
@@ -1,2 +0,0 @@
1
- import { HasAccessResult } from './monetization.js';
2
- export declare function parseHasAccessResult(value: unknown): HasAccessResult;
@@ -1,36 +0,0 @@
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 {};
@@ -1,39 +0,0 @@
1
- import './globals.js';
2
-
3
- /**
4
- * Names of the SDK instance properties that can be registered on the global {@link Window} object.
5
- */
6
- type Property = 'schAccount' | 'schIdentity' | 'schMonetization';
7
-
8
- /**
9
- * Registers an SDK instance on the global {@link Window} object's given property and dispatches a ready event.
10
- *
11
- * The dispatched event is a {@link CustomEvent} fired on `global` (i.e. `window`) with:
12
- * - name: `${property}:ready` (e.g. `"schIdentity:ready"` or `"schMonetization:ready"`)
13
- * - `detail.instance`: the registered SDK instance
14
- *
15
- * @typeParam T - Constrained to {@link Property}; inferred from the `property` argument.
16
- * @param global - The `Window` object to register on.
17
- * @param property - The window property name to assign the instance to, 'schIdentity' or 'schMonetization'.
18
- * @param instance - The SDK instance to register. Must be non-nullable.
19
- *
20
- * @example
21
- * registerAndDispatchInGlobal(window, 'schIdentity', identityInstance);
22
- * / window.schIdentity === identityInstance
23
- * / CustomEvent 'schIdentity:ready' has been dispatched on window
24
- */
25
-
26
- export const registerAndDispatchInGlobal = <T extends Property>(
27
- global: Window,
28
- property: T,
29
- instance: NonNullable<Window[T]>,
30
- ): void => {
31
- if (!global[property]) {
32
- global[property] = instance;
33
- }
34
-
35
- global.dispatchEvent(
36
- //TODO -> https://schibsted.ghe.com/connect/team/issues/645
37
- new CustomEvent(`${property}:ready`, { detail: { instance: global[property] } }),
38
- );
39
- };
@@ -1,35 +0,0 @@
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 { isObject, isStr } from '../validate.js';
7
- import type { HasAccessResult } from './monetization.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
- }