@schibsted/account-sdk-browser 5.2.7 → 6.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -59
- package/dist/RESTClient.d.ts +91 -0
- package/dist/SDKError.d.ts +27 -0
- package/dist/cache.d.ts +65 -0
- package/dist/config.d.ts +86 -0
- package/dist/global-registry.d.ts +23 -0
- package/dist/globals.d.ts +13 -0
- package/dist/identity-s4nofYmB.js +370 -0
- package/dist/identity-s4nofYmB.js.map +1 -0
- package/dist/identity.d.ts +523 -0
- package/dist/identity.js +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/monetization.d.ts +94 -0
- package/dist/monetization.js +72 -0
- package/dist/monetization.js.map +1 -0
- package/{src → dist}/object.d.ts +4 -9
- package/dist/popup.d.ts +9 -0
- package/{src → dist}/spidTalk.d.ts +4 -6
- package/dist/url.d.ts +8 -0
- package/dist/validate.d.ts +50 -0
- package/dist/version-spE-k97g.js +289 -0
- package/dist/version-spE-k97g.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/package.json +42 -49
- package/src/RESTClient.ts +226 -0
- package/src/SDKError.ts +59 -0
- package/src/{cache.js → cache.ts} +52 -37
- package/src/{config.js → config.ts} +7 -32
- package/src/global-registry.ts +39 -0
- package/src/globals.ts +10 -0
- package/src/{identity.js → identity.ts} +536 -437
- package/{index.js → src/index.ts} +1 -3
- package/src/{monetization.js → monetization.ts} +77 -48
- package/src/{object.js → object.ts} +8 -15
- package/src/popup.ts +74 -0
- package/src/{spidTalk.js → spidTalk.ts} +10 -12
- package/src/{url.js → url.ts} +6 -10
- package/src/{validate.js → validate.ts} +26 -42
- package/src/{version.js → version.ts} +1 -2
- package/es5/global.js +0 -12968
- package/es5/global.js.map +0 -1
- package/es5/global.min.js +0 -2
- package/es5/global.min.js.map +0 -1
- package/es5/identity.js +0 -12212
- package/es5/identity.js.map +0 -1
- package/es5/identity.min.js +0 -2
- package/es5/identity.min.js.map +0 -1
- package/es5/index.js +0 -12940
- package/es5/index.js.map +0 -1
- package/es5/index.min.js +0 -2
- package/es5/index.min.js.map +0 -1
- package/es5/monetization.js +0 -9176
- package/es5/monetization.js.map +0 -1
- package/es5/monetization.min.js +0 -2
- package/es5/monetization.min.js.map +0 -1
- package/es5/payment.js +0 -8853
- package/es5/payment.js.map +0 -1
- package/es5/payment.min.js +0 -2
- package/es5/payment.min.js.map +0 -1
- package/identity.d.ts +0 -1
- package/identity.js +0 -5
- package/index.d.ts +0 -4
- package/monetization.d.ts +0 -1
- package/monetization.js +0 -5
- package/payment.d.ts +0 -1
- package/payment.js +0 -5
- package/src/RESTClient.d.ts +0 -89
- package/src/RESTClient.js +0 -193
- package/src/SDKError.d.ts +0 -16
- package/src/SDKError.js +0 -55
- package/src/__mocks__/.eslintrc.yml +0 -8
- package/src/__mocks__/RESTClient.js +0 -54
- package/src/cache.d.ts +0 -64
- package/src/config.d.ts +0 -34
- package/src/es5/global.js +0 -13
- package/src/es5/identity.js +0 -10
- package/src/es5/index.js +0 -13
- package/src/es5/monetization.js +0 -10
- package/src/es5/payment.js +0 -10
- package/src/global-registry.js +0 -20
- package/src/identity.d.ts +0 -679
- package/src/monetization.d.ts +0 -80
- package/src/payment.d.ts +0 -115
- package/src/payment.js +0 -211
- package/src/popup.d.ts +0 -10
- package/src/popup.js +0 -59
- package/src/url.d.ts +0 -10
- package/src/validate.d.ts +0 -64
- package/src/version.d.ts +0 -2
|
@@ -2,38 +2,71 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { assert, isStr, isNonEmptyString, isUrl } from './validate.js';
|
|
8
|
-
import { urlMapper } from './url.js';
|
|
5
|
+
import { TinyEmitter } from 'tiny-emitter';
|
|
6
|
+
import Cache from './cache.js';
|
|
9
7
|
import { ENDPOINTS, NAMESPACE } from './config.js';
|
|
10
|
-
import
|
|
8
|
+
import { registerAndDispatchInGlobal } from './global-registry.js';
|
|
11
9
|
import RESTClient from './RESTClient.js';
|
|
12
|
-
import Cache from './cache.js';
|
|
13
|
-
import * as spidTalk from './spidTalk.js';
|
|
14
10
|
import SDKError from './SDKError.js';
|
|
11
|
+
import * as spidTalk from './spidTalk.js';
|
|
12
|
+
import { urlMapper } from './url.js';
|
|
13
|
+
import { assert, isNonEmptyString, isStr, isUrl } from './validate.js';
|
|
15
14
|
import version from './version.js';
|
|
16
|
-
import { registerGlobal } from './global-registry.js';
|
|
17
15
|
|
|
18
16
|
const globalWindow = () => window;
|
|
19
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Result returned by the Session Service `/hasAccess` endpoint, describing whether the user
|
|
20
|
+
* is entitled to a requested set of products/features.
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export interface HasAccessResult {
|
|
24
|
+
/** Whether the user is entitled to at least one of the requested products/features. */
|
|
25
|
+
entitled: boolean;
|
|
26
|
+
/** How long this result stays valid, in seconds, before the cache entry expires. */
|
|
27
|
+
ttl: number;
|
|
28
|
+
allowedFeatures: string[];
|
|
29
|
+
userId: number;
|
|
30
|
+
uuid: string;
|
|
31
|
+
sig: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
/**
|
|
21
35
|
* Provides features related to monetization
|
|
22
36
|
*/
|
|
23
|
-
export class Monetization extends
|
|
37
|
+
export class Monetization extends TinyEmitter {
|
|
38
|
+
cache: Cache;
|
|
39
|
+
clientId: string;
|
|
40
|
+
env: string;
|
|
41
|
+
redirectUri: string;
|
|
42
|
+
_spid!: RESTClient;
|
|
43
|
+
_sessionService?: RESTClient;
|
|
44
|
+
private pendingHasAccessRequests: Record<string, Promise<HasAccessResult>>;
|
|
45
|
+
|
|
24
46
|
/**
|
|
25
|
-
* @param
|
|
26
|
-
* @param {string} options.clientId - Mandatory client id
|
|
27
|
-
* @param {string} [options.redirectUri] - Redirect uri
|
|
28
|
-
* @param {string} options.sessionDomain - Example: "https://id.site.com"
|
|
29
|
-
* @param {string} [options.env=PRE] - Schibsted account environment: `PRE`, `PRO` or `PRO_NO`
|
|
30
|
-
* @param {object} [options.window]
|
|
47
|
+
* @param options - Monetization configuration
|
|
31
48
|
* @throws {SDKError} - If any of options are invalid
|
|
32
49
|
*/
|
|
33
|
-
constructor({
|
|
50
|
+
constructor({
|
|
51
|
+
clientId,
|
|
52
|
+
redirectUri,
|
|
53
|
+
env = 'PRE',
|
|
54
|
+
sessionDomain,
|
|
55
|
+
window = globalWindow(),
|
|
56
|
+
}: {
|
|
57
|
+
/** Mandatory client id */
|
|
58
|
+
clientId: string;
|
|
59
|
+
/** Redirect uri */
|
|
60
|
+
redirectUri: string;
|
|
61
|
+
/** Example: `"https://id.site.com"` */
|
|
62
|
+
sessionDomain: string;
|
|
63
|
+
/** Schibsted account environment: `PRE` (default), `PRO`, `PRO_NO` */
|
|
64
|
+
env?: string;
|
|
65
|
+
/** Window object to use (defaults to the global `window`). */
|
|
66
|
+
window?: Window;
|
|
67
|
+
}) {
|
|
34
68
|
super();
|
|
35
69
|
spidTalk.emulate(window);
|
|
36
|
-
// validate options
|
|
37
70
|
assert(isNonEmptyString(clientId), 'clientId parameter is required');
|
|
38
71
|
|
|
39
72
|
this.cache = new Cache(() => window && window.sessionStorage);
|
|
@@ -47,16 +80,15 @@ export class Monetization extends EventEmitter {
|
|
|
47
80
|
assert(isUrl(sessionDomain), 'sessionDomain parameter is not a valid URL');
|
|
48
81
|
this._setSessionServiceUrl(sessionDomain);
|
|
49
82
|
}
|
|
50
|
-
|
|
83
|
+
registerAndDispatchInGlobal(window, 'schMonetization', this);
|
|
51
84
|
}
|
|
52
85
|
|
|
53
86
|
/**
|
|
54
87
|
* Set SPiD server URL
|
|
55
88
|
* @private
|
|
56
|
-
* @param
|
|
57
|
-
* @returns {void}
|
|
89
|
+
* @param url
|
|
58
90
|
*/
|
|
59
|
-
_setSpidServerUrl(url) {
|
|
91
|
+
private _setSpidServerUrl(url: string): void {
|
|
60
92
|
assert(isStr(url), `url parameter is invalid: ${url}`);
|
|
61
93
|
this._spid = new RESTClient({
|
|
62
94
|
serverUrl: urlMapper(url, ENDPOINTS.SPiD),
|
|
@@ -67,29 +99,27 @@ export class Monetization extends EventEmitter {
|
|
|
67
99
|
/**
|
|
68
100
|
* Set session-service domain
|
|
69
101
|
* @private
|
|
70
|
-
* @param
|
|
71
|
-
* @returns {void}
|
|
102
|
+
* @param domain - real URL — (**not** 'PRE' style env key)
|
|
72
103
|
*/
|
|
73
|
-
_setSessionServiceUrl(domain) {
|
|
104
|
+
private _setSessionServiceUrl(domain: string): void {
|
|
74
105
|
assert(isStr(domain), `domain parameter is invalid: ${domain}`);
|
|
75
|
-
const client_sdrn = `sdrn:${NAMESPACE[this.env]}:client:${this.clientId}`;
|
|
106
|
+
const client_sdrn = `sdrn:${NAMESPACE[this.env as keyof typeof NAMESPACE]}:client:${this.clientId}`;
|
|
76
107
|
this._sessionService = new RESTClient({
|
|
77
108
|
serverUrl: domain,
|
|
78
|
-
|
|
79
|
-
defaultParams: { client_sdrn, redirect_uri: this.redirectUri, sdk_version: version },
|
|
109
|
+
defaultParams: { client_sdrn, redirect_uri: this.redirectUri, sdk_version: version },
|
|
80
110
|
});
|
|
81
111
|
}
|
|
82
112
|
|
|
83
113
|
/**
|
|
84
114
|
* Checks if the user has access to a set of products or features.
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
115
|
+
* @param productIds - which products/features to check
|
|
116
|
+
* @param userId - id of currently logged in user
|
|
87
117
|
* @throws {SDKError} - If the input is incorrect, or a network call fails in any way
|
|
88
118
|
* (this will happen if, say, the user is not logged in)
|
|
89
|
-
* @returns
|
|
119
|
+
* @returns The data object returned from Schibsted account (or `null` if the user
|
|
90
120
|
* doesn't have access to any of the given products/features)
|
|
91
121
|
*/
|
|
92
|
-
async hasAccess(productIds, userId) {
|
|
122
|
+
async hasAccess(productIds: string[], userId: number): Promise<HasAccessResult | null> {
|
|
93
123
|
if (!this._sessionService) {
|
|
94
124
|
throw new SDKError(`hasAccess can only be called if 'sessionDomain' is configured`);
|
|
95
125
|
}
|
|
@@ -102,10 +132,12 @@ export class Monetization extends EventEmitter {
|
|
|
102
132
|
|
|
103
133
|
const sortedIds = [...productIds].sort();
|
|
104
134
|
const cacheKey = this._accessCacheKey(sortedIds, userId);
|
|
105
|
-
let data = this.cache.get(cacheKey);
|
|
135
|
+
let data = this.cache.get(cacheKey) as HasAccessResult | null;
|
|
106
136
|
if (!data) {
|
|
107
137
|
if (!this.pendingHasAccessRequests[cacheKey]) {
|
|
108
|
-
this.pendingHasAccessRequests[cacheKey] = this._sessionService.get(
|
|
138
|
+
this.pendingHasAccessRequests[cacheKey] = this._sessionService.get(
|
|
139
|
+
`/hasAccess/${sortedIds.join(',')}`,
|
|
140
|
+
);
|
|
109
141
|
}
|
|
110
142
|
const promise = this.pendingHasAccessRequests[cacheKey];
|
|
111
143
|
try {
|
|
@@ -113,7 +145,6 @@ export class Monetization extends EventEmitter {
|
|
|
113
145
|
const expiresSeconds = data.ttl;
|
|
114
146
|
this.cache.set(cacheKey, data, expiresSeconds * 1000);
|
|
115
147
|
} finally {
|
|
116
|
-
// If it rejects, we still want to clear the pending request
|
|
117
148
|
if (this.pendingHasAccessRequests[cacheKey] === promise) {
|
|
118
149
|
delete this.pendingHasAccessRequests[cacheKey];
|
|
119
150
|
}
|
|
@@ -129,41 +160,39 @@ export class Monetization extends EventEmitter {
|
|
|
129
160
|
|
|
130
161
|
/**
|
|
131
162
|
* Removes the cached access result.
|
|
132
|
-
* @param
|
|
133
|
-
* @param
|
|
134
|
-
* @returns {void}
|
|
163
|
+
* @param productIds - which products/features to check
|
|
164
|
+
* @param userId - id of currently logged in user
|
|
135
165
|
*/
|
|
136
|
-
clearCachedAccessResult(productIds, userId) {
|
|
166
|
+
clearCachedAccessResult(productIds: string[], userId: number): void {
|
|
137
167
|
this.cache.delete(this._accessCacheKey(productIds, userId));
|
|
138
168
|
}
|
|
139
169
|
|
|
140
170
|
/**
|
|
141
171
|
* Compute "has access" cache key for the given product ids and user id.
|
|
142
|
-
* @param {array} productIds - which products/features to check
|
|
143
|
-
* @param {number} userId - id of currently logged in user
|
|
144
|
-
* @returns {string}
|
|
145
172
|
* @private
|
|
173
|
+
* @param productIds - which products/features to check
|
|
174
|
+
* @param userId - id of currently logged in user
|
|
146
175
|
*/
|
|
147
|
-
_accessCacheKey(productIds, userId) {
|
|
176
|
+
private _accessCacheKey(productIds: string[], userId: number): string {
|
|
148
177
|
return `prd_${[...productIds].sort()}_${userId}`;
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
/**
|
|
152
181
|
* Get the url for the end user to review the subscriptions
|
|
153
|
-
* @param
|
|
154
|
-
* @
|
|
182
|
+
* @param redirectUri
|
|
183
|
+
* @returns - The url to the subscriptions review page
|
|
155
184
|
*/
|
|
156
|
-
subscriptionsUrl(redirectUri = this.redirectUri) {
|
|
185
|
+
subscriptionsUrl(redirectUri: string = this.redirectUri): string {
|
|
157
186
|
assert(isUrl(redirectUri), `subscriptionsUrl(): redirectUri is invalid`);
|
|
158
187
|
return this._spid.makeUrl('account/subscriptions', { redirect_uri: redirectUri });
|
|
159
188
|
}
|
|
160
189
|
|
|
161
190
|
/**
|
|
162
191
|
* Get the url for the end user to review the products
|
|
163
|
-
* @param
|
|
164
|
-
* @
|
|
192
|
+
* @param redirectUri
|
|
193
|
+
* @returns - The url to the products review page
|
|
165
194
|
*/
|
|
166
|
-
productsUrl(redirectUri = this.redirectUri) {
|
|
195
|
+
productsUrl(redirectUri: string = this.redirectUri): string {
|
|
167
196
|
assert(isUrl(redirectUri), `productsUrl(): redirectUri is invalid`);
|
|
168
197
|
return this._spid.makeUrl('account/products', { redirect_uri: redirectUri });
|
|
169
198
|
}
|
|
@@ -2,41 +2,36 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* @summary Some routines that work on javascript objects
|
|
9
7
|
* @private
|
|
10
8
|
*/
|
|
11
9
|
|
|
12
|
-
import { assert, isObject, isNonEmptyObj } from './validate.js';
|
|
13
10
|
import SDKError from './SDKError.js';
|
|
11
|
+
import { assert, isNonEmptyObj, isObject } from './validate.js';
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
14
|
* Similar to Object.assign({}, src) but only clones the keys of an object that have non-undefined
|
|
17
15
|
* values.
|
|
18
16
|
* Please note that the values in the rightmost parameters can overwrite the values of the earlier
|
|
19
17
|
* parameters so the order of the parameters matters.
|
|
20
|
-
* @memberof core
|
|
21
18
|
* @example
|
|
22
19
|
* cloneDefined({foo: 1, bar: 2}, {foo: 2}) // returns {foo: 2, bar: 2}
|
|
23
20
|
*
|
|
24
|
-
* @param
|
|
21
|
+
* @param sources - one or more sources. Their defined properties will override the ones
|
|
25
22
|
* that came before it. For example if `source1.foo = 'bar'` and `source2.foo = 'baz'`, the
|
|
26
23
|
* result will include `{ foo: 'baz' }`
|
|
27
|
-
* @return {object} a new object that is similar to src with all the key/values where the
|
|
28
|
-
* keys for undefined values are removed.
|
|
29
24
|
*/
|
|
30
|
-
export function cloneDefined(...sources) {
|
|
31
|
-
const result = {};
|
|
25
|
+
export function cloneDefined(...sources: object[]): Record<string, unknown> {
|
|
26
|
+
const result: Record<string, unknown> = {};
|
|
32
27
|
if (!(sources && sources.length)) {
|
|
33
28
|
throw new SDKError('No objects to clone');
|
|
34
29
|
}
|
|
35
|
-
sources.forEach(source => {
|
|
30
|
+
sources.forEach((source) => {
|
|
36
31
|
assert(isObject(source));
|
|
37
32
|
if (isNonEmptyObj(source)) {
|
|
38
33
|
Object.entries(source).forEach(([key, value]) => {
|
|
39
|
-
if (typeof value !== 'undefined'
|
|
34
|
+
if (typeof value !== 'undefined') {
|
|
40
35
|
result[key] = isObject(value) ? cloneDeep(value) : value;
|
|
41
36
|
}
|
|
42
37
|
});
|
|
@@ -47,13 +42,11 @@ export function cloneDefined(...sources) {
|
|
|
47
42
|
|
|
48
43
|
/**
|
|
49
44
|
* Deep copies an object. This is handy for immutability.
|
|
50
|
-
* @
|
|
51
|
-
* @param {object} obj - An object, array or null.
|
|
52
|
-
* @return {object} - an exact copy of the object but deep copied
|
|
45
|
+
* @param obj - An object, array or null.
|
|
53
46
|
* @throws {SDKError} - if the obj is not an accepted type or is not
|
|
54
47
|
* stringifiable by JSON for example if it has loops
|
|
55
48
|
*/
|
|
56
|
-
export function cloneDeep(obj) {
|
|
49
|
+
export function cloneDeep<T extends object | null>(obj: T): T {
|
|
57
50
|
assert(typeof obj === 'object', `obj should be an object (even null) but it is ${obj}`);
|
|
58
51
|
return JSON.parse(JSON.stringify(obj)) || obj;
|
|
59
52
|
}
|
package/src/popup.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.
|
|
2
|
+
* See LICENSE.md in the project root.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { cloneDefined } from './object.js';
|
|
6
|
+
import { assert, isFunction, isObject, isUrl } from './validate.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Serializes an object to string.
|
|
10
|
+
* @private
|
|
11
|
+
* @param obj - for example {a: 'b', c: 1}
|
|
12
|
+
*/
|
|
13
|
+
function serialize(obj: Record<string, unknown>): string {
|
|
14
|
+
assert(isObject(obj), `Object must be an object but it is '${obj}'`);
|
|
15
|
+
return Object.keys(obj)
|
|
16
|
+
.map((key) => `${key}=${obj[key]}`)
|
|
17
|
+
.join(',');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const defaultWindowFeatures = {
|
|
21
|
+
scrollbars: 'yes',
|
|
22
|
+
location: 'yes',
|
|
23
|
+
status: 'no',
|
|
24
|
+
menubar: 'no',
|
|
25
|
+
toolbar: 'no',
|
|
26
|
+
resizable: 'yes',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Opens a popup
|
|
31
|
+
* @param parentWindow - A reference to the window that will open the popup
|
|
32
|
+
* @param url - The URL that the popup will open
|
|
33
|
+
* @param windowName - A name for the window
|
|
34
|
+
* @param windowFeatures - Window features for the popup (default ones are usually ok)
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
export function open(
|
|
38
|
+
parentWindow: Window,
|
|
39
|
+
url: string,
|
|
40
|
+
windowName = '',
|
|
41
|
+
windowFeatures: Record<string, string | number> = {},
|
|
42
|
+
): Window | null {
|
|
43
|
+
assert(isObject(parentWindow), `window was supposed to be an object but it is ${parentWindow}`);
|
|
44
|
+
assert(
|
|
45
|
+
isObject(parentWindow.screen),
|
|
46
|
+
`window should be a valid Window object but it lacks a 'screen' property`,
|
|
47
|
+
);
|
|
48
|
+
assert(
|
|
49
|
+
isFunction(parentWindow.open),
|
|
50
|
+
`window should be a valid Window object but it lacks an 'open' function`,
|
|
51
|
+
);
|
|
52
|
+
assert(isUrl(url), 'Invalid URL for popup');
|
|
53
|
+
|
|
54
|
+
const { height, width } = parentWindow.screen;
|
|
55
|
+
|
|
56
|
+
const mergedFeatures = cloneDefined(defaultWindowFeatures, windowFeatures);
|
|
57
|
+
const { width: featureWidth, height: featureHeight } = mergedFeatures;
|
|
58
|
+
if (
|
|
59
|
+
typeof featureWidth === 'number' &&
|
|
60
|
+
Number.isFinite(featureWidth) &&
|
|
61
|
+
Number.isFinite(width)
|
|
62
|
+
) {
|
|
63
|
+
mergedFeatures.left = (width - featureWidth) / 2;
|
|
64
|
+
}
|
|
65
|
+
if (
|
|
66
|
+
typeof featureHeight === 'number' &&
|
|
67
|
+
Number.isFinite(featureHeight) &&
|
|
68
|
+
Number.isFinite(height)
|
|
69
|
+
) {
|
|
70
|
+
mergedFeatures.top = (height - featureHeight) / 2;
|
|
71
|
+
}
|
|
72
|
+
const features = serialize(mergedFeatures);
|
|
73
|
+
return parentWindow.open(url, windowName, features);
|
|
74
|
+
}
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* A workaround for how Schibsted account handles JSONP calls in the browser
|
|
9
7
|
* @private
|
|
10
8
|
*/
|
|
11
9
|
|
|
10
|
+
import './globals.js';
|
|
12
11
|
import { isFunction } from './validate.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -20,20 +19,19 @@ import { isFunction } from './validate.js';
|
|
|
20
19
|
* The old SPiD JSONP APIs relied on SPiD.Talk.response(callbackName, data) but fetch-jsonp merely
|
|
21
20
|
* calls window[callbackName](data) which is more common practice. This module simply acts as an
|
|
22
21
|
* adapter to modernize the old mechanism until we support CORS. To see how the SPiD solution works,
|
|
23
|
-
* try to run a simple JSONP request or debug it in
|
|
24
|
-
* CORS is supported.
|
|
25
|
-
* @
|
|
26
|
-
* @param {object} global - a reference to the global object
|
|
27
|
-
* @return {void}
|
|
22
|
+
* try to run a simple JSONP request or debug it in the network tab. This module will be removed
|
|
23
|
+
* when CORS is supported.
|
|
24
|
+
* @param global - A reference to the global object, typically the `Window`.
|
|
28
25
|
*/
|
|
29
|
-
export function emulate(global) {
|
|
30
|
-
if (global.SPiD
|
|
26
|
+
export function emulate(global: Window): void {
|
|
27
|
+
if (!global.SPiD || typeof global.SPiD !== 'object') {
|
|
31
28
|
global.SPiD = {};
|
|
32
29
|
}
|
|
33
|
-
if (global.SPiD.Talk
|
|
34
|
-
global.SPiD.Talk = {}
|
|
30
|
+
if (!global.SPiD.Talk || typeof global.SPiD.Talk !== 'object') {
|
|
31
|
+
global.SPiD.Talk = {};
|
|
35
32
|
}
|
|
36
33
|
if (!isFunction(global.SPiD.Talk.response)) {
|
|
37
|
-
global.SPiD.Talk.response = (callbackName, data) =>
|
|
34
|
+
global.SPiD.Talk.response = (callbackName: string, data: unknown) =>
|
|
35
|
+
(global as any)[callbackName](data);
|
|
38
36
|
}
|
|
39
37
|
}
|
package/src/{url.js → url.ts}
RENAMED
|
@@ -2,20 +2,16 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { assert, isNonEmptyString, isUrl, isNonEmptyObj } from './validate.js';
|
|
5
|
+
import { assert, isNonEmptyObj, isNonEmptyString, isUrl } from './validate.js';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* A simple utility function that allows looking up URLs from a dictionary
|
|
11
|
-
* @
|
|
12
|
-
* @param
|
|
13
|
-
* @
|
|
14
|
-
*
|
|
15
|
-
* @throws {SDKError} - If the url is not an string or is an empty string
|
|
16
|
-
* @return {string} The url that points to the server
|
|
9
|
+
* @param url - A url like http://example.com, or a key used for lookup
|
|
10
|
+
* @param urlMap - A map of URLs like `{ DEV: 'http://dev.example.com' }`
|
|
11
|
+
* @returns The resolved URL: the mapped value when `url` is a known key, otherwise `url` itself
|
|
12
|
+
* @throws {SDKError} - If the url is not a string or is an empty string
|
|
17
13
|
*/
|
|
18
|
-
export function urlMapper(url, urlMap) {
|
|
14
|
+
export function urlMapper(url: string, urlMap: Record<string, string>): string {
|
|
19
15
|
assert(isNonEmptyString(url), `"url" param must be a non empty string: ${typeof url}`);
|
|
20
16
|
if (isNonEmptyObj(urlMap) && isUrl(urlMap[url])) {
|
|
21
17
|
return urlMap[url];
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
5
|
import SDKError from './SDKError.js';
|
|
8
6
|
|
|
9
7
|
/*
|
|
@@ -16,13 +14,13 @@ import SDKError from './SDKError.js';
|
|
|
16
14
|
/**
|
|
17
15
|
* A utility function that throws an SDKError if an assertion fails. It's mostly useful for
|
|
18
16
|
* validating function inputs.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param
|
|
17
|
+
*
|
|
18
|
+
* Narrows `condition` for the rest of the enclosing scope (TypeScript assertion signature).
|
|
19
|
+
* @param condition - The condition that we're asserting
|
|
20
|
+
* @param message - The error message
|
|
22
21
|
* @throws {SDKError} - If the condition is falsy it throws the appropriate error
|
|
23
|
-
* @return {void}
|
|
24
22
|
*/
|
|
25
|
-
export function assert(condition, message = 'Assertion failed') {
|
|
23
|
+
export function assert(condition: boolean, message = 'Assertion failed'): asserts condition {
|
|
26
24
|
if (!condition) {
|
|
27
25
|
throw new SDKError(message);
|
|
28
26
|
}
|
|
@@ -30,82 +28,68 @@ export function assert(condition, message = 'Assertion failed') {
|
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
* Checks if a value is a string or not
|
|
33
|
-
* @
|
|
34
|
-
* @param {*} value - The value to check
|
|
35
|
-
* @return {boolean}
|
|
31
|
+
* @param value - The value to check
|
|
36
32
|
*/
|
|
37
|
-
export function isStr(value) {
|
|
33
|
+
export function isStr(value: unknown): value is string {
|
|
38
34
|
return typeof value === 'string';
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
/**
|
|
42
38
|
* Checks if a value is a non-empty string
|
|
43
|
-
* @
|
|
44
|
-
* @param {*} value - The value to check
|
|
45
|
-
* @return {boolean}
|
|
39
|
+
* @param value - The value to check
|
|
46
40
|
*/
|
|
47
|
-
export function isNonEmptyString(value) {
|
|
41
|
+
export function isNonEmptyString(value: unknown): value is string {
|
|
48
42
|
return typeof value === 'string' && value.length > 0;
|
|
49
43
|
}
|
|
50
44
|
|
|
51
45
|
/**
|
|
52
46
|
* checks if a given value is an object (but not null)
|
|
53
|
-
* @
|
|
54
|
-
* @param {*} value - The value to check
|
|
55
|
-
* @return {boolean}
|
|
47
|
+
* @param value - The value to check
|
|
56
48
|
*/
|
|
57
|
-
export function isObject(value) {
|
|
49
|
+
export function isObject(value: unknown): value is Record<string, unknown> {
|
|
58
50
|
return typeof value === 'object' && value !== null;
|
|
59
51
|
}
|
|
60
52
|
|
|
61
53
|
/**
|
|
62
54
|
* Checks if a given value is an object with at least one own key
|
|
63
|
-
* @
|
|
64
|
-
* @param {*} value - The value to check
|
|
65
|
-
* @return {boolean}
|
|
55
|
+
* @param value - The value to check
|
|
66
56
|
*/
|
|
67
|
-
export function isNonEmptyObj(value) {
|
|
57
|
+
export function isNonEmptyObj(value: unknown): value is Record<string, unknown> {
|
|
68
58
|
return isObject(value) && Object.keys(value).length > 0;
|
|
69
59
|
}
|
|
70
60
|
|
|
71
61
|
/**
|
|
72
62
|
* Checks if a given string is a valid URL
|
|
73
|
-
* @
|
|
74
|
-
* @param
|
|
75
|
-
*
|
|
76
|
-
* URL object
|
|
77
|
-
* @return {boolean}
|
|
63
|
+
* @param value - The string to be tested
|
|
64
|
+
* @param mandatoryFields - A list of mandatory fields that should exist in the parsed
|
|
65
|
+
* `URL` object
|
|
78
66
|
*/
|
|
79
|
-
export function isUrl(value, ...mandatoryFields) {
|
|
67
|
+
export function isUrl(value: string, ...mandatoryFields: (keyof URL)[]): boolean {
|
|
80
68
|
try {
|
|
81
69
|
const parsedUrl = new URL(value);
|
|
82
|
-
return mandatoryFields.every(f => parsedUrl[f]);
|
|
83
|
-
} catch
|
|
70
|
+
return mandatoryFields.every((f) => parsedUrl[f]);
|
|
71
|
+
} catch {
|
|
84
72
|
return false;
|
|
85
73
|
}
|
|
86
74
|
}
|
|
87
75
|
|
|
88
76
|
/**
|
|
89
77
|
* Checks if a given value is a function
|
|
90
|
-
* @
|
|
91
|
-
* @param {*} value - The value to check
|
|
92
|
-
* @return {boolean}
|
|
78
|
+
* @param value - The value to check
|
|
93
79
|
*/
|
|
94
|
-
export function isFunction(value) {
|
|
80
|
+
export function isFunction(value: unknown): value is (...args: unknown[]) => unknown {
|
|
95
81
|
return typeof value === 'function';
|
|
96
82
|
}
|
|
97
83
|
|
|
98
84
|
/**
|
|
99
85
|
* Checks if a string matches any of the strings in a set of possibilities
|
|
100
|
-
* @
|
|
101
|
-
* @param
|
|
102
|
-
* @param {string[]} possibilities - An array of strings that'll be used to check the string
|
|
86
|
+
* @param value
|
|
87
|
+
* @param possibilities - An array of strings that'll be used to check the string
|
|
103
88
|
* inclusion. Note that for performance reasons, we don't validate this parameter.
|
|
104
|
-
* @param
|
|
105
|
-
* @return {boolean}
|
|
89
|
+
* @param caseSensitive - Should the check be case sensitive
|
|
106
90
|
*/
|
|
107
|
-
export function isStrIn(value, possibilities, caseSensitive = false) {
|
|
108
|
-
const _isSameStrCaseInsensitive = str =>
|
|
91
|
+
export function isStrIn(value: string, possibilities: string[], caseSensitive = false): boolean {
|
|
92
|
+
const _isSameStrCaseInsensitive = (str: string) =>
|
|
109
93
|
isStr(str) && value.toUpperCase() === str.toUpperCase();
|
|
110
94
|
if (!(isStr(value) && Array.isArray(possibilities))) {
|
|
111
95
|
return false;
|