@adobe/helix-onedrive-support 10.0.13 → 10.1.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [10.1.0](https://github.com/adobe/helix-onedrive-support/compare/v10.0.14...v10.1.0) (2023-06-05)
2
+
3
+
4
+ ### Features
5
+
6
+ * add rate limit in log and StatusCodeError ([#394](https://github.com/adobe/helix-onedrive-support/issues/394)) ([d9289fd](https://github.com/adobe/helix-onedrive-support/commit/d9289fd12fd290ad6482f3604ab9a3b1b9f1200d))
7
+
8
+ ## [10.0.14](https://github.com/adobe/helix-onedrive-support/compare/v10.0.13...v10.0.14) (2023-06-03)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** update dependency @adobe/helix-shared-tokencache to v1.2.5 ([#393](https://github.com/adobe/helix-onedrive-support/issues/393)) ([a40b956](https://github.com/adobe/helix-onedrive-support/commit/a40b956a4bb01f10ea85d84bb387a7644f54173d))
14
+
1
15
  ## [10.0.13](https://github.com/adobe/helix-onedrive-support/compare/v10.0.12...v10.0.13) (2023-05-28)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-onedrive-support",
3
- "version": "10.0.13",
3
+ "version": "10.1.0",
4
4
  "description": "Helix OneDrive Support",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -28,7 +28,7 @@
28
28
  "homepage": "https://github.com/adobe/helix-onedrive-support#readme",
29
29
  "dependencies": {
30
30
  "@adobe/fetch": "4.0.13",
31
- "@adobe/helix-shared-tokencache": "1.2.4",
31
+ "@adobe/helix-shared-tokencache": "1.2.5",
32
32
  "@azure/msal-node": "1.17.2",
33
33
  "jose": "4.14.4"
34
34
  },
@@ -36,12 +36,12 @@
36
36
  "@adobe/eslint-config-helix": "2.0.2",
37
37
  "@semantic-release/changelog": "6.0.3",
38
38
  "@semantic-release/git": "10.0.1",
39
- "@aws-sdk/client-s3": "3.341.0",
39
+ "@aws-sdk/client-s3": "3.345.0",
40
40
  "ajv": "8.12.0",
41
- "c8": "7.13.0",
41
+ "c8": "7.14.0",
42
42
  "codecov": "3.8.3",
43
- "dotenv": "16.0.3",
44
- "eslint": "8.41.0",
43
+ "dotenv": "16.1.3",
44
+ "eslint": "8.42.0",
45
45
  "eslint-plugin-header": "3.1.1",
46
46
  "eslint-plugin-import": "2.27.5",
47
47
  "husky": "8.0.3",
@@ -54,7 +54,7 @@
54
54
  "mocha-multi-reporters": "1.5.1",
55
55
  "nock": "13.3.1",
56
56
  "npm": "9.6.7",
57
- "semantic-release": "21.0.2"
57
+ "semantic-release": "21.0.3"
58
58
  },
59
59
  "lint-staged": {
60
60
  "*.js": "eslint"
package/src/OneDrive.js CHANGED
@@ -16,6 +16,7 @@ import { Workbook } from './excel/Workbook.js';
16
16
  import { StatusCodeError } from './StatusCodeError.js';
17
17
  import { editDistance, sanitizeName, splitByExtension } from './utils.js';
18
18
  import { SharePointSite } from './SharePointSite.js';
19
+ import { RateLimit } from './RateLimit.js';
19
20
 
20
21
  /**
21
22
  * the maximum subscription time in milliseconds
@@ -128,12 +129,18 @@ export class OneDrive {
128
129
  try {
129
130
  const { fetch } = this.fetchContext;
130
131
  const resp = await fetch(url, opts);
132
+ const rateLimit = RateLimit.fromHeaders(resp.headers);
133
+
134
+ if (rateLimit) {
135
+ this.log.warn({ sharepointRateLimit: { tenant: this.auth.tenant, ...rateLimit.toJSON() } });
136
+ }
137
+
131
138
  if (!resp.ok) {
132
139
  const text = await resp.text();
133
140
  let err;
134
141
  try {
135
142
  // try to parse json
136
- err = StatusCodeError.fromErrorResponse(JSON.parse(text), resp.status);
143
+ err = StatusCodeError.fromErrorResponse(JSON.parse(text), resp.status, rateLimit);
137
144
  } catch {
138
145
  err = new StatusCodeError(text, resp.status);
139
146
  }
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright 2023 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ /**
14
+ * Rate limit class
15
+ */
16
+ export class RateLimit {
17
+ static fromHeaders(headers) {
18
+ const names = [
19
+ ['RateLimit-Limit', 'limit'],
20
+ ['RateLimit-Remaining', 'remaining'],
21
+ ['RateLimit-Reset', 'reset'],
22
+ ['Retry-After', 'retryAfter'],
23
+ ];
24
+
25
+ const result = {};
26
+ let notEmpty = false;
27
+
28
+ names.forEach(([hdr, prop]) => {
29
+ const valueS = headers.get(hdr);
30
+ if (valueS) {
31
+ const value = Number.parseInt(valueS, 10);
32
+ if (!Number.isNaN(value)) {
33
+ result[prop] = value;
34
+ notEmpty = true;
35
+ }
36
+ }
37
+ });
38
+ return notEmpty ? new RateLimit(result) : null;
39
+ }
40
+
41
+ constructor({
42
+ limit, remaining, reset, retryAfter,
43
+ }) {
44
+ this._limit = limit;
45
+ this._remaining = remaining;
46
+ this._reset = reset;
47
+ this._retryAfter = retryAfter;
48
+ }
49
+
50
+ get limit() {
51
+ return this._limit;
52
+ }
53
+
54
+ get remaining() {
55
+ return this._remaining;
56
+ }
57
+
58
+ get reset() {
59
+ return this._reset;
60
+ }
61
+
62
+ get retryAfter() {
63
+ return this._retryAfter;
64
+ }
65
+
66
+ toJSON() {
67
+ const o = {
68
+ limit: this.limit,
69
+ remaining: this.remaining,
70
+ reset: this.reset,
71
+ };
72
+ if (this.retryAfter) {
73
+ o.retryAfter = this.retryAfter;
74
+ }
75
+ return o;
76
+ }
77
+ }
@@ -39,15 +39,16 @@ export class StatusCodeError extends Error {
39
39
  * Converts a Graph API error response to a status code error.
40
40
  * @param {object} errorBody The parsed error response body
41
41
  * @param {number} statusCode The status code of the error response
42
+ * @param {RateLimit} rateLimit rate limit or null
42
43
  * @param {object} details The underlying error
43
44
  * @returns {StatusCodeError} status code error
44
45
  */
45
- static fromErrorResponse(errorBody, statusCode) {
46
+ static fromErrorResponse(errorBody, statusCode, rateLimit) {
46
47
  if (errorBody.error && errorBody.error.message) {
47
48
  // eslint-disable-next-line no-param-reassign
48
49
  errorBody = errorBody.error;
49
50
  }
50
- return new StatusCodeError(errorBody.message, statusCode, errorBody);
51
+ return new StatusCodeError(errorBody.message, statusCode, errorBody, rateLimit);
51
52
  }
52
53
 
53
54
  /**
@@ -56,10 +57,12 @@ export class StatusCodeError extends Error {
56
57
  * @param {string} msg Error message
57
58
  * @param {number} statusCode Status code of the error response
58
59
  * @param {object} details underlying error
60
+ * @param {RateLimit} rateLimit rate limit or null
59
61
  */
60
- constructor(msg, statusCode, details) {
62
+ constructor(msg, statusCode, details, rateLimit) {
61
63
  super(msg?.value ?? msg);
62
64
  this.statusCode = statusCode;
63
65
  this.details = details;
66
+ this.rateLimit = rateLimit;
64
67
  }
65
68
  }
@@ -50,7 +50,7 @@ export class NamedItemContainer {
50
50
  });
51
51
  } catch (e) {
52
52
  if ((e.details && e.details.code === 'ItemAlreadyExists') && e.statusCode !== 409) {
53
- throw new StatusCodeError(e.message, 409, e.code, e);
53
+ throw new StatusCodeError(e.message, 409);
54
54
  }
55
55
  throw e;
56
56
  }
@@ -64,7 +64,7 @@ export class NamedItemContainer {
64
64
  });
65
65
  } catch (e) {
66
66
  if ((e.details && e.details.code === 'ItemNotFound') && e.statusCode !== 404) {
67
- throw new StatusCodeError(e.message, 404, e.code, e);
67
+ throw new StatusCodeError(e.message, 404);
68
68
  }
69
69
  throw e;
70
70
  }