Skip to content

Commit 1b7e74c

Browse files
authored
release: Amplify JS release (#11661)
2 parents b5f8346 + a197d8b commit 1b7e74c

File tree

21 files changed

+240
-114
lines changed

21 files changed

+240
-114
lines changed

.circleci/config.yml

+27
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,23 @@ jobs:
15701570
spec: websocket-disruption
15711571
browser: << parameters.browser >>
15721572

1573+
integ_react_api_optimistic_ui:
1574+
parameters:
1575+
browser:
1576+
type: string
1577+
executor: js-test-executor
1578+
<<: *test_env_vars
1579+
working_directory: ~/amplify-js-samples-staging/samples/react/api/optimistic-ui
1580+
steps:
1581+
- prepare_test_env
1582+
- integ_test_js:
1583+
test_name: 'API (GraphQL) - Optimistic UI'
1584+
framework: react
1585+
category: api
1586+
sample_name: optimistic-ui
1587+
spec: optimistic-ui
1588+
browser: << parameters.browser >>
1589+
15731590
deploy:
15741591
executor: macos-executor
15751592
working_directory: ~/amplify-js
@@ -2237,6 +2254,15 @@ workflows:
22372254
matrix:
22382255
parameters:
22392256
<<: *minimal_browser_list
2257+
- integ_react_api_optimistic_ui:
2258+
requires:
2259+
- integ_setup
2260+
- build
2261+
filters:
2262+
<<: *releasable_branches
2263+
matrix:
2264+
parameters:
2265+
<<: *extended_browser_list
22402266
- deploy:
22412267
filters:
22422268
<<: *releasable_branches
@@ -2308,6 +2334,7 @@ workflows:
23082334
- integ_vanilla_js_datastore_basic_crud
23092335
- integ_react_datastore_docs_examples
23102336
- integ_react_datastore_websocket_disruption
2337+
- integ_react_api_optimistic_ui
23112338
- post_release:
23122339
filters:
23132340
branches:

license_config.json

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"**/lib-esm",
3232
"**/node_modules",
3333
"**/pushnotification",
34+
"**/polyfills/URL/*.js",
3435
"**/vendor",
3536
"**/__tests__",
3637
"**/__mocks__"

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"setup-dev": "yarn && yarn bootstrap && yarn link-all && yarn build",
88
"setup-dev:react-native": "node ./scripts/setup-dev-rn",
99
"bootstrap": "lerna bootstrap",
10-
"test": "lerna run test --stream",
10+
"test": "lerna run test --stream && yarn test:license",
1111
"test:size": "lerna run test:size --no-bail",
1212
"test:duplicates": "./scripts/duplicates-yarn.sh",
1313
"test:license": "license-check-and-add check -f license_config.json",

packages/api-rest/__tests__/RestAPI-test.ts

+29-50
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { Signer, Credentials, DateUtils } from '@aws-amplify/core';
55

66
jest.mock('axios');
77

8+
const mockAxios = jest.spyOn(axios as any, 'default');
9+
810
axios.CancelToken = <CancelTokenStatic>{
911
source: () => ({ token: null, cancel: null }),
1012
};
@@ -28,6 +30,7 @@ const config = {
2830

2931
afterEach(() => {
3032
jest.restoreAllMocks();
33+
mockAxios.mockClear();
3134
});
3235

3336
describe('Rest API test', () => {
@@ -166,19 +169,11 @@ describe('Rest API test', () => {
166169
api.configure(custom_config);
167170
const spyon = jest
168171
.spyOn(Credentials, 'get')
169-
.mockImplementationOnce(() => {
170-
return new Promise((res, rej) => {
171-
res('cred');
172-
});
173-
});
172+
.mockResolvedValueOnce('cred');
174173

175174
const spyonRequest = jest
176175
.spyOn(RestClient.prototype as any, '_request')
177-
.mockImplementationOnce(() => {
178-
return new Promise((res, rej) => {
179-
res({});
180-
});
181-
});
176+
.mockResolvedValueOnce({});
182177
await api.get('apiName', 'path', {});
183178

184179
expect(spyonRequest).toBeCalledWith(
@@ -221,25 +216,15 @@ describe('Rest API test', () => {
221216
session_token: 'token',
222217
};
223218

224-
const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => {
225-
return new Promise((res, rej) => {
226-
res(creds);
227-
});
228-
});
219+
const spyon = jest.spyOn(Credentials, 'get').mockResolvedValue(creds);
229220

230221
const spyonSigner = jest
231222
.spyOn(Signer, 'sign')
232223
.mockImplementationOnce(() => {
233224
return { headers: {} };
234225
});
235226

236-
const spyAxios = jest
237-
.spyOn(axios as any, 'default')
238-
.mockImplementationOnce(() => {
239-
return new Promise((res, rej) => {
240-
res(resp);
241-
});
242-
});
227+
mockAxios.mockResolvedValue(resp);
243228

244229
const init = {
245230
timeout: 2500,
@@ -297,13 +282,7 @@ describe('Rest API test', () => {
297282
return { headers: {} };
298283
});
299284

300-
const spyAxios = jest
301-
.spyOn(axios as any, 'default')
302-
.mockImplementationOnce(() => {
303-
return new Promise((res, rej) => {
304-
res(resp);
305-
});
306-
});
285+
mockAxios.mockResolvedValue(resp);
307286

308287
const init = {
309288
queryStringParameters: {
@@ -363,13 +342,7 @@ describe('Rest API test', () => {
363342
return { headers: {} };
364343
});
365344

366-
const spyAxios = jest
367-
.spyOn(axios as any, 'default')
368-
.mockImplementationOnce(() => {
369-
return new Promise((res, rej) => {
370-
res(resp);
371-
});
372-
});
345+
mockAxios.mockResolvedValue(resp);
373346

374347
const init = {
375348
queryStringParameters: {
@@ -429,13 +402,7 @@ describe('Rest API test', () => {
429402
return { headers: {} };
430403
});
431404

432-
const spyAxios = jest
433-
.spyOn(axios as any, 'default')
434-
.mockImplementationOnce(() => {
435-
return new Promise((res, rej) => {
436-
res(resp);
437-
});
438-
});
405+
mockAxios.mockResolvedValue(resp);
439406

440407
const init = {
441408
queryStringParameters: {
@@ -557,19 +524,31 @@ describe('Rest API test', () => {
557524
.mockImplementation(() => 'endpoint');
558525

559526
jest.spyOn(Credentials, 'get').mockResolvedValue('creds');
560-
561-
jest
562-
.spyOn(RestClient.prototype as any, '_signed')
563-
.mockRejectedValueOnce(normalError);
527+
jest.spyOn(RestClient.prototype as any, '_sign').mockReturnValue({
528+
...init,
529+
headers: { ...init.headers, Authorization: 'signed' },
530+
});
531+
mockAxios.mockImplementationOnce(() => {
532+
return new Promise((_, rej) => {
533+
rej(normalError);
534+
});
535+
});
564536

565537
await expect(api.post('url', 'path', init)).rejects.toThrow(normalError);
566538

567539
// Clock should not be skewed from normal errors
568540
expect(DateUtils.getClockOffset()).toBe(0);
569541

570-
jest
571-
.spyOn(RestClient.prototype as any, '_signed')
572-
.mockRejectedValueOnce(clockSkewError);
542+
// mock clock skew error response and successful response after retry
543+
mockAxios
544+
.mockImplementationOnce(() => {
545+
return new Promise((_, rej) => {
546+
rej(clockSkewError);
547+
});
548+
})
549+
.mockResolvedValue({
550+
data: [{ name: 'Bob' }],
551+
});
573552

574553
await expect(api.post('url', 'path', init)).resolves.toEqual([
575554
{ name: 'Bob' },

packages/api-rest/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"name": "API (rest client)",
5757
"path": "./lib-esm/index.js",
5858
"import": "{ Amplify, RestAPI }",
59-
"limit": "30.91 kB"
59+
"limit": "31 kB"
6060
}
6161
],
6262
"jest": {

packages/api-rest/src/RestClient.ts

+37-39
Original file line numberDiff line numberDiff line change
@@ -171,39 +171,42 @@ export class RestClient {
171171
return this._request(params, isAllResponse);
172172
}
173173

174-
// Signing the request in case there credentials are available
175-
return this.Credentials.get().then(
176-
credentials => {
177-
return this._signed({ ...params }, credentials, isAllResponse, {
178-
region,
179-
service,
180-
}).catch(error => {
181-
if (DateUtils.isClockSkewError(error)) {
182-
const { headers } = error.response;
183-
const dateHeader = headers && (headers.date || headers.Date);
184-
const responseDate = new Date(dateHeader);
185-
const requestDate = DateUtils.getDateFromHeaderString(
186-
params.headers['x-amz-date']
187-
);
188-
189-
// Compare local clock to the server clock
190-
if (DateUtils.isClockSkewed(responseDate)) {
191-
DateUtils.setClockOffset(
192-
responseDate.getTime() - requestDate.getTime()
193-
);
194-
195-
return this.ajax(urlOrApiInfo, method, init);
196-
}
197-
}
198-
199-
throw error;
200-
});
201-
},
202-
err => {
203-
logger.debug('No credentials available, the request will be unsigned');
204-
return this._request(params, isAllResponse);
174+
let credentials;
175+
try {
176+
credentials = await this.Credentials.get();
177+
} catch (error) {
178+
logger.debug('No credentials available, the request will be unsigned');
179+
return this._request(params, isAllResponse);
180+
}
181+
let signedParams;
182+
try {
183+
signedParams = this._sign({ ...params }, credentials, {
184+
region,
185+
service,
186+
});
187+
const response = await axios(signedParams);
188+
return isAllResponse ? response : response.data;
189+
} catch (error) {
190+
logger.debug(error);
191+
if (DateUtils.isClockSkewError(error)) {
192+
const { headers } = error.response;
193+
const dateHeader = headers && (headers.date || headers.Date);
194+
const responseDate = new Date(dateHeader);
195+
const requestDate = DateUtils.getDateFromHeaderString(
196+
signedParams.headers['x-amz-date']
197+
);
198+
199+
// Compare local clock to the server clock
200+
if (DateUtils.isClockSkewed(responseDate)) {
201+
DateUtils.setClockOffset(
202+
responseDate.getTime() - requestDate.getTime()
203+
);
204+
205+
return this.ajax(urlOrApiInfo, method, init);
206+
}
205207
}
206-
);
208+
throw error;
209+
}
207210
}
208211

209212
/**
@@ -356,7 +359,7 @@ export class RestClient {
356359

357360
/** private methods **/
358361

359-
private _signed(params, credentials, isAllResponse, { service, region }) {
362+
private _sign(params, credentials, { service, region }) {
360363
const { signerServiceInfo: signerServiceInfoParams, ...otherParams } =
361364
params;
362365

@@ -391,12 +394,7 @@ export class RestClient {
391394

392395
delete signed_params.headers['host'];
393396

394-
return axios(signed_params)
395-
.then(response => (isAllResponse ? response : response.data))
396-
.catch(error => {
397-
logger.debug(error);
398-
throw error;
399-
});
397+
return signed_params;
400398
}
401399

402400
private _request(params, isAllResponse = false) {

packages/core/__tests__/Platform-test.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,18 @@ describe('Platform test', () => {
2929
expect(
3030
getAmplifyUserAgentObject({
3131
category: Category.API,
32-
action: ApiAction.None,
32+
action: ApiAction.GraphQl,
33+
additionalInfo: [
34+
['amplify-ui', '1.x.x'],
35+
['uicomponent', '1'],
36+
],
3337
})
3438
).toStrictEqual([
3539
['aws-amplify', version],
36-
[Category.API, ApiAction.None],
40+
[Category.API, ApiAction.GraphQl],
3741
['framework', Framework.WebUnknown],
42+
['amplify-ui', '1.x.x'],
43+
['uicomponent', '1'],
3844
]);
3945
});
4046
});
@@ -50,10 +56,14 @@ describe('Platform test', () => {
5056
expect(
5157
getAmplifyUserAgent({
5258
category: Category.API,
53-
action: ApiAction.None,
59+
action: ApiAction.GraphQl,
60+
additionalInfo: [
61+
['amplify-ui', '1.x.x'],
62+
['uicomponent', '1'],
63+
],
5464
})
5565
).toBe(
56-
`${Platform.userAgent} ${Category.API}/${ApiAction.None} framework/${Framework.WebUnknown}`
66+
`${Platform.userAgent} ${Category.API}/${ApiAction.GraphQl} framework/${Framework.WebUnknown} amplify-ui/1.x.x uicomponent/1`
5767
);
5868
});
5969
});

packages/core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
"name": "Core (Credentials)",
105105
"path": "./lib-esm/index.js",
106106
"import": "{ Credentials }",
107-
"limit": "13.3 kB"
107+
"limit": "13.33 kB"
108108
},
109109
{
110110
"name": "Core (Signer)",

packages/core/src/Platform/index.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { CustomUserAgentDetails, Framework } from './types';
55
import { version } from './version';
66
import { detectFramework, observeFrameworkChanges } from './detectFramework';
7-
import { UserAgent as AWSUserAgent } from '@aws-sdk/types';
7+
import type { UserAgent as AWSUserAgent } from '@aws-sdk/types';
88

99
const BASE_USER_AGENT = `aws-amplify`;
1010

@@ -32,12 +32,17 @@ export const getAmplifyUserAgentObject = ({
3232
category,
3333
action,
3434
framework,
35+
additionalInfo,
3536
}: CustomUserAgentDetails = {}): AWSUserAgent => {
36-
const userAgent: AWSUserAgent = [[BASE_USER_AGENT, version]];
37+
let userAgent: AWSUserAgent = [[BASE_USER_AGENT, version]];
3738
if (category) {
3839
userAgent.push([category, action]);
3940
}
40-
userAgent.push(['framework', detectFramework()]);
41+
userAgent.push(['framework', framework || detectFramework()]);
42+
43+
if (additionalInfo) {
44+
userAgent = userAgent.concat(additionalInfo);
45+
}
4146

4247
return userAgent;
4348
};

0 commit comments

Comments
 (0)