@schibsted/account-sdk-browser 6.0.0-alpha.1 → 6.0.0-alpha.3

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.
Files changed (89) hide show
  1. package/README.md +39 -64
  2. package/dist/account-sdk.d.ts +4 -0
  3. package/dist/account.d.ts +29 -0
  4. package/dist/cache.d.ts +65 -0
  5. package/dist/config.d.ts +86 -0
  6. package/dist/get-account-sdk.d.ts +3 -0
  7. package/dist/global-registry.d.ts +23 -0
  8. package/dist/globals.d.ts +15 -0
  9. package/dist/has-access-response.d.ts +2 -0
  10. package/dist/identity.d.ts +323 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.js +859 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/monetization.d.ts +58 -0
  15. package/{src → dist}/object.d.ts +4 -9
  16. package/dist/popup.d.ts +9 -0
  17. package/dist/resolve-browser-window.d.ts +1 -0
  18. package/dist/rest-client.d.ts +102 -0
  19. package/dist/rest-clients.d.ts +10 -0
  20. package/dist/sdk-error.d.ts +27 -0
  21. package/dist/session-response.d.ts +30 -0
  22. package/{src/spidTalk.d.ts → dist/spid-talk.d.ts} +4 -6
  23. package/dist/types/account.d.ts +13 -0
  24. package/dist/types/common.d.ts +22 -0
  25. package/dist/types/identity.d.ts +41 -0
  26. package/dist/types/login.d.ts +120 -0
  27. package/dist/types/monetization-guards.d.ts +2 -0
  28. package/dist/types/monetization.d.ts +21 -0
  29. package/dist/types/session-guards.d.ts +36 -0
  30. package/dist/types/session.d.ts +124 -0
  31. package/dist/url.d.ts +8 -0
  32. package/dist/validate.d.ts +50 -0
  33. package/dist/version.d.ts +2 -0
  34. package/package.json +30 -22
  35. package/src/account-sdk.ts +74 -0
  36. package/src/account.ts +149 -0
  37. package/src/{cache.js → cache.ts} +53 -38
  38. package/src/{config.js → config.ts} +7 -32
  39. package/src/get-account-sdk.ts +94 -0
  40. package/src/global-registry.ts +39 -0
  41. package/src/globals.ts +12 -0
  42. package/src/has-access-response.ts +35 -0
  43. package/src/identity.ts +1102 -0
  44. package/src/index.ts +32 -0
  45. package/src/{monetization.js → monetization.ts} +65 -73
  46. package/src/{object.js → object.ts} +9 -16
  47. package/src/popup.ts +74 -0
  48. package/src/resolve-browser-window.ts +11 -0
  49. package/src/rest-client.ts +253 -0
  50. package/src/rest-clients.ts +30 -0
  51. package/src/sdk-error.ts +59 -0
  52. package/src/session-response.ts +85 -0
  53. package/src/{spidTalk.js → spid-talk.ts} +10 -12
  54. package/src/types/account.ts +27 -0
  55. package/src/types/common.ts +26 -0
  56. package/src/types/identity.ts +55 -0
  57. package/src/types/login.ts +145 -0
  58. package/src/types/monetization-guards.ts +35 -0
  59. package/src/types/monetization.ts +24 -0
  60. package/src/types/session-guards.ts +89 -0
  61. package/src/types/session.ts +147 -0
  62. package/src/{url.js → url.ts} +6 -10
  63. package/src/{validate.js → validate.ts} +27 -43
  64. package/src/{version.js → version.ts} +1 -2
  65. package/identity.d.ts +0 -1
  66. package/identity.js +0 -5
  67. package/index.d.ts +0 -4
  68. package/index.js +0 -9
  69. package/monetization.d.ts +0 -1
  70. package/monetization.js +0 -5
  71. package/payment.d.ts +0 -1
  72. package/payment.js +0 -5
  73. package/src/RESTClient.d.ts +0 -89
  74. package/src/RESTClient.js +0 -193
  75. package/src/SDKError.d.ts +0 -16
  76. package/src/SDKError.js +0 -55
  77. package/src/cache.d.ts +0 -64
  78. package/src/config.d.ts +0 -34
  79. package/src/global-registry.js +0 -20
  80. package/src/identity.d.ts +0 -679
  81. package/src/identity.js +0 -1154
  82. package/src/monetization.d.ts +0 -80
  83. package/src/payment.d.ts +0 -115
  84. package/src/payment.js +0 -211
  85. package/src/popup.d.ts +0 -10
  86. package/src/popup.js +0 -59
  87. package/src/url.d.ts +0 -10
  88. package/src/validate.d.ts +0 -64
  89. package/src/version.d.ts +0 -2
@@ -0,0 +1,147 @@
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
+ /**
6
+ * User identifier returned by Session Service responses.
7
+ *
8
+ * Session Service historically returned numeric ids, while some integrations and tests use
9
+ * string ids. SDK convenience methods normalize this where they promise a string.
10
+ */
11
+ export type SessionUserId = number | string;
12
+
13
+ // Session Service object payloads.
14
+
15
+ /**
16
+ * Successful response returned from {@link Identity#hasSession}.
17
+ *
18
+ * `result` means the has-session call itself succeeded. `result: true` means the user is
19
+ * connected to the merchant; `result: false` means a session may exist, but the user is not
20
+ * connected to this client.
21
+ */
22
+ export type SessionSuccessResponse = {
23
+ /** Response status code. Example: 200. */
24
+ code: number;
25
+ /** Response type. Example: 'OK'. */
26
+ type: string;
27
+ /** Human-readable response description. Example: 'OK'. */
28
+ description: string;
29
+ /**
30
+ * Is the user connected to the merchant? This means the merchant id is in the list of
31
+ * merchants connected to this user.
32
+ */
33
+ result: boolean;
34
+ /** Connection status string. Deprecated; use `Identity.isConnected()`. Example: 'connected'. */
35
+ userStatus?: string;
36
+ /** Cookie base domain used as the `SP_ID` cookie domain fallback. Example: 'spid.no'. */
37
+ baseDomain?: string;
38
+ /** Legacy session id. Obsolete. Example: '58eca10fdbb9f6df72c3368f'. */
39
+ id?: string;
40
+ /** A numeric user id which is unique per realm (country). Example: 37162 */
41
+ userId?: SessionUserId;
42
+ /** Globally unique user id. Example: 'b3b23aa7-34f2-5d02-a10e-5a3455c6ab2c' */
43
+ uuid?: string;
44
+ /** Session token used for the `SP_ID` cookie. Example: 'eyJjbGllbnRfaWQ...'. */
45
+ sp_id?: string;
46
+ /** Session response TTL in seconds. Example: 300. */
47
+ expiresIn?: number;
48
+ /** Server time as a Unix timestamp in seconds. Example: 1506285759. */
49
+ serverTime?: number;
50
+ /**
51
+ * Example: 'NCdzXaz4ZRb7...' The sig parameter is a concatenation of an HMAC SHA-256
52
+ * signature string, a dot (.) and a base64url encoded JSON object (session).
53
+ * {@link http://techdocs.spid.no/sdks/js/response-signature-and-validation/}
54
+ */
55
+ sig?: string;
56
+ /** User display name. Example: 'batman'. */
57
+ displayName?: string;
58
+ /** User given name. Example: 'Bruce'. */
59
+ givenName?: string;
60
+ /** User family name. Example: 'Wayne'. */
61
+ familyName?: string;
62
+ /** User gender value. Example: 'male', 'female', 'undisclosed'. */
63
+ gender?: string;
64
+ /** User profile photo URL. Example: 'http://www.srv.com/some/picture.jpg' . */
65
+ photo?: string;
66
+ /** Whether tracking is enabled for this session. Example: true. */
67
+ tracking?: boolean;
68
+ /** Whether the client agreement is accepted. Example: true. */
69
+ clientAgreementAccepted?: boolean;
70
+ /** Whether the default agreement is accepted. Example: true. */
71
+ defaultAgreementAccepted?: boolean;
72
+ /** Pairwise user id for this client. Example: 'b2a23caa...'. */
73
+ pairId?: string;
74
+ /** User SDRN. Example: 'sdrn:spid.no:user:12345'. */
75
+ sdrn?: string;
76
+ };
77
+
78
+ /**
79
+ * Successful has-session response for a user connected to the merchant.
80
+ */
81
+ export type ConnectedSessionResponse = SessionSuccessResponse & {
82
+ result: true;
83
+ };
84
+
85
+ /**
86
+ * Connected session response that also carries a usable user id.
87
+ */
88
+ export type ConnectedSessionWithUserIdResponse = ConnectedSessionResponse & {
89
+ userId: SessionUserId;
90
+ };
91
+
92
+ /**
93
+ * Failure payload returned by Session Service.
94
+ *
95
+ * API and network failures usually reject with {@link SDKError}; this shape represents a failure
96
+ * payload when one is returned by Session Service and reaches the has-session flow.
97
+ */
98
+ export type SessionFailureResponse = {
99
+ /** Failure payload returned by Session Service. Usually an object, but tests also pass strings. */
100
+ error: string | number | boolean | object;
101
+ response?: {
102
+ /** Response status code. Example: 404. */
103
+ code: number;
104
+ /** Response type. Example: 'NOT_FOUND'. */
105
+ type: string;
106
+ /** Human-readable response description. Example: 'No session found'. */
107
+ description: string;
108
+ /** Cookie base domain used as the `SP_ID` cookie domain fallback. Example: 'spid.no'. */
109
+ baseDomain?: string;
110
+ /** Time span in milliseconds. Example: 30 * 60 * 1000 (for 30 minutes) */
111
+ expiresIn?: number;
112
+ result?: boolean;
113
+ /** Server time in seconds since the Unix Epoch. Example: 1506287788 */
114
+ serverTime?: number;
115
+ [key: string]: string | number | boolean | object | null | undefined;
116
+ };
117
+ };
118
+
119
+ /**
120
+ * Object response that does not match one of the SDK-known has-session shapes.
121
+ *
122
+ * This intentionally includes `{}`. Historically `hasSession()` could resolve an empty object or
123
+ * other object payloads that callers inspected themselves, so the SDK preserves those responses.
124
+ */
125
+ export type UnrecognizedSessionResponse = object;
126
+
127
+ export type RedirectSessionResponse = string;
128
+
129
+ export type SessionObjectResponse =
130
+ | SessionSuccessResponse
131
+ | SessionFailureResponse
132
+ | UnrecognizedSessionResponse;
133
+
134
+ export type RedirectSessionPayload = {
135
+ redirectURL: string;
136
+ };
137
+
138
+ export type NormalizedSessionPayload = SessionObjectResponse | RedirectSessionPayload;
139
+
140
+ /**
141
+ * Public response union returned from {@link Identity#hasSession}.
142
+ */
143
+ export type SessionResponse =
144
+ | SessionSuccessResponse
145
+ | SessionFailureResponse
146
+ | UnrecognizedSessionResponse
147
+ | RedirectSessionResponse;
@@ -2,20 +2,16 @@
2
2
  * See LICENSE.md in the project root.
3
3
  */
4
4
 
5
- 'use strict'
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
- * @memberof core
12
- * @param {string} url - A url like http://example.com, or a key used for lookup
13
- * @param {object<string,string>} urlMap - A map of URLs like
14
- * `{ DEV: 'http://dev.example.com' }`
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,9 +2,7 @@
2
2
  * See LICENSE.md in the project root.
3
3
  */
4
4
 
5
- 'use strict';
6
-
7
- import SDKError from './SDKError.js';
5
+ import SDKError from './sdk-error.js';
8
6
 
9
7
  /*
10
8
  * This module defines a set of validation functions which are used in the rest of the SDK.
@@ -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
- * @memberof core
20
- * @param {boolean} condition - The condition that we're asserting
21
- * @param {string} [message = Assertion failed] - The error message
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
- * @memberof core
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
- * @memberof core
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
- * @memberof core
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
- * @memberof core
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
- * @memberof core
74
- * @param {string} value - The string to be tested
75
- * @param {...string} mandatoryFields - A list of mandatory fields that should exist in the parsed
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 (urlParsingError) {
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
- * @memberof core
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
- * @memberof core
101
- * @param {string} value
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 {boolean} [caseSensitive=false] - Should the check be case sensitive
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;
@@ -1,5 +1,4 @@
1
1
  // Version is bumped automatically by release-please. See release-please-config.json.
2
2
 
3
- 'use strict'
4
- const version = '6.0.0-alpha.1'; // x-release-please-version
3
+ const version = '6.0.0-alpha.3'; // x-release-please-version
5
4
  export default version;
package/identity.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/identity.js";
package/identity.js DELETED
@@ -1,5 +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
- export { default, Identity } from './src/identity.js';
package/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from "./identity.js";
2
- export * from "./monetization.js";
3
- export * from "./payment.js";
4
- export { default as SDKError } from "./src/SDKError.js";
package/index.js DELETED
@@ -1,9 +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
- 'use strict';
6
-
7
- export * from './identity.js';
8
- export * from './monetization.js';
9
- export * from './payment.js';
package/monetization.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/monetization.js";
package/monetization.js DELETED
@@ -1,5 +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
- export { default, Monetization } from './src/monetization.js';
package/payment.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/payment.js";
package/payment.js DELETED
@@ -1,5 +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
- export { default, Payment } from './src/payment.js';
@@ -1,89 +0,0 @@
1
- /**
2
- * This class can be used for creating a wrapper around a server and all its endpoints.
3
- * Its functionality is extended by {@link JSONPClient}
4
- * Creates a client to a REST server. While useful stand-alone, it's also used for some other
5
- * types of client that change some functionalities.
6
- * @throws {SDKError} if any of options are invalid
7
- * @summary the simplest way to communicate to a REST endpoint without any
8
- * special authentication
9
- * @memberof core
10
- * @private
11
- */
12
- export class RESTClient {
13
- /**
14
- * Construct query string for WHATWG urls
15
- * @private
16
- * @param {object} query - Object to generate query string from
17
- * @param {boolean} useDefaultParams - Use defaultParams or not
18
- * @param {object} defaultParams - Default params
19
- * @returns {string} Query string
20
- */
21
- private static search;
22
- /**
23
- * @param {object} options
24
- * @param {string} [options.serverUrl=PRE] - The URL to the server eg.
25
- * https://login.schibsted.com or a URL key like 'DEV' in combination with {@link envDic}.
26
- * @param {object} [options.envDic] - A dictionary that will be used for looking up
27
- * {@link serverUrl} keys. If serverUrl is always a URL, you don't need this.
28
- * @param {function} [options.fetch=window.fetch] - The fetch function to use. It can be native
29
- * or a polyfill
30
- * @param {function} [options.log] - A function that will be called with log messages about
31
- * request and response
32
- * @param {object} [options.defaultParams={}] - a set of parameters to add to every call custom.
33
- * As long as it supports the standard fetch API we're good.
34
- */
35
- constructor({ serverUrl, envDic, fetch, log, defaultParams }: {
36
- serverUrl?: string;
37
- envDic?: any;
38
- fetch?: Function;
39
- log?: Function;
40
- defaultParams?: any;
41
- });
42
- url: URL;
43
- defaultParams: any;
44
- log: Function;
45
- fetch: Function;
46
- /**
47
- * Makes the actual call to the server and deals with headers, data objects and the edge cases.
48
- * Please note that this method expects the response to be in JSON format. However, it'll not
49
- * parse the response if its code is not in the 200 range.
50
- * @param {object} options - an obligatory options object
51
- * @param {string} options.method - can be 'GET', 'POST', 'DELETE', etc. case sensitive. To be
52
- * more specific, this can be one of the values that are passed to the `methods`
53
- * property of the constructor's `options` parameter.
54
- * @param {string} options.pathname - the path to the endpoint like 'api/2/endpoint-name'
55
- * @param {Object} [options.data={}] - data payload (depending on GET/DELETE or POST it may be a query
56
- * string or form body)
57
- * @param {array} [options.headers] - fetch options headers
58
- * @param {boolean} [options.useDefaultParams] - should we add the defaultParams to the query?
59
- * @param {object} [options.fetchOptions] - fetch options
60
- * @throws {SDKError} - if the call can't be made for whatever reason.
61
- * @return {Promise<object>} - A promise that will resolve to the call's response or reject if there
62
- * is an error before making the call or if the server returns a non-2xx error or
63
- * something that's not parsable as JSON.
64
- */
65
- go({ method, headers, pathname, data, useDefaultParams, fetchOptions }: {
66
- method: string;
67
- pathname: string;
68
- data?: any;
69
- headers?: any[];
70
- useDefaultParams?: boolean;
71
- fetchOptions?: any;
72
- }): Promise<any>;
73
- /**
74
- * Creates a url that points to an endpoint in the server
75
- * @param {string} [pathname=] - WHATWG pathname ie. 'api/2/endpoint-name'
76
- * @param {object} [query={}] - WHATWG query. It's the data payload.
77
- * @param {boolean} [useDefaultParams=true] - should we add the defaultParams to the query?
78
- * @return {string} - the resulting url string ready to pass to fetch
79
- */
80
- makeUrl(pathname?: string, query?: any, useDefaultParams?: boolean): string;
81
- /**
82
- * Make a GET request
83
- * @param {string} pathname - WHATWG pathname ie. 'api/2/endpoint-name'
84
- * @param {object} [data={}] - the data payload.
85
- * @return {Promise}
86
- */
87
- get(pathname: string, data?: any): Promise<any>;
88
- }
89
- export default RESTClient;
package/src/RESTClient.js DELETED
@@ -1,193 +0,0 @@
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
- 'use strict';
6
-
7
- import SDKError from './SDKError.js';
8
- import { cloneDefined } from './object.js';
9
- import { urlMapper } from './url.js';
10
- import { assert, isObject, isFunction, isStr, isNonEmptyString } from './validate.js';
11
-
12
- /**
13
- * Converts a series of parameters of various types to a string that's suitable for logging.
14
- * @private
15
- * @param {Array.<*>} msg - a number of parameters from any type (including objects)
16
- * @return {string}
17
- */
18
- const logString = (msg) => msg.map(m => isObject(m) ? JSON.stringify(m, null, 2) : m).join(' ');
19
-
20
- /**
21
- * Calls a log function passing a string
22
- * @private
23
- * @param {function} fn - the log function
24
- * @param {...*} msg - a series of message objects
25
- * @return {*} - The result of calling fn
26
- */
27
- const logFn = (fn, ...msg) => (typeof fn === 'function') && fn(logString(msg));
28
-
29
- /**
30
- * Encode a string like URLSearchParams would do
31
- * @private
32
- * @param {string} str - The input
33
- * @returns {string} The encoded string
34
- */
35
- function encode(str) {
36
- const replace = {
37
- '!': '%21',
38
- "'": '%27',
39
- '(': '%28',
40
- ')': '%29',
41
- '~': '%7E',
42
- '%20': '+',
43
- '%00': '\x00'
44
- };
45
- return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, match => replace[match]);
46
- }
47
-
48
- const globalFetch = () => window.fetch && window.fetch.bind(window);
49
-
50
- /**
51
- * This class can be used for creating a wrapper around a server and all its endpoints.
52
- * Its functionality is extended by {@link JSONPClient}
53
- * Creates a client to a REST server. While useful stand-alone, it's also used for some other
54
- * types of client that change some functionalities.
55
- * @throws {SDKError} if any of options are invalid
56
- * @summary the simplest way to communicate to a REST endpoint without any
57
- * special authentication
58
- * @memberof core
59
- * @private
60
- */
61
- export class RESTClient {
62
-
63
- /**
64
- * @param {object} options
65
- * @param {string} [options.serverUrl=PRE] - The URL to the server eg.
66
- * https://login.schibsted.com or a URL key like 'DEV' in combination with {@link envDic}.
67
- * @param {object} [options.envDic] - A dictionary that will be used for looking up
68
- * {@link serverUrl} keys. If serverUrl is always a URL, you don't need this.
69
- * @param {function} [options.fetch=window.fetch] - The fetch function to use. It can be native
70
- * or a polyfill
71
- * @param {function} [options.log] - A function that will be called with log messages about
72
- * request and response
73
- * @param {object} [options.defaultParams={}] - a set of parameters to add to every call custom.
74
- * As long as it supports the standard fetch API we're good.
75
- */
76
- constructor({ serverUrl = 'PRE', envDic, fetch = globalFetch(), log, defaultParams = {}}) {
77
- assert(isObject(defaultParams), `defaultParams should be a non-null object`);
78
-
79
- const mappedUrl = urlMapper(serverUrl, envDic);
80
- const handledServerUrl = mappedUrl.endsWith('/') ? mappedUrl : `${mappedUrl}/`;
81
- this.url = new URL(handledServerUrl);
82
-
83
- this.defaultParams = defaultParams;
84
-
85
- if (log) {
86
- assert(isFunction(log), `log must be a function but it is ${log}`);
87
- this.log = log;
88
- }
89
-
90
- if (fetch) {
91
- assert(isFunction(fetch), 'Fetch should be a function');
92
- this.fetch = fetch;
93
- }
94
- }
95
-
96
- /**
97
- * Makes the actual call to the server and deals with headers, data objects and the edge cases.
98
- * Please note that this method expects the response to be in JSON format. However, it'll not
99
- * parse the response if its code is not in the 200 range.
100
- * @param {object} options - an obligatory options object
101
- * @param {string} options.method - can be 'GET', 'POST', 'DELETE', etc. case sensitive. To be
102
- * more specific, this can be one of the values that are passed to the `methods`
103
- * property of the constructor's `options` parameter.
104
- * @param {string} options.pathname - the path to the endpoint like 'api/2/endpoint-name'
105
- * @param {Object} [options.data={}] - data payload (depending on GET/DELETE or POST it may be a query
106
- * string or form body)
107
- * @param {array} [options.headers] - fetch options headers
108
- * @param {boolean} [options.useDefaultParams] - should we add the defaultParams to the query?
109
- * @param {object} [options.fetchOptions] - fetch options
110
- * @throws {SDKError} - if the call can't be made for whatever reason.
111
- * @return {Promise<object>} - A promise that will resolve to the call's response or reject if there
112
- * is an error before making the call or if the server returns a non-2xx error or
113
- * something that's not parsable as JSON.
114
- */
115
- async go({
116
- method,
117
- headers,
118
- pathname,
119
- data = {},
120
- useDefaultParams = true,
121
- fetchOptions = { method, credentials: 'include' }
122
- }) {
123
- assert(isFunction(this.fetch),
124
- `Can't make a call. The reference to fetch is missing or not a function.`);
125
- assert(isNonEmptyString(method), `Method must be a non empty string but it is "${method}"`);
126
- assert(isNonEmptyString(pathname), `Pathname must be string but it is "${pathname}"`);
127
- assert(isObject(data), `data must be a non-null object`);
128
-
129
- fetchOptions.headers = isObject(headers) ? cloneDefined(headers) : {};
130
- const fullUrl = this.makeUrl(pathname, data, useDefaultParams);
131
-
132
- logFn(this.log, 'Request:', fetchOptions.method.toUpperCase(), fullUrl);
133
- logFn(this.log, 'Request Headers:', fetchOptions.headers);
134
- logFn(this.log, 'Request Body:', fetchOptions.body);
135
- try {
136
- const response = await this.fetch(fullUrl, fetchOptions);
137
- logFn(this.log, 'Response Code:', response.status, response.statusText);
138
- if (!response.ok) {
139
- // status code not in range 200-299
140
- throw new SDKError(response.statusText, { code: response.status });
141
- }
142
- const responseObject = await response.json();
143
- logFn(this.log, 'Response Parsed:', responseObject);
144
- return responseObject;
145
- } catch (err) {
146
- let msg = isStr(err) ? err : 'Unknown RESTClient error';
147
- if (isObject(err) && isStr(err.message)) {
148
- msg = err.message;
149
- }
150
- throw new SDKError(`Failed to '${method}' '${fullUrl}': '${msg}'`, err);
151
- }
152
- }
153
-
154
- /**
155
- * Creates a url that points to an endpoint in the server
156
- * @param {string} [pathname=] - WHATWG pathname ie. 'api/2/endpoint-name'
157
- * @param {object} [query={}] - WHATWG query. It's the data payload.
158
- * @param {boolean} [useDefaultParams=true] - should we add the defaultParams to the query?
159
- * @return {string} - the resulting url string ready to pass to fetch
160
- */
161
- makeUrl(pathname = '', query = {}, useDefaultParams = true) {
162
- const handledPathname = pathname.startsWith('/') ? pathname.slice(1) : pathname;
163
-
164
- const url = new URL(handledPathname, this.url);
165
- url.search = RESTClient.search(query, useDefaultParams, this.defaultParams);
166
- return url.href;
167
- }
168
-
169
- /**
170
- * Make a GET request
171
- * @param {string} pathname - WHATWG pathname ie. 'api/2/endpoint-name'
172
- * @param {object} [data={}] - the data payload.
173
- * @return {Promise}
174
- */
175
- get(pathname, data) {
176
- return this.go({ method: 'get', pathname, data });
177
- }
178
-
179
- /**
180
- * Construct query string for WHATWG urls
181
- * @private
182
- * @param {object} query - Object to generate query string from
183
- * @param {boolean} useDefaultParams - Use defaultParams or not
184
- * @param {object} defaultParams - Default params
185
- * @returns {string} Query string
186
- */
187
- static search(query, useDefaultParams, defaultParams) {
188
- const params = useDefaultParams ? cloneDefined(defaultParams, query) : cloneDefined(query);
189
- return Object.keys(params).filter(p => params[p]!=='').map(p => `${encode(p)}=${encode(params[p])}`).join('&');
190
- }
191
- }
192
-
193
- export default RESTClient;
package/src/SDKError.d.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Represents a SDK error. This is returned from all rejected promises that are returned from an API
3
- * call. Constructs an SDK error ready to throw
4
- * @summary When the SDK throws an error, it's supposed to be an instance of this class
5
- * @private
6
- */
7
- export default class SDKError extends Error {
8
- /**
9
- * @property {number} code - The HTTP error code
10
- * @extends {Error}
11
- * @param {string} message - The error message
12
- * @param {object} [errorObject] - The error object that was returned from the server. Any
13
- * property of errorObject object will be copied into this instance SDKError
14
- */
15
- constructor(message: string, errorObject?: any);
16
- }