Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support unique credential cookie names #560

Merged
merged 17 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
src/events/*
src/events/*
**/src/loader-npm-rum.ts
**/src/loader-npm-rum-2.ts
9 changes: 9 additions & 0 deletions .github/scripts/update_smoke_test.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ GUEST_ARN=$3
IDENTITY_POOL=$4
ENDPOINT=$5
CDN=$6
MONITOR_ID_2=$7
GUEST_ARN_2=$8
IDENTITY_POOL_2=$9
VERSION=$(npm pkg get version | sed 's/"//g')/cwr.js
CDN+=${VERSION}

Expand All @@ -16,6 +19,12 @@ awk '{sub(/\$MONITOR_ID/,MONITOR_ID);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub
awk '{sub(/\$MONITOR_ID/,MONITOR_ID);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN/,GUEST_ARN);sub(/\$IDENTITY_POOL/,IDENTITY_POOL);sub(/\$ENDPOINT/,ENDPOINT);}1' \
MONITOR_ID="'$MONITOR_ID'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN="'$GUEST_ARN'" IDENTITY_POOL="'$IDENTITY_POOL'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-NPM-ES/src/loader-npm-rum.ts > smoke/smoke-test-application-NPM-ES/src/loader-npm-rum-tmp.ts

awk '{sub(/\$MONITOR_ID_2/,MONITOR_ID_2);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN_2/,GUEST_ARN_2);sub(/\$IDENTITY_POOL_2/,IDENTITY_POOL_2);sub(/\$ENDPOINT/,ENDPOINT);}1' \
MONITOR_ID_2="'$MONITOR_ID_2'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN_2="'$GUEST_ARN_2'" IDENTITY_POOL_2="'$IDENTITY_POOL_2'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-NPM-ES/src/loader-npm-rum-2.ts > smoke/smoke-test-application-NPM-ES/src/loader-npm-rum-tmp-2.ts

# Module CJS
awk '{sub(/\$MONITOR_ID/,MONITOR_ID);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN/,GUEST_ARN);sub(/\$IDENTITY_POOL/,IDENTITY_POOL);sub(/\$ENDPOINT/,ENDPOINT);}1' \
MONITOR_ID="'$MONITOR_ID'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN="'$GUEST_ARN'" IDENTITY_POOL="'$IDENTITY_POOL'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum.ts > smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum-tmp.ts

awk '{sub(/\$MONITOR_ID_2/,MONITOR_ID_2);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN_2/,GUEST_ARN_2);sub(/\$IDENTITY_POOL_2/,IDENTITY_POOL_2);sub(/\$ENDPOINT/,ENDPOINT);}1' \
MONITOR_ID_2="'$MONITOR_ID_2'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN_2="'$GUEST_ARN_2'" IDENTITY_POOL_2="'$IDENTITY_POOL_2'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum-2.ts > smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum-tmp-2.ts
2 changes: 2 additions & 0 deletions .github/scripts/upload_smoke_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ aws s3api put-object --bucket $bucket --key "smoke-$version.html" --body process
# NPM ES
aws s3api put-object --bucket $bucket --key "npm/es/$version/smoke.html" --body smoke/smoke-test-application-NPM-ES/app/smoke.html --content-type "text/html"
aws s3api put-object --bucket $bucket --key "npm/es/$version/loader_npm_rum_tmp.js" --body smoke/smoke-test-application-NPM-ES/build/dev/loader_npm_rum_tmp.js --content-type application/x-javascript
aws s3api put-object --bucket $bucket --key "npm/es/$version/loader_npm_rum_tmp_2.js" --body smoke/smoke-test-application-NPM-ES/build/dev/loader_npm_rum_tmp_2.js --content-type application/x-javascript

# NPM CJS
aws s3api put-object --bucket $bucket --key "npm/cjs/$version/smoke.html" --body smoke/smoke-test-application-NPM-CJS/app/smoke.html --content-type "text/html"
aws s3api put-object --bucket $bucket --key "npm/cjs/$version/loader_npm_rum_tmp.js" --body smoke/smoke-test-application-NPM-CJS/build/dev/loader_npm_rum_tmp.js --content-type application/x-javascript
aws s3api put-object --bucket $bucket --key "npm/cjs/$version/loader_npm_rum_tmp_2.js" --body smoke/smoke-test-application-NPM-CJS/build/dev/loader_npm_rum_tmp_2.js --content-type application/x-javascript
7 changes: 5 additions & 2 deletions .github/workflows/cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
id: update-smoke-test-gamma-cdn
run: |
chmod u+x .github/scripts/update_smoke_test.sh
.github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN_GAMMA }}
.github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN_GAMMA }} ${{ secrets.SMOKE_MONITOR_2 }} ${{ secrets.SMOKE_ARN_2 }} ${{ secrets.SMOKE_IDENTITY_2 }}

- name: Build Smoke Test Application - NPM/ES
id: build-npm-es-application-pre-release
Expand All @@ -98,6 +98,7 @@ jobs:
env:
URL: ${{ secrets.SMOKE_URL }}
MONITOR: ${{ secrets.SMOKE_MONITOR }}
MONITOR2: ${{ secrets.SMOKE_MONITOR_2 }}
ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
INSTALL_METHOD: 'NPM-ES'
Expand All @@ -110,6 +111,7 @@ jobs:
env:
URL: ${{ secrets.SMOKE_URL }}
MONITOR: ${{ secrets.SMOKE_MONITOR }}
MONITOR_2: ${{ secrets.SMOKE_MONITOR_2 }}
ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
INSTALL_METHOD: 'NPM-CJS'
Expand Down Expand Up @@ -168,7 +170,7 @@ jobs:
id: update-smoke-test-prod-cdn
run: |
chmod u+x .github/scripts/update_smoke_test.sh
.github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }}
.github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} ${{ secrets.SMOKE_MONITOR_2 }} ${{ secrets.SMOKE_ARN_2 }} ${{ secrets.SMOKE_IDENTITY_2 }}

- name: Upload Prod Smoke Tests to CloudFront
id: upload-smoke-test-prod
Expand All @@ -180,6 +182,7 @@ jobs:
env:
URL: ${{ secrets.SMOKE_URL }}
MONITOR: ${{ secrets.SMOKE_MONITOR }}
MONITOR_2: ${{ secrets.SMOKE_MONITOR_2 }}
ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
INSTALL_METHOD: 'CDN'
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/cdn_rollback.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
id: update-smoke-test
run: |
chmod u+x .github/scripts/update_smoke_test.sh
.github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} >> processed_smoke.html
.github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} ${{ secrets.SMOKE_MONITOR_2 }} ${{ secrets.SMOKE_ARN_2 }} ${{ secrets.SMOKE_IDENTITY_2 }} >> processed_smoke.html

- name: Upload Smoke Test to CloudFront
id: upload-smoke-test
Expand All @@ -81,6 +81,7 @@ jobs:
env:
URL: ${{ secrets.SMOKE_URL }}
MONITOR: ${{ secrets.SMOKE_MONITOR }}
MONITOR_2: ${{ secrets.SMOKE_MONITOR_2 }}
ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
run: npm run smoke:headless
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ For example, the config object may look similar to the following:
| path | String | `/` | See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent |
| sameSite | Boolean | `true` | See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent |
| secure | Boolean | `true` | See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent |
| unique | Boolean | `false` | When this field is `false`, the session cookie name is `cwr_s`. When this field is `true`, the session cookie name is `cwr_s_[AppMonitor Id]`.<br/><br/>Set this field to `true` when multiple AppMonitors will monitor the same page. For example, this might be the case if one AppMonitor is used for logged-in users, and a second AppMonitor is used for guest users. |
| unique | Boolean | `false` | When this field is `false`, the session cookie name is `cwr_s` and the credential cookie name is `cwr_c`. When this field is `true`, the session cookie name is `cwr_s_[AppMonitor Id]` and the credential cookie name is `cwr_c_[AppMonitor Id]`.<br/><br/>Set this field to `true` when multiple AppMonitors will monitor the same page. For example, this might be the case if one AppMonitor is used for logged-in users, and a second AppMonitor is used for guest users. |

## MetadataAttributes

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@
"preinteg:local:nightwatch:firefox": "http-server ./build/dev -s &",
"integ:local:nightwatch:firefox": "nightwatch -e firefox",
"postinteg:local:nightwatch:firefox": "kill $(lsof -t -i:8080)",
"smoke:local:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version npx playwright test --config=playwright.local.config.ts",
"smoke:local": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version npx playwright test --config=playwright.local.config.ts --headed",
"smoke:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version INSTALL_METHOD=$INSTALL_METHOD npx playwright test --config=playwright.config.ts",
"smoke:local:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version MONITOR_ID_2=$MONITOR_ID_2 npx playwright test --config=playwright.local.config.ts",
"smoke:local": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version MONITOR_ID_2=$MONITOR_ID_2 npx playwright test --config=playwright.local.config.ts --headed",
"smoke:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version INSTALL_METHOD=$INSTALL_METHOD MONITOR_ID_2=$MONITOR_ID_2 npx playwright test --config=playwright.config.ts",
"prepare": "husky install"
},
"devDependencies": {
Expand Down
13 changes: 13 additions & 0 deletions smoke/smoke-test-application-NPM-CJS/app/smoke.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
<title>RUM Smoke Test</title>

<script type="text/javascript" src="./loader_npm_rum_tmp.js"></script>
<script>
function loadScriptWithDelay() {
setTimeout(function () {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = './loader_npm_rum_tmp_2.js';
document.head.appendChild(script);
}, 10000); // 10 seconds
}

// Call the function to load the script with a delay
loadScriptWithDelay();
</script>

<link
rel="icon"
Expand Down
32 changes: 32 additions & 0 deletions smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum-2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// @ts-nocheck
const { AwsRum, AwsRumConfig } = require('aws-rum-web');

let awsRum;

try {
const config: AwsRumConfig = {
sessionSampleRate: 1,
identityPoolId: $IDENTITY_POOL_2,
endpoint: $ENDPOINT,
telemetries: ['performance', 'errors', 'http', 'interaction'],
allowCookies: true,
enableXRay: true,
cookieAttributes: {
unique: true
}
};

const APPLICATION_ID: string = $MONITOR_ID_2;
const APPLICATION_VERSION: string = '1.0.0';
const APPLICATION_REGION: string = $REGION;

awsRum: AwsRum = new AwsRum(
APPLICATION_ID,
APPLICATION_VERSION,
APPLICATION_REGION,
config
);
} catch (error) {
console.log(error);
throw error;
}
5 changes: 4 additions & 1 deletion smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ try {
endpoint: $ENDPOINT,
telemetries: ['performance', 'errors', 'http', 'interaction'],
allowCookies: true,
enableXRay: true
enableXRay: true,
cookieAttributes: {
unique: true
}
};

const APPLICATION_ID: string = $MONITOR_ID;
Expand Down
3 changes: 2 additions & 1 deletion smoke/smoke-test-application-NPM-CJS/webpack/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ module.exports = {
devtool: 'inline-source-map',
target: ['web', 'es5'],
entry: {
loader_npm_rum_tmp: './src/loader-npm-rum-tmp.ts'
loader_npm_rum_tmp: './src/loader-npm-rum-tmp.ts',
loader_npm_rum_tmp_2: './src/loader-npm-rum-tmp-2.ts'
},
resolve: {
extensions: ['.ts', '.js', '.json'],
Expand Down
13 changes: 13 additions & 0 deletions smoke/smoke-test-application-NPM-ES/app/smoke.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
<title>RUM Smoke Test</title>

<script type="text/javascript" src="./loader_npm_rum_tmp.js"></script>
<script>
function loadScriptWithDelay() {
setTimeout(function () {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = './loader_npm_rum_tmp_2.js';
document.head.appendChild(script);
}, 10000); // 10 seconds
}

// Call the function to load the script with a delay
loadScriptWithDelay();
</script>

<link
rel="icon"
Expand Down
32 changes: 32 additions & 0 deletions smoke/smoke-test-application-NPM-ES/src/loader-npm-rum-2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// @ts-nocheck
import { AwsRum, AwsRumConfig } from 'aws-rum-web';

let awsRum;

try {
const config: AwsRumConfig = {
sessionSampleRate: 1,
identityPoolId: $IDENTITY_POOL_2,
endpoint: $ENDPOINT,
telemetries: ['performance', 'errors', 'http', 'interaction'],
allowCookies: true,
enableXRay: true,
cookieAttributes: {
unique: true
}
};

const APPLICATION_ID: string = $MONITOR_ID_2;
const APPLICATION_VERSION: string = '1.0.0';
const APPLICATION_REGION: string = $REGION;

awsRum: AwsRum = new AwsRum(
APPLICATION_ID,
APPLICATION_VERSION,
APPLICATION_REGION,
config
);
} catch (error) {
console.log(error);
throw error;
}
6 changes: 5 additions & 1 deletion smoke/smoke-test-application-NPM-ES/src/loader-npm-rum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-nocheck
import { AwsRum, AwsRumConfig } from 'aws-rum-web';

let awsRum;

try {
Expand All @@ -9,7 +10,10 @@ try {
endpoint: $ENDPOINT,
telemetries: ['performance', 'errors', 'http', 'interaction'],
allowCookies: true,
enableXRay: true
enableXRay: true,
cookieAttributes: {
unique: true
}
};

const APPLICATION_ID: string = $MONITOR_ID;
Expand Down
3 changes: 2 additions & 1 deletion smoke/smoke-test-application-NPM-ES/webpack/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ module.exports = {
devtool: 'inline-source-map',
target: ['web', 'es5'],
entry: {
loader_npm_rum_tmp: './src/loader-npm-rum-tmp.ts'
loader_npm_rum_tmp: './src/loader-npm-rum-tmp.ts',
loader_npm_rum_tmp_2: './src/loader-npm-rum-tmp-2.ts'
},
resolve: {
extensions: ['.ts', '.js', '.json']
Expand Down
14 changes: 14 additions & 0 deletions src/__smoke-test-npm__/dataplane-integ.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import {
// Environment variables set through CLI command
const ENDPOINT = process.env.ENDPOINT;
const MONITOR_ID = process.env.MONITOR;
const MONITOR_ID_2 = process.env.MONITOR_ID_2;
const TEST_URL = getUrl(
process.env.URL,
process.env.VERSION,
process.env.INSTALL_METHOD
);
const TARGET_URL = ENDPOINT + MONITOR_ID;
const TARGET_URL_2 = ENDPOINT + MONITOR_ID_2;

test('when web client calls PutRumEvents then the response code is 200', async ({
page
Expand All @@ -33,6 +35,18 @@ test('when web client calls PutRumEvents then the response code is 200', async (
);
});

test('when cookies are unique and web client calls PutRumEvents then the response code for second app monitor is 200', async ({
page
}) => {
// Open page
await page.goto(TEST_URL);

// Test will timeout if no successful dataplane request is found
await page.waitForResponse(async (response) =>
isDataPlaneRequest(response, TARGET_URL_2)
);
});

test('when web client calls PutRumEvents then the payload contains all events', async ({
page
}) => {
Expand Down
14 changes: 11 additions & 3 deletions src/dispatch/Authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ export abstract class Authentication {
protected cognitoIdentityClient: CognitoIdentityClient;
protected config: Config;
protected credentials: AwsCredentialIdentity | undefined;
protected credentialStorageKey: string;

constructor(config: Config) {
constructor(config: Config, applicationId: string) {
const region: string = config.identityPoolId!.split(':')[0];
this.config = config;
this.cognitoIdentityClient = new CognitoIdentityClient({
limhjgrace marked this conversation as resolved.
Show resolved Hide resolved
fetchRequestHandler: new FetchHttpHandler(),
region
region,
clientConfig: config,
applicationId
});
this.credentialStorageKey = this.config.cookieAttributes.unique
? `${CRED_KEY}_${applicationId}`
: CRED_KEY;
}

/**
Expand Down Expand Up @@ -80,7 +86,9 @@ export abstract class Authentication {
return new Promise<AwsCredentialIdentity>((resolve, reject) => {
let credentials: AwsCredentialIdentity;
try {
credentials = JSON.parse(localStorage.getItem(CRED_KEY)!);
credentials = JSON.parse(
localStorage.getItem(this.credentialStorageKey)!
);
} catch (e) {
// Error retrieving, decoding or parsing the cred string -- abort
return reject();
Expand Down
7 changes: 3 additions & 4 deletions src/dispatch/BasicAuthentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import { Config } from '../orchestration/Orchestration';
import { AwsCredentialIdentity } from '@aws-sdk/types';
import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler';
import { StsClient } from './StsClient';
import { CRED_KEY } from '../utils/constants';
import { Authentication } from './Authentication';

export class BasicAuthentication extends Authentication {
private stsClient: StsClient;

constructor(config: Config) {
super(config);
constructor(config: Config, applicationId: string) {
super(config, applicationId);
const region: string = config.identityPoolId!.split(':')[0];
this.stsClient = new StsClient({
fetchRequestHandler: new FetchHttpHandler(),
Expand Down Expand Up @@ -51,7 +50,7 @@ export class BasicAuthentication extends Authentication {
this.credentials = credentials;
try {
localStorage.setItem(
CRED_KEY,
this.credentialStorageKey,
JSON.stringify(credentials)
);
} catch (e) {
Expand Down
Loading
Loading