@whereby.com/browser-sdk 2.0.0-alpha → 2.0.0-alpha1
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/dist/lib.cjs.js +5467 -0
- package/dist/lib.esm.js +5451 -0
- package/dist/types.d.ts +104 -0
- package/dist/v2-alpha1.js +105 -0
- package/package.json +2 -1
- package/.eslintrc +0 -23
- package/.github/actions/build/action.yml +0 -17
- package/.github/workflows/deploy.yml +0 -102
- package/.github/workflows/test.yml +0 -24
- package/.prettierignore +0 -7
- package/.prettierrc +0 -4
- package/.storybook/main.cjs +0 -16
- package/.storybook/preview.js +0 -9
- package/jest.config.js +0 -6
- package/rollup.config.js +0 -70
- package/src/lib/RoomConnection.ts +0 -516
- package/src/lib/RoomParticipant.ts +0 -77
- package/src/lib/__tests__/embed.unit.ts +0 -77
- package/src/lib/api/ApiClient.ts +0 -111
- package/src/lib/api/Credentials.ts +0 -45
- package/src/lib/api/HttpClient.ts +0 -95
- package/src/lib/api/MultipartHttpClient.ts +0 -53
- package/src/lib/api/OrganizationApiClient.ts +0 -64
- package/src/lib/api/Response.ts +0 -34
- package/src/lib/api/credentialsService/index.ts +0 -159
- package/src/lib/api/credentialsService/test/index.spec.ts +0 -181
- package/src/lib/api/deviceService/index.ts +0 -42
- package/src/lib/api/deviceService/tests/index.spec.ts +0 -74
- package/src/lib/api/extractUtils.ts +0 -160
- package/src/lib/api/index.ts +0 -8
- package/src/lib/api/localStorageWrapper/index.ts +0 -15
- package/src/lib/api/models/Account.ts +0 -48
- package/src/lib/api/models/Meeting.ts +0 -42
- package/src/lib/api/models/Organization.ts +0 -186
- package/src/lib/api/models/Room.ts +0 -44
- package/src/lib/api/models/account/EmbeddedFreeTierStatus.ts +0 -34
- package/src/lib/api/models/tests/Account.spec.ts +0 -128
- package/src/lib/api/models/tests/Organization.spec.ts +0 -161
- package/src/lib/api/models/tests/Room.spec.ts +0 -74
- package/src/lib/api/modules/AbstractStore.ts +0 -18
- package/src/lib/api/modules/ChromeStorageStore.ts +0 -44
- package/src/lib/api/modules/LocalStorageStore.ts +0 -57
- package/src/lib/api/modules/tests/ChromeStorageStore.spec.ts +0 -67
- package/src/lib/api/modules/tests/LocalStorageStore.spec.ts +0 -79
- package/src/lib/api/modules/tests/__mocks__/storage.ts +0 -24
- package/src/lib/api/organizationService/index.ts +0 -284
- package/src/lib/api/organizationService/tests/index.spec.ts +0 -781
- package/src/lib/api/organizationServiceCache/index.ts +0 -28
- package/src/lib/api/organizationServiceCache/tests/index.spec.ts +0 -101
- package/src/lib/api/parameterAssertUtils.ts +0 -166
- package/src/lib/api/roomService/index.ts +0 -310
- package/src/lib/api/roomService/tests/index.spec.ts +0 -668
- package/src/lib/api/test/ApiClient.spec.ts +0 -139
- package/src/lib/api/test/HttpClient.spec.ts +0 -120
- package/src/lib/api/test/MultipartHttpClient.spec.ts +0 -145
- package/src/lib/api/test/OrganizationApiClient.spec.ts +0 -132
- package/src/lib/api/test/extractUtils.spec.ts +0 -357
- package/src/lib/api/test/helpers.ts +0 -41
- package/src/lib/api/test/parameterAssertUtils.spec.ts +0 -265
- package/src/lib/api/types.ts +0 -6
- package/src/lib/embed.ts +0 -172
- package/src/lib/index.ts +0 -3
- package/src/lib/react/VideoElement.tsx +0 -16
- package/src/lib/react/index.ts +0 -3
- package/src/lib/react/useLocalMedia.ts +0 -25
- package/src/lib/react/useRoomConnection.ts +0 -92
- package/src/lib/reducer.ts +0 -142
- package/src/stories/custom-ui.stories.tsx +0 -133
- package/src/stories/prebuilt-ui.stories.tsx +0 -131
- package/src/stories/styles.css +0 -74
- package/src/types.d.ts +0 -175
- package/tsconfig.json +0 -30
package/src/lib/api/ApiClient.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import assert from "assert";
|
|
2
|
-
import nodeBtoa from "btoa";
|
|
3
|
-
import HttpClient, { HttpClientRequestConfig } from "./HttpClient";
|
|
4
|
-
import MultipartHttpClient from "./MultipartHttpClient";
|
|
5
|
-
import { assertString } from "./parameterAssertUtils";
|
|
6
|
-
import Credentials from "./Credentials";
|
|
7
|
-
import Response from "./Response";
|
|
8
|
-
|
|
9
|
-
let btoa: (str: string) => string;
|
|
10
|
-
if (typeof window === "object") {
|
|
11
|
-
btoa = window.btoa || nodeBtoa;
|
|
12
|
-
} else if (typeof global === "object") {
|
|
13
|
-
btoa = global.btoa || nodeBtoa;
|
|
14
|
-
} else {
|
|
15
|
-
btoa = nodeBtoa;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Create an object, which should be merged into the request header
|
|
20
|
-
* object, which deals with the header's authorisation
|
|
21
|
-
*/
|
|
22
|
-
function _getAuthHeader(credentials: Credentials | null) {
|
|
23
|
-
if (credentials && credentials.credentials) {
|
|
24
|
-
const btoaStr = `${credentials.credentials.uuid}:${credentials.hmac}`;
|
|
25
|
-
return { Authorization: `Basic ${btoa(btoaStr)}` };
|
|
26
|
-
}
|
|
27
|
-
return {};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface AuthenticatedHttpClientOptions {
|
|
31
|
-
httpClient: HttpClient;
|
|
32
|
-
fetchDeviceCredentials: () => Promise<Credentials | null>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const noCredentials: AuthenticatedHttpClientOptions["fetchDeviceCredentials"] = () => Promise.resolve(null);
|
|
36
|
-
|
|
37
|
-
class AuthenticatedHttpClient {
|
|
38
|
-
private _httpClient: AuthenticatedHttpClientOptions["httpClient"];
|
|
39
|
-
private _fetchDeviceCredentials: AuthenticatedHttpClientOptions["fetchDeviceCredentials"];
|
|
40
|
-
|
|
41
|
-
constructor({ httpClient, fetchDeviceCredentials }: AuthenticatedHttpClientOptions) {
|
|
42
|
-
this._httpClient = httpClient;
|
|
43
|
-
this._fetchDeviceCredentials = fetchDeviceCredentials;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
request(url: string, options: HttpClientRequestConfig): Promise<Response> {
|
|
47
|
-
return this._fetchDeviceCredentials().then((credentials) => {
|
|
48
|
-
const headers = Object.assign({}, options.headers, _getAuthHeader(credentials), {
|
|
49
|
-
"X-Appearin-Device-Platform": "web",
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const httpClientOptions = Object.assign({}, options, { headers });
|
|
53
|
-
|
|
54
|
-
return this._httpClient.request(url, httpClientOptions);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
interface ApiClientOptions {
|
|
60
|
-
baseUrl?: string;
|
|
61
|
-
fetchDeviceCredentials?: AuthenticatedHttpClientOptions["fetchDeviceCredentials"];
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Class used for all Whereby API calls.
|
|
65
|
-
*/
|
|
66
|
-
export default class ApiClient {
|
|
67
|
-
authenticatedHttpClient: AuthenticatedHttpClient;
|
|
68
|
-
authenticatedFormDataHttpClient: MultipartHttpClient;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Create an ApiClient instance.
|
|
72
|
-
*/
|
|
73
|
-
constructor({
|
|
74
|
-
baseUrl = "https://api.appearin.net",
|
|
75
|
-
fetchDeviceCredentials = noCredentials,
|
|
76
|
-
}: ApiClientOptions = {}) {
|
|
77
|
-
assertString(baseUrl, "baseUrl");
|
|
78
|
-
assert.ok(typeof fetchDeviceCredentials === "function", "fetchDeviceCredentials<Function> is required");
|
|
79
|
-
|
|
80
|
-
this.authenticatedHttpClient = new AuthenticatedHttpClient({
|
|
81
|
-
httpClient: new HttpClient({
|
|
82
|
-
baseUrl,
|
|
83
|
-
}),
|
|
84
|
-
fetchDeviceCredentials,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
this.authenticatedFormDataHttpClient = new MultipartHttpClient({ httpClient: this.authenticatedHttpClient });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Wrapper for the fetch API
|
|
92
|
-
*/
|
|
93
|
-
request(url: string, options: HttpClientRequestConfig): Promise<Response> {
|
|
94
|
-
assertString(url, "url");
|
|
95
|
-
assert.equal(url[0], "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
96
|
-
assert.ok(options, "options are required");
|
|
97
|
-
|
|
98
|
-
return this.authenticatedHttpClient.request(url, options);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Performs a multipart request where data is multipart/form-data encoded.
|
|
103
|
-
*/
|
|
104
|
-
requestMultipart(url: string, options: HttpClientRequestConfig): Promise<Response> {
|
|
105
|
-
assertString(url, "url");
|
|
106
|
-
assert.equal(url[0], "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
107
|
-
assert.ok(options, "options are required");
|
|
108
|
-
|
|
109
|
-
return this.authenticatedFormDataHttpClient.request(url, options);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { extractJson, extractNullOrString, extractString } from "./extractUtils";
|
|
2
|
-
import { Json } from "./Response";
|
|
3
|
-
|
|
4
|
-
interface CredentialsOptions {
|
|
5
|
-
uuid: string;
|
|
6
|
-
hmac: string;
|
|
7
|
-
userId?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default class Credentials {
|
|
11
|
-
credentials: {
|
|
12
|
-
uuid: CredentialsOptions["uuid"];
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
hmac: CredentialsOptions["hmac"];
|
|
16
|
-
userId: CredentialsOptions["userId"];
|
|
17
|
-
|
|
18
|
-
constructor(
|
|
19
|
-
uuid: CredentialsOptions["uuid"],
|
|
20
|
-
hmac: CredentialsOptions["hmac"],
|
|
21
|
-
userId: CredentialsOptions["userId"] = undefined
|
|
22
|
-
) {
|
|
23
|
-
this.credentials = {
|
|
24
|
-
uuid,
|
|
25
|
-
};
|
|
26
|
-
this.hmac = hmac;
|
|
27
|
-
this.userId = userId;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
toJson(): Json {
|
|
31
|
-
return {
|
|
32
|
-
credentials: this.credentials,
|
|
33
|
-
hmac: this.hmac,
|
|
34
|
-
...(this.userId && { userId: this.userId }),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static fromJson(json: Json): Credentials {
|
|
39
|
-
return new Credentials(
|
|
40
|
-
extractString(extractJson(json, "credentials"), "uuid"),
|
|
41
|
-
extractString(json, "hmac"),
|
|
42
|
-
extractNullOrString(json, "userId") || undefined
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import assert from "assert";
|
|
2
|
-
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
|
|
3
|
-
import Response, { ErrorResponseObject } from "./Response";
|
|
4
|
-
import { assertString } from "./parameterAssertUtils";
|
|
5
|
-
|
|
6
|
-
export type HttpClientRequestConfig =
|
|
7
|
-
| AxiosRequestConfig
|
|
8
|
-
| { [key: string]: any };
|
|
9
|
-
|
|
10
|
-
export interface IHttpClient {
|
|
11
|
-
request(url: string, options: HttpClientRequestConfig): Promise<Response>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function _getAbsoluteUrl({ baseUrl, url }: { baseUrl?: string; url: string }): string {
|
|
15
|
-
assert.ok(typeof url === "string", "url<String> is required");
|
|
16
|
-
return baseUrl ? baseUrl + url : url;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Class used for making http calls. This is just a pure
|
|
21
|
-
* wrapper around the http lib that we decide to use,
|
|
22
|
-
* so that we can switch implementations.
|
|
23
|
-
*/
|
|
24
|
-
export default class HttpClient implements IHttpClient {
|
|
25
|
-
_baseUrl: string;
|
|
26
|
-
/**
|
|
27
|
-
* Creates an HttpClient instance.
|
|
28
|
-
*
|
|
29
|
-
* @param {string} [baseUrl] - The base URL where all requests are made.
|
|
30
|
-
*/
|
|
31
|
-
constructor({ baseUrl }: { baseUrl: string }) {
|
|
32
|
-
assertString(baseUrl, "baseUrl");
|
|
33
|
-
|
|
34
|
-
this._baseUrl = baseUrl;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private _requestAxios(url: string, options: HttpClientRequestConfig): Promise<AxiosResponse> {
|
|
38
|
-
const axiosOptions = Object.assign({}, options, {
|
|
39
|
-
url,
|
|
40
|
-
baseURL: this._baseUrl,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return axios.request(axiosOptions);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Wrapper for the axios API
|
|
48
|
-
*
|
|
49
|
-
* @param {string} url - Required. URL (appended to base URL) where API call will be made
|
|
50
|
-
* @param {object} options - Required. Contains the data needed for the fetch API
|
|
51
|
-
* @return {Promise<Response>} - A promise which will return a Response object (https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
|
52
|
-
*/
|
|
53
|
-
request(url: string, options: HttpClientRequestConfig): Promise<Response> {
|
|
54
|
-
assertString(url, "url");
|
|
55
|
-
assert.equal(url[0], "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
56
|
-
assert.ok(options, "options are required");
|
|
57
|
-
|
|
58
|
-
return this._requestAxios(url, options)
|
|
59
|
-
.then((response) => {
|
|
60
|
-
const { data, headers, status, statusText, config } = response;
|
|
61
|
-
const requestUrl =
|
|
62
|
-
config && config.url ? _getAbsoluteUrl({ baseUrl: config.baseURL, url: config.url }) : null;
|
|
63
|
-
|
|
64
|
-
return new Response({
|
|
65
|
-
data,
|
|
66
|
-
headers,
|
|
67
|
-
status,
|
|
68
|
-
statusText,
|
|
69
|
-
url: requestUrl,
|
|
70
|
-
});
|
|
71
|
-
})
|
|
72
|
-
.catch((error: AxiosError) => {
|
|
73
|
-
const responseObject = error.response;
|
|
74
|
-
|
|
75
|
-
if (!responseObject) {
|
|
76
|
-
// Either server error or something else.
|
|
77
|
-
throw new Error("Could not make the request.");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const { data, headers, status, statusText, config } = responseObject as ErrorResponseObject;
|
|
81
|
-
const requestUrl =
|
|
82
|
-
config && config.url ? _getAbsoluteUrl({ baseUrl: config.baseURL, url: config.url }) : null;
|
|
83
|
-
|
|
84
|
-
return Promise.reject(
|
|
85
|
-
new Response({
|
|
86
|
-
data,
|
|
87
|
-
headers,
|
|
88
|
-
status,
|
|
89
|
-
statusText,
|
|
90
|
-
url: requestUrl,
|
|
91
|
-
})
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import assert from "assert";
|
|
2
|
-
import { HttpClientRequestConfig, IHttpClient } from "./HttpClient";
|
|
3
|
-
import Response from "./Response";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* ApiClient for doing multipart/form-data requests.
|
|
7
|
-
*/
|
|
8
|
-
export default class MultipartHttpClient implements IHttpClient {
|
|
9
|
-
_httpClient: IHttpClient;
|
|
10
|
-
|
|
11
|
-
constructor({ httpClient }: { httpClient: IHttpClient }) {
|
|
12
|
-
assert.ok(httpClient, "httpClient is required");
|
|
13
|
-
|
|
14
|
-
this._httpClient = httpClient;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Convert the provided object to a FormData object containing the same keys and values.
|
|
19
|
-
* @param {object} data - the data to convert.
|
|
20
|
-
* @returns {FormData}
|
|
21
|
-
*/
|
|
22
|
-
static dataToFormData(data: Record<string, string>): FormData {
|
|
23
|
-
assert.ok(data, "data is required");
|
|
24
|
-
|
|
25
|
-
const fd = new FormData();
|
|
26
|
-
Object.keys(data).forEach((key) => {
|
|
27
|
-
const value = data[key];
|
|
28
|
-
fd.append(key, value);
|
|
29
|
-
});
|
|
30
|
-
return fd;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Request a resource using multipart/form-data encoding.
|
|
35
|
-
*
|
|
36
|
-
* @param {string} url - the url to request
|
|
37
|
-
* @param {object} options - Required. Contains the data needed for the fetch API
|
|
38
|
-
* @return {Promise<Response>} - A promise which will return a Response object (https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
|
39
|
-
*/
|
|
40
|
-
request(url: string, options: HttpClientRequestConfig = {}): Promise<Response> {
|
|
41
|
-
const headers = Object.assign(options.headers || {}, {
|
|
42
|
-
"Content-Type": undefined,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
return this._httpClient.request(
|
|
46
|
-
url,
|
|
47
|
-
Object.assign(options, {
|
|
48
|
-
headers,
|
|
49
|
-
transformRequest: MultipartHttpClient.dataToFormData,
|
|
50
|
-
})
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import ApiClient from "./ApiClient";
|
|
2
|
-
import assert from "assert";
|
|
3
|
-
import { assertInstanceOf, assertString } from "./parameterAssertUtils";
|
|
4
|
-
import { HttpClientRequestConfig } from "./HttpClient";
|
|
5
|
-
import Response from "./Response";
|
|
6
|
-
import Organization from "./models/Organization";
|
|
7
|
-
|
|
8
|
-
const noOrganization = () => Promise.resolve(undefined);
|
|
9
|
-
|
|
10
|
-
export type FetchOrganizationFunction = () => Promise<Organization | undefined>;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Class used for all Whereby organization API calls.
|
|
14
|
-
*/
|
|
15
|
-
export default class OrganizationApiClient {
|
|
16
|
-
private _apiClient: ApiClient;
|
|
17
|
-
private _fetchOrganization: FetchOrganizationFunction;
|
|
18
|
-
/**
|
|
19
|
-
* Create an OrganizationApiClient instance.
|
|
20
|
-
*
|
|
21
|
-
* @param {ApiClient} [apiClient] - The apiClient to use.
|
|
22
|
-
* @param {Function} [fetchOrganization] - function that returns a promise with the organization.
|
|
23
|
-
*/
|
|
24
|
-
constructor({
|
|
25
|
-
apiClient,
|
|
26
|
-
fetchOrganization = noOrganization,
|
|
27
|
-
}: {
|
|
28
|
-
apiClient: ApiClient;
|
|
29
|
-
fetchOrganization?: FetchOrganizationFunction;
|
|
30
|
-
}) {
|
|
31
|
-
this._apiClient = assertInstanceOf(apiClient, ApiClient);
|
|
32
|
-
assert.ok(typeof fetchOrganization === "function", "fetchOrganization<Function> is required");
|
|
33
|
-
|
|
34
|
-
this._fetchOrganization = fetchOrganization;
|
|
35
|
-
this._apiClient = apiClient;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
_callRequestMethod(
|
|
39
|
-
method: "request" | "requestMultipart",
|
|
40
|
-
url: string,
|
|
41
|
-
options: HttpClientRequestConfig
|
|
42
|
-
): Promise<Response> {
|
|
43
|
-
assertString(url, "url");
|
|
44
|
-
assert.equal(url[0], "/", 'url<String> only accepts relative URLs beginning with "/".');
|
|
45
|
-
assert.ok(options, "options are required");
|
|
46
|
-
return this._fetchOrganization().then((organization) => {
|
|
47
|
-
if (!organization) {
|
|
48
|
-
return this._apiClient[method](url, options);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const { organizationId } = organization;
|
|
52
|
-
|
|
53
|
-
return this._apiClient[method](`/organizations/${encodeURIComponent(organizationId)}${url}`, options);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
request(url: string, options: HttpClientRequestConfig): Promise<Response> {
|
|
58
|
-
return this._callRequestMethod("request", url, options);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
requestMultipart(url: string, options: HttpClientRequestConfig): Promise<Response> {
|
|
62
|
-
return this._callRequestMethod("requestMultipart", url, options);
|
|
63
|
-
}
|
|
64
|
-
}
|
package/src/lib/api/Response.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2
|
-
export type Json = string | number | boolean | null | Array<Json> | { [key: string]: Json };
|
|
3
|
-
|
|
4
|
-
export type ErrorResponseObject = {
|
|
5
|
-
data?: Json;
|
|
6
|
-
headers?: Record<string, any>;
|
|
7
|
-
status?: number;
|
|
8
|
-
statusText?: string;
|
|
9
|
-
config?: { url?: string; baseURL?: string } | null;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
interface ResponseOptions {
|
|
13
|
-
data?: Json;
|
|
14
|
-
headers?: Record<string, any>;
|
|
15
|
-
status?: number;
|
|
16
|
-
statusText?: string;
|
|
17
|
-
url?: string | null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default class Response {
|
|
21
|
-
data: Json;
|
|
22
|
-
headers: Record<string, unknown>;
|
|
23
|
-
status: number;
|
|
24
|
-
statusText: string;
|
|
25
|
-
url: string | null;
|
|
26
|
-
|
|
27
|
-
constructor(initialValues: ResponseOptions = {}) {
|
|
28
|
-
this.data = initialValues.data === undefined ? {} : initialValues.data;
|
|
29
|
-
this.headers = initialValues.headers || {};
|
|
30
|
-
this.status = initialValues.status || 200;
|
|
31
|
-
this.statusText = initialValues.statusText || "OK";
|
|
32
|
-
this.url = initialValues.url || null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import EventEmitter from "events";
|
|
2
|
-
|
|
3
|
-
import DeviceService from "../deviceService/index";
|
|
4
|
-
import AbstractStore from "../modules/AbstractStore";
|
|
5
|
-
import ChromeStorageStore from "../modules/ChromeStorageStore";
|
|
6
|
-
import LocalStorageStore from "../modules/LocalStorageStore";
|
|
7
|
-
import { assertInstanceOf } from "../parameterAssertUtils";
|
|
8
|
-
import ApiClient from "../ApiClient";
|
|
9
|
-
import localStorage from "../localStorageWrapper";
|
|
10
|
-
import { Credentials } from "..";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Events triggered by this service
|
|
14
|
-
*/
|
|
15
|
-
export const events = {
|
|
16
|
-
CREDENTIALS_SAVED: "credentials_saved",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export default class CredentialsService extends EventEmitter {
|
|
20
|
-
_deviceService: DeviceService;
|
|
21
|
-
_credentialsStore: AbstractStore;
|
|
22
|
-
credentialsPromise?: Promise<Credentials | null>;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Service to manage Whereby's Rest API credentials.
|
|
26
|
-
*
|
|
27
|
-
* @param {ObjectStore} credentialsStore - Store to manage the credentials.
|
|
28
|
-
*/
|
|
29
|
-
constructor({
|
|
30
|
-
deviceService,
|
|
31
|
-
credentialsStore,
|
|
32
|
-
}: {
|
|
33
|
-
deviceService: DeviceService;
|
|
34
|
-
credentialsStore: AbstractStore;
|
|
35
|
-
}) {
|
|
36
|
-
super();
|
|
37
|
-
this._deviceService = assertInstanceOf(deviceService, DeviceService);
|
|
38
|
-
this._credentialsStore = credentialsStore;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
static create({
|
|
42
|
-
baseUrl,
|
|
43
|
-
storeName = "CredentialsStorage",
|
|
44
|
-
storeType = "localStorage",
|
|
45
|
-
}: {
|
|
46
|
-
baseUrl: string;
|
|
47
|
-
storeName?: string;
|
|
48
|
-
storeType?: "localStorage" | "chromeStorage";
|
|
49
|
-
}): CredentialsService {
|
|
50
|
-
const deviceService = new DeviceService({
|
|
51
|
-
apiClient: new ApiClient({ baseUrl }),
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
let credentialsStore = null;
|
|
55
|
-
|
|
56
|
-
if (storeType === "localStorage") {
|
|
57
|
-
credentialsStore = new LocalStorageStore(storeName, localStorage);
|
|
58
|
-
} else if (storeType === "chromeStorage") {
|
|
59
|
-
credentialsStore = new ChromeStorageStore(storeName, window["chrome"].storage.local);
|
|
60
|
-
} else {
|
|
61
|
-
throw new Error(`Unknown store type: ${storeType}`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return new CredentialsService({
|
|
65
|
-
deviceService,
|
|
66
|
-
credentialsStore,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Contacts the REST API to get new credentials. DO NOT USE directly, call getCredentials() instead.
|
|
71
|
-
*
|
|
72
|
-
* @see getCredentials
|
|
73
|
-
* @returns {Promise.<Credentials>} - Promise that resolves with the credentials.
|
|
74
|
-
*/
|
|
75
|
-
_fetchNewCredentialsFromApi(): Promise<Credentials | null> {
|
|
76
|
-
const credentialsStore = this._credentialsStore;
|
|
77
|
-
return new Promise((resolve) => {
|
|
78
|
-
const fetchCredentials = () => {
|
|
79
|
-
this._deviceService
|
|
80
|
-
.getCredentials()
|
|
81
|
-
.then((credentials) => {
|
|
82
|
-
return credentialsStore
|
|
83
|
-
.save(credentials ? credentials.toJson() : null)
|
|
84
|
-
.then(() => resolve(credentials));
|
|
85
|
-
})
|
|
86
|
-
.catch(() => {
|
|
87
|
-
setTimeout(fetchCredentials, 2000);
|
|
88
|
-
});
|
|
89
|
-
};
|
|
90
|
-
fetchCredentials();
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Returns the current credentials without triggering an API request to get new ones.
|
|
96
|
-
* If no credentials are currently available it will return null.
|
|
97
|
-
*
|
|
98
|
-
* @returns {?Credentials} - The credentials currently in use, null otherwise.
|
|
99
|
-
*/
|
|
100
|
-
getCurrentCredentials(): Promise<Credentials | null> {
|
|
101
|
-
return this._credentialsStore.loadOrDefault(null).then((json) => (json ? Credentials.fromJson(json) : null));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Returns a promise that will contain the credentials for this client.
|
|
106
|
-
* If no credentials are available in local storage, new ones will be fetched from the server.
|
|
107
|
-
*
|
|
108
|
-
* @returns {Promise.<Credentials>} - Promise that resolves with the credentials.
|
|
109
|
-
*/
|
|
110
|
-
getCredentials(): Promise<Credentials | null> {
|
|
111
|
-
if (!this.credentialsPromise) {
|
|
112
|
-
this.credentialsPromise = this.getCurrentCredentials().then((storedCredentials) => {
|
|
113
|
-
if (storedCredentials) {
|
|
114
|
-
return storedCredentials;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return this._fetchNewCredentialsFromApi();
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return this.credentialsPromise;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Saves new credentials which replace the existing ones and abort any pending request to get new ones.
|
|
126
|
-
*
|
|
127
|
-
* @param {Credentials} credentials - New credentials to store.
|
|
128
|
-
*/
|
|
129
|
-
saveCredentials(credentials: Credentials): Promise<Credentials> {
|
|
130
|
-
this.credentialsPromise = undefined;
|
|
131
|
-
return this._credentialsStore.save(credentials.toJson()).then(() => {
|
|
132
|
-
this.emit(events.CREDENTIALS_SAVED, credentials);
|
|
133
|
-
return credentials;
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* It will set the userId for the current credentials.
|
|
139
|
-
*
|
|
140
|
-
* @param userId - The user id to set.
|
|
141
|
-
*/
|
|
142
|
-
setUserId(userId: string | null): Promise<void> {
|
|
143
|
-
// Used to ensure that the userId is changed if localStorage has been modified by another tab
|
|
144
|
-
return this.getCurrentCredentials()
|
|
145
|
-
.then((storedCredentials) => {
|
|
146
|
-
if (!storedCredentials) {
|
|
147
|
-
console.error("Illegal state: no credentials to set user id for."); // eslint-disable-line no-console
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const userIdChangedFromLocalStorage = storedCredentials === null || storedCredentials.userId !== userId;
|
|
151
|
-
if (!userIdChangedFromLocalStorage) {
|
|
152
|
-
return undefined;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return this._credentialsStore.save(Object.assign({}, storedCredentials?.toJson(), { userId }));
|
|
156
|
-
})
|
|
157
|
-
.then(() => undefined);
|
|
158
|
-
}
|
|
159
|
-
}
|