@aws-amplify/api-rest 3.5.5 → 4.0.1-console-preview.047a1dd.0

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/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@aws-amplify/api-rest",
3
- "version": "3.5.5",
3
+ "private": false,
4
+ "version": "4.0.1-console-preview.047a1dd.0+047a1dd",
4
5
  "description": "Api-rest category of aws-amplify",
5
6
  "main": "./lib/index.js",
6
7
  "module": "./lib-esm/index.js",
@@ -16,19 +17,19 @@
16
17
  "access": "public"
17
18
  },
18
19
  "scripts": {
19
- "test": "npm run lint && jest --coverage",
20
- "test:size": "size-limit",
21
- "build-with-test": "npm test && npm run build",
22
- "build:cjs": "node ./build es5 && webpack && webpack --config ./webpack.config.dev.js",
23
- "build:esm": "node ./build es6",
24
- "build:cjs:watch": "node ./build es5 --watch",
25
- "build:esm:watch": "node ./build es6 --watch",
20
+ "test": "npm run lint && jest -w 1 --coverage",
21
+ "test:watch": "tslint 'src/**/*.ts' && jest -w 1 --watch",
22
+ "build-with-test": "npm run clean && npm test && tsc && webpack",
23
+ "build:cjs": "rimraf lib && tsc -m commonjs --outDir lib && webpack && webpack --config ./webpack.config.dev.js",
24
+ "build:esm": "rimraf lib-esm && tsc -m esnext --outDir lib-esm",
25
+ "build:cjs:watch": "rimraf lib && tsc -m commonjs --outDir lib --watch",
26
+ "build:esm:watch": "rimraf lib-esm && tsc -m esnext --outDir lib-esm --watch",
26
27
  "build": "npm run clean && npm run build:esm && npm run build:cjs",
27
28
  "clean": "npm run clean:size && rimraf lib-esm lib dist",
28
29
  "clean:size": "rimraf dual-publish-tmp tmp*",
29
30
  "format": "echo \"Not implemented\"",
30
31
  "lint": "tslint 'src/**/*.ts' && npm run ts-coverage",
31
- "ts-coverage": "typescript-coverage-report -p ./tsconfig.build.json -t 65.41"
32
+ "ts-coverage": "typescript-coverage-report -p ./tsconfig.json -t 70.0"
32
33
  },
33
34
  "repository": {
34
35
  "type": "git",
@@ -46,17 +47,23 @@
46
47
  "src"
47
48
  ],
48
49
  "dependencies": {
49
- "@aws-amplify/core": "5.8.5",
50
- "axios": "0.26.0",
51
- "tslib": "^1.8.0",
50
+ "axios": "1.5.0",
51
+ "tslib": "^2.5.0",
52
52
  "url": "0.11.0"
53
53
  },
54
+ "peerDependencies": {
55
+ "@aws-amplify/core": "6.0.1-console-preview.047a1dd.0+047a1dd"
56
+ },
57
+ "devDependencies": {
58
+ "@aws-amplify/core": "6.0.1-console-preview.047a1dd.0+047a1dd",
59
+ "typescript": "5.0.2"
60
+ },
54
61
  "size-limit": [
55
62
  {
56
63
  "name": "API (rest client)",
57
64
  "path": "./lib-esm/index.js",
58
65
  "import": "{ Amplify, RestAPI }",
59
- "limit": "31 kB"
66
+ "limit": "31.5 kB"
60
67
  }
61
68
  ],
62
69
  "jest": {
@@ -64,20 +71,17 @@
64
71
  "ts-jest": {
65
72
  "diagnostics": false,
66
73
  "tsConfig": {
67
- "lib": [
68
- "es5",
69
- "es2015",
70
- "dom",
71
- "esnext.asynciterable",
72
- "es2017.object"
73
- ],
74
- "allowJs": true
74
+ "allowJs": true,
75
+ "noEmitOnError": false
75
76
  }
76
77
  }
77
78
  },
78
79
  "transform": {
79
80
  "^.+\\.(js|jsx|ts|tsx)$": "ts-jest"
80
81
  },
82
+ "testPathIgnorePatterns": [
83
+ "/testUtils/"
84
+ ],
81
85
  "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$",
82
86
  "moduleFileExtensions": [
83
87
  "ts",
@@ -97,11 +101,14 @@
97
101
  }
98
102
  },
99
103
  "coveragePathIgnorePatterns": [
100
- "/node_modules/",
104
+ "node_modules",
101
105
  "dist",
102
106
  "lib",
103
107
  "lib-esm"
108
+ ],
109
+ "setupFiles": [
110
+ "<rootDir>/setupTests.ts"
104
111
  ]
105
112
  },
106
- "gitHead": "c3a06153e3ffe05dd65485a22b1f99aabe9b3d83"
113
+ "gitHead": "047a1dd83d54c8f3ee74e0766d96c6a3b9f97f90"
107
114
  }
package/src/API.ts ADDED
@@ -0,0 +1,17 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { RestClient } from './RestClient';
4
+ import { PostOptions } from './types';
5
+
6
+ const restClient = new RestClient({ headers: {}, endpoints: [] });
7
+ export function post(url: string, options: PostOptions) {
8
+ return restClient.post(url, options);
9
+ }
10
+
11
+ export function cancel(request: Promise<unknown>, message?: string) {
12
+ return restClient.cancel(request, message);
13
+ }
14
+
15
+ export function isCancel(error: Error) {
16
+ return restClient.isCancel(error);
17
+ }
package/src/RestClient.ts CHANGED
@@ -1,32 +1,13 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
-
4
3
  import {
5
- ConsoleLogger as Logger,
6
- Credentials,
7
- DateUtils,
8
- Signer,
4
+ AWSCredentialsAndIdentityId,
5
+ fetchAuthSession,
9
6
  } from '@aws-amplify/core';
10
-
11
- import { apiOptions, ApiInfo } from './types';
7
+ import { apiOptions } from './types';
12
8
  import axios, { CancelTokenSource } from 'axios';
13
9
  import { parse, format } from 'url';
14
-
15
- const logger = new Logger('RestClient');
16
-
17
- /**
18
- * HTTP Client for REST requests. Send and receive JSON data.
19
- * Sign request with AWS credentials if available
20
- * Usage:
21
- <pre>
22
- const restClient = new RestClient();
23
- restClient.get('...')
24
- .then(function(data) {
25
- console.log(data);
26
- })
27
- .catch(err => console.log(err));
28
- </pre>
29
- */
10
+ import { signRequest } from '@aws-amplify/core/internals/aws-client-utils';
30
11
  export class RestClient {
31
12
  private _options;
32
13
  private _region: string = 'us-east-1'; // this will be updated by endpoint function
@@ -47,166 +28,145 @@ export class RestClient {
47
28
  *
48
29
  * For more details, see https://github.com/aws-amplify/amplify-js/pull/3769#issuecomment-552660025
49
30
  */
50
- private _cancelTokenMap: WeakMap<any, CancelTokenSource> = null;
51
-
52
- Credentials = Credentials;
53
-
31
+ private _cancelTokenMap: WeakMap<Promise<any>, CancelTokenSource> | null =
32
+ null;
54
33
  /**
55
34
  * @param {RestClientOptions} [options] - Instance options
56
35
  */
57
36
  constructor(options: apiOptions) {
58
37
  this._options = options;
59
- logger.debug('API Options', this._options);
60
38
  if (this._cancelTokenMap == null) {
61
39
  this._cancelTokenMap = new WeakMap();
62
40
  }
63
41
  }
64
42
 
65
43
  /**
66
- * Update AWS credentials
67
- * @param {AWSCredentials} credentials - AWS credentials
68
- *
69
- updateCredentials(credentials: AWSCredentials) {
70
- this.options.credentials = credentials;
71
- }
72
- */
73
- /**
74
44
  * Basic HTTP request. Customizable
75
45
  * @param {string | ApiInfo } urlOrApiInfo - Full request URL or Api information
76
46
  * @param {string} method - Request HTTP method
77
47
  * @param {json} [init] - Request extra params
78
48
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
79
49
  */
80
- async ajax(urlOrApiInfo: string | ApiInfo, method: string, init) {
81
- logger.debug(method, urlOrApiInfo);
82
-
83
- let parsed_url;
84
- let url: string;
85
- let region: string = 'us-east-1';
86
- let service: string = 'execute-api';
87
- let custom_header: () => {
88
- [key: string]: string;
89
- } = undefined;
90
-
91
- if (typeof urlOrApiInfo === 'string') {
92
- parsed_url = this._parseUrl(urlOrApiInfo);
93
- url = urlOrApiInfo;
94
- } else {
95
- ({ endpoint: url, custom_header, region, service } = urlOrApiInfo);
96
- parsed_url = this._parseUrl(urlOrApiInfo.endpoint);
97
- }
50
+ ajax(url: string, method: string, init) {
51
+ const source = axios.CancelToken.source();
52
+ const promise = new Promise(async (res, rej) => {
53
+ const parsed_url = new URL(url);
54
+
55
+ const region: string = init.region || 'us-east-1';
56
+ const service: string = init.serviceName || 'execute-api';
57
+
58
+ const params = {
59
+ method,
60
+ url,
61
+ host: parsed_url.host,
62
+ path: parsed_url.pathname,
63
+ headers: {},
64
+ data: JSON.stringify(''),
65
+ responseType: 'json',
66
+ timeout: 0,
67
+ };
68
+
69
+ const libraryHeaders = {};
70
+ const initParams = Object.assign({}, init);
71
+ const isAllResponse = initParams.response;
72
+ if (initParams.body) {
73
+ if (
74
+ typeof FormData === 'function' &&
75
+ initParams.body instanceof FormData
76
+ ) {
77
+ libraryHeaders['Content-Type'] = 'multipart/form-data';
78
+ params.data = initParams.body;
79
+ } else {
80
+ libraryHeaders['Content-Type'] = 'application/json; charset=UTF-8';
81
+ params.data = JSON.stringify(initParams.body);
82
+ }
83
+ }
84
+ if (initParams.responseType) {
85
+ params.responseType = initParams.responseType;
86
+ }
87
+ if (initParams.withCredentials) {
88
+ params['withCredentials'] = initParams.withCredentials;
89
+ }
90
+ if (initParams.timeout) {
91
+ params.timeout = initParams.timeout;
92
+ }
98
93
 
99
- const params = {
100
- method,
101
- url,
102
- host: parsed_url.host,
103
- path: parsed_url.path,
104
- headers: {},
105
- data: null,
106
- responseType: 'json',
107
- timeout: 0,
108
- cancelToken: null,
109
- };
110
-
111
- const libraryHeaders = {};
112
- const initParams = Object.assign({}, init);
113
- const isAllResponse = initParams.response;
114
- if (initParams.body) {
94
+ params['signerServiceInfo'] = initParams.signerServiceInfo;
95
+
96
+ params.headers = {
97
+ ...libraryHeaders,
98
+ ...initParams.headers,
99
+ };
100
+
101
+ // Intentionally discarding search
102
+ const { search, ...parsedUrl } = parse(url, true, true);
103
+ params.url = format({
104
+ ...parsedUrl,
105
+ query: {
106
+ ...parsedUrl.query,
107
+ ...(initParams.queryStringParameters || {}),
108
+ },
109
+ });
110
+
111
+ // Do not sign the request if client has added 'Authorization' or x-api-key header,
112
+ // which means custom authorizer.
115
113
  if (
116
- typeof FormData === 'function' &&
117
- initParams.body instanceof FormData
114
+ (params.headers['Authorization'] &&
115
+ typeof params.headers['Authorization'] !== 'undefined') ||
116
+ (params.headers['X-Api-Key'] &&
117
+ typeof params.headers['X-Api-Key'] !== 'undefined')
118
118
  ) {
119
- libraryHeaders['Content-Type'] = 'multipart/form-data';
120
- params.data = initParams.body;
121
- } else {
122
- libraryHeaders['Content-Type'] = 'application/json; charset=UTF-8';
123
- params.data = JSON.stringify(initParams.body);
119
+ params.headers = Object.keys(params.headers).reduce((acc, k) => {
120
+ if (params.headers[k]) {
121
+ acc[k] = params.headers[k];
122
+ }
123
+ return acc;
124
+ // tslint:disable-next-line:align
125
+ }, {});
126
+
127
+ return res(await this._request(params, isAllResponse));
124
128
  }
125
- }
126
- if (initParams.responseType) {
127
- params.responseType = initParams.responseType;
128
- }
129
- if (initParams.withCredentials) {
130
- params['withCredentials'] = initParams.withCredentials;
131
- }
132
- if (initParams.timeout) {
133
- params.timeout = initParams.timeout;
134
- }
135
- if (initParams.cancellableToken) {
136
- params.cancelToken = initParams.cancellableToken.token;
137
- }
138
129
 
139
- params['signerServiceInfo'] = initParams.signerServiceInfo;
140
-
141
- // custom_header callback
142
- const custom_header_obj =
143
- typeof custom_header === 'function' ? await custom_header() : undefined;
144
-
145
- params.headers = {
146
- ...libraryHeaders,
147
- ...custom_header_obj,
148
- ...initParams.headers,
149
- };
150
-
151
- // Intentionally discarding search
152
- const { search, ...parsedUrl } = parse(url, true, true);
153
- params.url = format({
154
- ...parsedUrl,
155
- query: {
156
- ...parsedUrl.query,
157
- ...(initParams.queryStringParameters || {}),
158
- },
159
- });
130
+ let credentials: AWSCredentialsAndIdentityId;
160
131
 
161
- // Do not sign the request if client has added 'Authorization' header,
162
- // which means custom authorizer.
163
- if (typeof params.headers['Authorization'] !== 'undefined') {
164
- params.headers = Object.keys(params.headers).reduce((acc, k) => {
165
- if (params.headers[k]) {
166
- acc[k] = params.headers[k];
132
+ try {
133
+ const session = await fetchAuthSession();
134
+ if (
135
+ session.credentials === undefined &&
136
+ session.identityId === undefined
137
+ ) {
138
+ throw new Error('No credentials available');
167
139
  }
168
- return acc;
169
- // tslint:disable-next-line:align
170
- }, {});
171
- return this._request(params, isAllResponse);
172
- }
140
+ credentials = {
141
+ credentials: session.credentials,
142
+ identityId: session.identityId,
143
+ };
144
+ } catch (error) {
145
+ res(await this._request(params, isAllResponse));
146
+ }
173
147
 
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 {
148
+ let signedParams;
149
+ // before signed PARAMS
183
150
  signedParams = this._sign({ ...params }, credentials, {
184
151
  region,
185
152
  service,
186
153
  });
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
154
 
205
- return this.ajax(urlOrApiInfo, method, init);
206
- }
155
+ try {
156
+ res(
157
+ await this._request({
158
+ ...signedParams,
159
+ data: signedParams.body,
160
+ cancelToken: source.token,
161
+ })
162
+ );
163
+ } catch (error) {
164
+ rej(error);
207
165
  }
208
- throw error;
209
- }
166
+ });
167
+ this._cancelTokenMap.set(promise, source);
168
+
169
+ return promise;
210
170
  }
211
171
 
212
172
  /**
@@ -215,7 +175,7 @@ export class RestClient {
215
175
  * @param {JSON} init - Request extra params
216
176
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
217
177
  */
218
- get(urlOrApiInfo: string | ApiInfo, init) {
178
+ get(urlOrApiInfo: string, init) {
219
179
  return this.ajax(urlOrApiInfo, 'GET', init);
220
180
  }
221
181
 
@@ -225,7 +185,7 @@ export class RestClient {
225
185
  * @param {json} init - Request extra params
226
186
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
227
187
  */
228
- put(urlOrApiInfo: string | ApiInfo, init) {
188
+ put(urlOrApiInfo: string, init) {
229
189
  return this.ajax(urlOrApiInfo, 'PUT', init);
230
190
  }
231
191
 
@@ -235,7 +195,7 @@ export class RestClient {
235
195
  * @param {json} init - Request extra params
236
196
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
237
197
  */
238
- patch(urlOrApiInfo: string | ApiInfo, init) {
198
+ patch(urlOrApiInfo: string, init) {
239
199
  return this.ajax(urlOrApiInfo, 'PATCH', init);
240
200
  }
241
201
 
@@ -245,7 +205,7 @@ export class RestClient {
245
205
  * @param {json} init - Request extra params
246
206
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
247
207
  */
248
- post(urlOrApiInfo: string | ApiInfo, init) {
208
+ post(urlOrApiInfo: string, init) {
249
209
  return this.ajax(urlOrApiInfo, 'POST', init);
250
210
  }
251
211
 
@@ -255,7 +215,7 @@ export class RestClient {
255
215
  * @param {json} init - Request extra params
256
216
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
257
217
  */
258
- del(urlOrApiInfo: string | ApiInfo, init) {
218
+ del(urlOrApiInfo: string, init) {
259
219
  return this.ajax(urlOrApiInfo, 'DELETE', init);
260
220
  }
261
221
 
@@ -265,7 +225,7 @@ export class RestClient {
265
225
  * @param {json} init - Request extra params
266
226
  * @return {Promise} - A promise that resolves to an object with response status and JSON data, if successful.
267
227
  */
268
- head(urlOrApiInfo: string | ApiInfo, init) {
228
+ head(urlOrApiInfo: string, init) {
269
229
  return this.ajax(urlOrApiInfo, 'HEAD', init);
270
230
  }
271
231
 
@@ -275,7 +235,7 @@ export class RestClient {
275
235
  * @param {string} [message] - A message to include in the cancelation exception
276
236
  */
277
237
  cancel(request: Promise<any>, message?: string) {
278
- const source = this._cancelTokenMap.get(request);
238
+ const source = this._cancelTokenMap?.get(request);
279
239
  if (source) {
280
240
  source.cancel(message);
281
241
  return true;
@@ -289,7 +249,7 @@ export class RestClient {
289
249
  * @return if the request has a corresponding cancel token.
290
250
  */
291
251
  hasCancelToken(request: Promise<any>) {
292
- return this._cancelTokenMap.has(request);
252
+ return this._cancelTokenMap?.has(request);
293
253
  }
294
254
 
295
255
  /**
@@ -318,7 +278,7 @@ export class RestClient {
318
278
  promise: Promise<any>,
319
279
  cancelTokenSource: CancelTokenSource
320
280
  ) {
321
- this._cancelTokenMap.set(promise, cancelTokenSource);
281
+ this._cancelTokenMap?.set(promise, cancelTokenSource);
322
282
  }
323
283
 
324
284
  /**
@@ -359,39 +319,34 @@ export class RestClient {
359
319
 
360
320
  /** private methods **/
361
321
 
362
- private _sign(params, credentials, { service, region }) {
363
- const { signerServiceInfo: signerServiceInfoParams, ...otherParams } =
364
- params;
365
-
366
- const endpoint_region: string =
367
- region || this._region || this._options.region;
368
- const endpoint_service: string =
369
- service || this._service || this._options.service;
370
-
371
- const creds = {
372
- secret_key: credentials.secretAccessKey,
373
- access_key: credentials.accessKeyId,
374
- session_token: credentials.sessionToken,
375
- };
376
-
377
- const endpointInfo = {
378
- region: endpoint_region,
379
- service: endpoint_service,
380
- };
381
-
382
- const signerServiceInfo = Object.assign(
383
- endpointInfo,
384
- signerServiceInfoParams
322
+ private _sign(
323
+ params: {
324
+ method: string;
325
+ url: string;
326
+ host: string;
327
+ path: string;
328
+ headers: {};
329
+ data: BodyInit;
330
+ responseType: string;
331
+ timeout: number;
332
+ },
333
+ credentialsAndIdentityId: AWSCredentialsAndIdentityId,
334
+ { service, region }
335
+ ) {
336
+ const signed_params = signRequest(
337
+ {
338
+ method: params.method,
339
+ headers: params.headers,
340
+ url: new URL(params.url),
341
+ body: params.data,
342
+ },
343
+ {
344
+ credentials: credentialsAndIdentityId.credentials,
345
+ signingRegion: region,
346
+ signingService: service,
347
+ }
385
348
  );
386
349
 
387
- const signed_params = Signer.sign(otherParams, creds, signerServiceInfo);
388
-
389
- if (signed_params.data) {
390
- signed_params.body = signed_params.data;
391
- }
392
-
393
- logger.debug('Signed Request: ', signed_params);
394
-
395
350
  delete signed_params.headers['host'];
396
351
 
397
352
  return signed_params;
@@ -401,17 +356,7 @@ export class RestClient {
401
356
  return axios(params)
402
357
  .then(response => (isAllResponse ? response : response.data))
403
358
  .catch(error => {
404
- logger.debug(error);
405
359
  throw error;
406
360
  });
407
361
  }
408
-
409
- private _parseUrl(url) {
410
- const parts = url.split('/');
411
-
412
- return {
413
- host: parts[2],
414
- path: '/' + parts.slice(3).join('/'),
415
- };
416
- }
417
362
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- export { RestAPI, RestAPIClass } from './RestAPI';
5
- export { RestClient } from './RestClient';
4
+ export { post, cancel, isCancel } from './API';
5
+ export { DocumentType } from './types';
@@ -24,6 +24,20 @@ export class RestClientOptions {
24
24
  }
25
25
  }
26
26
 
27
+ export type DocumentType =
28
+ | null
29
+ | boolean
30
+ | number
31
+ | string
32
+ | DocumentType[]
33
+ | { [prop: string]: DocumentType };
34
+
35
+ export type PostOptions = {
36
+ headers?: Record<string, string>;
37
+ body: DocumentType;
38
+ region?: string;
39
+ serviceName?: string;
40
+ };
27
41
  /**
28
42
  * AWS credentials needed for RestClient
29
43
  */
package/lib/.tsbuildinfo DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "version": "3.8.3"
3
- }