microsoft-graph 2.8.0 → 2.9.1
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/cjs/graphApi.d.ts.map +1 -1
- package/dist/cjs/graphApi.js +45 -26
- package/dist/cjs/operations/driveItem/getDriveItemContent.d.ts.map +1 -1
- package/dist/cjs/operations/driveItem/getDriveItemContent.js +17 -6
- package/dist/cjs/operations/workbookRange/autoFitWorkbookRangeColumns.d.ts +1 -1
- package/dist/cjs/operations/workbookRange/autoFitWorkbookRangeColumns.js +1 -1
- package/dist/cjs/services/httpStatus.d.ts +6 -0
- package/dist/cjs/services/httpStatus.d.ts.map +1 -1
- package/dist/cjs/services/httpStatus.js +9 -0
- package/dist/esm/graphApi.d.ts.map +1 -1
- package/dist/esm/graphApi.js +46 -27
- package/dist/esm/operations/driveItem/getDriveItemContent.d.ts.map +1 -1
- package/dist/esm/operations/driveItem/getDriveItemContent.js +17 -6
- package/dist/esm/operations/workbookRange/autoFitWorkbookRangeColumns.d.ts +1 -1
- package/dist/esm/operations/workbookRange/autoFitWorkbookRangeColumns.js +1 -1
- package/dist/esm/services/httpStatus.d.ts +6 -0
- package/dist/esm/services/httpStatus.d.ts.map +1 -1
- package/dist/esm/services/httpStatus.js +8 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphApi.d.ts","sourceRoot":"","sources":["../../src/graphApi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graphApi.d.ts","sourceRoot":"","sources":["../../src/graphApi.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAgB,cAAc,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACzG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAQ/C,eAAO,MAAM,mBAAmB,EAA6C,KAAK,CAAC;AACnF,eAAO,MAAM,QAAQ,qCAAqC,CAAC;AAC3D,eAAO,MAAM,aAAa,4CAAuB,CAAC;AAElD,8KAA8K;AAC9K,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAQvF;AAED,6LAA6L;AAC7L,wBAAsB,QAAQ,CAAC,CAAC,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAInH;AAED,2DAA2D;AAC3D,wBAAsB,UAAU,CAAC,CAAC,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAOrH;AAoBD,KAAK,iBAAiB,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CAChE,CAAC"}
|
package/dist/cjs/graphApi.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.batchEndpoint = exports.endpoint = exports.authenticationScope = void 0;
|
|
|
7
7
|
exports.operation = operation;
|
|
8
8
|
exports.parallel = parallel;
|
|
9
9
|
exports.sequential = sequential;
|
|
10
|
-
const
|
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
|
11
11
|
const InconsistentContextError_ts_1 = __importDefault(require("./errors/InconsistentContextError.js"));
|
|
12
12
|
const InvalidArgumentError_ts_1 = __importDefault(require("./errors/InvalidArgumentError.js"));
|
|
13
13
|
const NeverError_ts_1 = __importDefault(require("./errors/NeverError.js"));
|
|
@@ -51,7 +51,7 @@ const consecutiveRetryDelayMultiplier = 2;
|
|
|
51
51
|
async function executeSingle(definition) {
|
|
52
52
|
const context = (0, context_ts_1.getContext)(definition.contextId);
|
|
53
53
|
const accessToken = await (0, accessToken_ts_1.getCurrentAccessToken)(context.tenantId, context.clientId, context.clientSecret, exports.authenticationScope);
|
|
54
|
-
const
|
|
54
|
+
const httpAgent = (0, httpAgent_ts_1.tryGetHttpAgent)(context.httpProxy);
|
|
55
55
|
const response = await innerFetch({
|
|
56
56
|
url: `${exports.endpoint}${definition.path}`,
|
|
57
57
|
method: definition.method,
|
|
@@ -59,8 +59,8 @@ async function executeSingle(definition) {
|
|
|
59
59
|
authorization: createAuthorizationHeader(accessToken),
|
|
60
60
|
...headersToObject(definition.headers),
|
|
61
61
|
},
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
data: definition.body === null ? null : definition.body,
|
|
63
|
+
httpAgent,
|
|
64
64
|
});
|
|
65
65
|
return definition.responseTransform(response);
|
|
66
66
|
}
|
|
@@ -79,7 +79,7 @@ async function executeBatch(...ops) {
|
|
|
79
79
|
}
|
|
80
80
|
const context = (0, context_ts_1.getContext)(contextId);
|
|
81
81
|
const accessToken = await (0, accessToken_ts_1.getCurrentAccessToken)(context.tenantId, context.clientId, context.clientSecret, exports.authenticationScope);
|
|
82
|
-
const
|
|
82
|
+
const httpAgent = (0, httpAgent_ts_1.tryGetHttpAgent)(context.httpProxy);
|
|
83
83
|
const body = await innerFetch({
|
|
84
84
|
url: exports.batchEndpoint,
|
|
85
85
|
method: "POST",
|
|
@@ -88,7 +88,7 @@ async function executeBatch(...ops) {
|
|
|
88
88
|
accept: "application/json",
|
|
89
89
|
"content-type": "application/json",
|
|
90
90
|
},
|
|
91
|
-
|
|
91
|
+
data: {
|
|
92
92
|
requests: ops.map((op, index) => ({
|
|
93
93
|
id: (0, operationId_ts_1.operationIndexToId)(index),
|
|
94
94
|
method: op.method,
|
|
@@ -97,8 +97,8 @@ async function executeBatch(...ops) {
|
|
|
97
97
|
body: op.body === null ? undefined : op.body,
|
|
98
98
|
dependsOn: op.dependsOn?.map((id) => id.toString()),
|
|
99
99
|
})),
|
|
100
|
-
}
|
|
101
|
-
|
|
100
|
+
},
|
|
101
|
+
httpAgent,
|
|
102
102
|
});
|
|
103
103
|
const responses = [];
|
|
104
104
|
for (const r of body.responses) {
|
|
@@ -123,27 +123,48 @@ async function executeBatch(...ops) {
|
|
|
123
123
|
return responses; // TODO: Is there a neater way to massage the types correctly? This is functionally correct, but I do want to avoid using `unknown` here if possible.
|
|
124
124
|
}
|
|
125
125
|
/** Execute request, supporting GraphAPI retry logic */
|
|
126
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: This function does need to be simplified, though it is a TODO for another day
|
|
126
127
|
async function innerFetch(args) {
|
|
127
128
|
const { url, ...options } = args;
|
|
129
|
+
if (!url) {
|
|
130
|
+
throw new Error("URL is required for request");
|
|
131
|
+
}
|
|
128
132
|
let retryAfterMilliseconds = defaultRetryDelayMilliseconds;
|
|
129
133
|
let response = null;
|
|
130
134
|
let attempts = 0; // Track the number of attempts
|
|
135
|
+
const instance = axios_1.default.create({
|
|
136
|
+
httpsAgent: options.httpAgent,
|
|
137
|
+
});
|
|
131
138
|
while (attempts < maxRetries) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
try {
|
|
140
|
+
response = await instance({
|
|
141
|
+
url,
|
|
142
|
+
...options,
|
|
143
|
+
});
|
|
144
|
+
break; // If successful, exit the loop
|
|
136
145
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (axios_1.default.isAxiosError(error) && error.response) {
|
|
148
|
+
response = error.response;
|
|
149
|
+
if (!((0, httpStatus_ts_1.isHttpTooManyRequests)(response.status) || (0, httpStatus_ts_1.isServiceUnavailable)(response.status) || (0, httpStatus_ts_1.isGatewayTimeout)(response.status))) {
|
|
150
|
+
throw error; // Don't retry for other error codes
|
|
151
|
+
}
|
|
152
|
+
const requestedRetryAfterSeconds = Number.parseInt(response.headers["retry-after"] ?? "0", 10);
|
|
153
|
+
if (requestedRetryAfterSeconds) {
|
|
154
|
+
retryAfterMilliseconds = requestedRetryAfterSeconds * 1000;
|
|
155
|
+
}
|
|
156
|
+
await (0, sleep_ts_1.sleep)(retryAfterMilliseconds);
|
|
157
|
+
retryAfterMilliseconds *= consecutiveRetryDelayMultiplier;
|
|
158
|
+
attempts++; // Increment the attempt counter
|
|
159
|
+
if (attempts >= maxRetries) {
|
|
160
|
+
RequestFailedError_ts_1.default.throw(`GraphAPI fetch exceed retry limit of ${maxRetries} attempts.`, args);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// For non-Axios errors or errors without response, just throw
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
140
167
|
}
|
|
141
|
-
await (0, sleep_ts_1.sleep)(retryAfterMilliseconds);
|
|
142
|
-
retryAfterMilliseconds *= consecutiveRetryDelayMultiplier;
|
|
143
|
-
attempts++; // Increment the attempt counter
|
|
144
|
-
}
|
|
145
|
-
if (attempts >= maxRetries) {
|
|
146
|
-
RequestFailedError_ts_1.default.throw(`GraphAPI fetch exceed retry limit of ${maxRetries} attempts.`, args);
|
|
147
168
|
}
|
|
148
169
|
if (!response) {
|
|
149
170
|
throw new NeverError_ts_1.default("Response is null. Should be impossible");
|
|
@@ -151,17 +172,15 @@ async function innerFetch(args) {
|
|
|
151
172
|
if ((0, httpStatus_ts_1.isHttpTooManyRequests)(response.status)) {
|
|
152
173
|
RequestFailedError_ts_1.default.throw("GraphAPI fetch failed after 3 retries due to too many requests.", args);
|
|
153
174
|
}
|
|
154
|
-
const replyContentType = response.headers.get("content-type")?.toLowerCase();
|
|
155
|
-
const body = replyContentType?.startsWith("application/json") ? await response.json() : null;
|
|
156
175
|
if (!(0, httpStatus_ts_1.isHttpOk)(response.status)) {
|
|
157
|
-
const bodyError =
|
|
176
|
+
const bodyError = response.data;
|
|
158
177
|
let errorMessage = `${response.status} '${response.statusText}'`;
|
|
159
178
|
if (bodyError?.error) {
|
|
160
179
|
errorMessage += `: [${bodyError.error.code}] '${bodyError.error.message}'`;
|
|
161
180
|
}
|
|
162
|
-
RequestFailedError_ts_1.default.throw(`GraphAPI fetch failed: ${errorMessage}`, args,
|
|
181
|
+
RequestFailedError_ts_1.default.throw(`GraphAPI fetch failed: ${errorMessage}`, args, response.data);
|
|
163
182
|
}
|
|
164
|
-
return
|
|
183
|
+
return response.data;
|
|
165
184
|
}
|
|
166
185
|
function normalizeBatchBody(contentType, body) {
|
|
167
186
|
if (contentType?.startsWith("application/json") && typeof body === "string") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/getDriveItemContent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"getDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/getDriveItemContent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE;;;;;;;GAOG;AACH,wBAA8B,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAgC7F"}
|
|
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.default = getDriveItemContent;
|
|
7
|
-
const
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const graphApi_ts_1 = require("../../graphApi.js");
|
|
9
9
|
const accessToken_ts_1 = require("../../services/accessToken.js");
|
|
10
10
|
const context_ts_1 = require("../../services/context.js");
|
|
11
11
|
const httpAgent_ts_1 = require("../../services/httpAgent.js");
|
|
12
|
+
const httpStatus_ts_1 = require("../../services/httpStatus.js");
|
|
12
13
|
const templatedPaths_ts_1 = require("../../services/templatedPaths.js");
|
|
13
14
|
/**
|
|
14
15
|
* Download the content of a drive item.
|
|
@@ -23,15 +24,25 @@ async function getDriveItemContent(itemRef) {
|
|
|
23
24
|
const url = `${graphApi_ts_1.endpoint}${(0, templatedPaths_ts_1.generatePath)("/sites/{site-id}/drives/{drive-id}/items/{item-id}/content", itemRef)}`;
|
|
24
25
|
const context = (0, context_ts_1.getContext)(itemRef.contextId);
|
|
25
26
|
const accessToken = await (0, accessToken_ts_1.getCurrentAccessToken)(context.tenantId, context.clientId, context.clientSecret, graphApi_ts_1.authenticationScope);
|
|
26
|
-
const
|
|
27
|
-
const response = await (0,
|
|
27
|
+
const httpAgent = (0, httpAgent_ts_1.tryGetHttpAgent)(context.httpProxy);
|
|
28
|
+
const response = await (0, axios_1.default)({
|
|
29
|
+
url,
|
|
30
|
+
method: "GET",
|
|
28
31
|
headers: {
|
|
29
32
|
authorization: `Bearer ${accessToken}`,
|
|
30
33
|
},
|
|
31
|
-
|
|
34
|
+
responseType: "arraybuffer",
|
|
35
|
+
httpsAgent: httpAgent,
|
|
32
36
|
});
|
|
33
|
-
if (!response.
|
|
37
|
+
if (!(0, httpStatus_ts_1.isHttpOk)(response.status)) {
|
|
34
38
|
throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
|
|
35
39
|
}
|
|
36
|
-
|
|
40
|
+
if (!Buffer.isBuffer(response.data)) {
|
|
41
|
+
throw new Error(`Unexpected response type: ${typeof response.data}`);
|
|
42
|
+
}
|
|
43
|
+
const buffer = response.data.buffer.slice(response.data.byteOffset, response.data.byteOffset + response.data.byteLength);
|
|
44
|
+
if (!(buffer instanceof ArrayBuffer)) {
|
|
45
|
+
throw new Error("Failed to convert Buffer to ArrayBuffer");
|
|
46
|
+
}
|
|
47
|
+
return buffer;
|
|
37
48
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { GraphOperation } from "../../models/GraphOperation.ts";
|
|
2
2
|
import type { WorkbookRangeRef } from "../../models/WorkbookRangeRef.ts";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Auto-fit the columns in a range.
|
|
5
5
|
*
|
|
6
6
|
* @param rangeRef - A reference to the range, optionally including session information.
|
|
7
7
|
* @returns Nothing.
|
|
@@ -4,7 +4,7 @@ exports.default = autoFitWorkbookRangeColumns;
|
|
|
4
4
|
const graphApi_ts_1 = require("../../graphApi.js");
|
|
5
5
|
const templatedPaths_ts_1 = require("../../services/templatedPaths.js");
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Auto-fit the columns in a range.
|
|
8
8
|
*
|
|
9
9
|
* @param rangeRef - A reference to the range, optionally including session information.
|
|
10
10
|
* @returns Nothing.
|
|
@@ -16,4 +16,10 @@ export declare function isHttpTooManyRequests(status: number): boolean;
|
|
|
16
16
|
* @returns True if the status code is 503, otherwise false.
|
|
17
17
|
*/
|
|
18
18
|
export declare function isServiceUnavailable(status: number): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the HTTP status code indicates a gateway has timed out.
|
|
21
|
+
* @param status - The HTTP status code.
|
|
22
|
+
* @returns True if the status code is 504, otherwise false.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isGatewayTimeout(status: number): boolean;
|
|
19
25
|
//# sourceMappingURL=httpStatus.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpStatus.d.ts","sourceRoot":"","sources":["../../../src/services/httpStatus.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D"}
|
|
1
|
+
{"version":3,"file":"httpStatus.d.ts","sourceRoot":"","sources":["../../../src/services/httpStatus.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD"}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isHttpOk = isHttpOk;
|
|
4
4
|
exports.isHttpTooManyRequests = isHttpTooManyRequests;
|
|
5
5
|
exports.isServiceUnavailable = isServiceUnavailable;
|
|
6
|
+
exports.isGatewayTimeout = isGatewayTimeout;
|
|
6
7
|
/**
|
|
7
8
|
* Checks if the HTTP status code indicates a successful response.
|
|
8
9
|
* @param status - The HTTP status code.
|
|
@@ -27,3 +28,11 @@ function isHttpTooManyRequests(status) {
|
|
|
27
28
|
function isServiceUnavailable(status) {
|
|
28
29
|
return status === 503;
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Checks if the HTTP status code indicates a gateway has timed out.
|
|
33
|
+
* @param status - The HTTP status code.
|
|
34
|
+
* @returns True if the status code is 504, otherwise false.
|
|
35
|
+
*/
|
|
36
|
+
function isGatewayTimeout(status) {
|
|
37
|
+
return status === 504;
|
|
38
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphApi.d.ts","sourceRoot":"","sources":["../../src/graphApi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graphApi.d.ts","sourceRoot":"","sources":["../../src/graphApi.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAgB,cAAc,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACzG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAQ/C,eAAO,MAAM,mBAAmB,EAA6C,KAAK,CAAC;AACnF,eAAO,MAAM,QAAQ,qCAAqC,CAAC;AAC3D,eAAO,MAAM,aAAa,4CAAuB,CAAC;AAElD,8KAA8K;AAC9K,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAQvF;AAED,6LAA6L;AAC7L,wBAAsB,QAAQ,CAAC,CAAC,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAInH;AAED,2DAA2D;AAC3D,wBAAsB,UAAU,CAAC,CAAC,SAAS,cAAc,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAOrH;AAoBD,KAAK,iBAAiB,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CAChE,CAAC"}
|
package/dist/esm/graphApi.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import axios from "axios";
|
|
2
2
|
import InconsistentContextError from "./errors/InconsistentContextError.js";
|
|
3
3
|
import InvalidArgumentError from "./errors/InvalidArgumentError.js";
|
|
4
4
|
import NeverError from "./errors/NeverError.js";
|
|
@@ -7,7 +7,7 @@ import RequestFailedError from "./errors/RequestFailedError.js";
|
|
|
7
7
|
import { getCurrentAccessToken } from "./services/accessToken.js";
|
|
8
8
|
import { getContext } from "./services/context.js";
|
|
9
9
|
import { tryGetHttpAgent } from "./services/httpAgent.js";
|
|
10
|
-
import { isHttpOk, isHttpTooManyRequests, isServiceUnavailable } from "./services/httpStatus.js";
|
|
10
|
+
import { isGatewayTimeout, isHttpOk, isHttpTooManyRequests, isServiceUnavailable } from "./services/httpStatus.js";
|
|
11
11
|
import { operationIdToIndex, operationIndexToId } from "./services/operationId.js";
|
|
12
12
|
import { sleep } from "./services/sleep.js";
|
|
13
13
|
export const authenticationScope = "https://graph.microsoft.com/.default";
|
|
@@ -42,7 +42,7 @@ const consecutiveRetryDelayMultiplier = 2;
|
|
|
42
42
|
async function executeSingle(definition) {
|
|
43
43
|
const context = getContext(definition.contextId);
|
|
44
44
|
const accessToken = await getCurrentAccessToken(context.tenantId, context.clientId, context.clientSecret, authenticationScope);
|
|
45
|
-
const
|
|
45
|
+
const httpAgent = tryGetHttpAgent(context.httpProxy);
|
|
46
46
|
const response = await innerFetch({
|
|
47
47
|
url: `${endpoint}${definition.path}`,
|
|
48
48
|
method: definition.method,
|
|
@@ -50,8 +50,8 @@ async function executeSingle(definition) {
|
|
|
50
50
|
authorization: createAuthorizationHeader(accessToken),
|
|
51
51
|
...headersToObject(definition.headers),
|
|
52
52
|
},
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
data: definition.body === null ? null : definition.body,
|
|
54
|
+
httpAgent,
|
|
55
55
|
});
|
|
56
56
|
return definition.responseTransform(response);
|
|
57
57
|
}
|
|
@@ -70,7 +70,7 @@ async function executeBatch(...ops) {
|
|
|
70
70
|
}
|
|
71
71
|
const context = getContext(contextId);
|
|
72
72
|
const accessToken = await getCurrentAccessToken(context.tenantId, context.clientId, context.clientSecret, authenticationScope);
|
|
73
|
-
const
|
|
73
|
+
const httpAgent = tryGetHttpAgent(context.httpProxy);
|
|
74
74
|
const body = await innerFetch({
|
|
75
75
|
url: batchEndpoint,
|
|
76
76
|
method: "POST",
|
|
@@ -79,7 +79,7 @@ async function executeBatch(...ops) {
|
|
|
79
79
|
accept: "application/json",
|
|
80
80
|
"content-type": "application/json",
|
|
81
81
|
},
|
|
82
|
-
|
|
82
|
+
data: {
|
|
83
83
|
requests: ops.map((op, index) => ({
|
|
84
84
|
id: operationIndexToId(index),
|
|
85
85
|
method: op.method,
|
|
@@ -88,8 +88,8 @@ async function executeBatch(...ops) {
|
|
|
88
88
|
body: op.body === null ? undefined : op.body,
|
|
89
89
|
dependsOn: op.dependsOn?.map((id) => id.toString()),
|
|
90
90
|
})),
|
|
91
|
-
}
|
|
92
|
-
|
|
91
|
+
},
|
|
92
|
+
httpAgent,
|
|
93
93
|
});
|
|
94
94
|
const responses = [];
|
|
95
95
|
for (const r of body.responses) {
|
|
@@ -114,27 +114,48 @@ async function executeBatch(...ops) {
|
|
|
114
114
|
return responses; // TODO: Is there a neater way to massage the types correctly? This is functionally correct, but I do want to avoid using `unknown` here if possible.
|
|
115
115
|
}
|
|
116
116
|
/** Execute request, supporting GraphAPI retry logic */
|
|
117
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: This function does need to be simplified, though it is a TODO for another day
|
|
117
118
|
async function innerFetch(args) {
|
|
118
119
|
const { url, ...options } = args;
|
|
120
|
+
if (!url) {
|
|
121
|
+
throw new Error("URL is required for request");
|
|
122
|
+
}
|
|
119
123
|
let retryAfterMilliseconds = defaultRetryDelayMilliseconds;
|
|
120
124
|
let response = null;
|
|
121
125
|
let attempts = 0; // Track the number of attempts
|
|
126
|
+
const instance = axios.create({
|
|
127
|
+
httpsAgent: options.httpAgent,
|
|
128
|
+
});
|
|
122
129
|
while (attempts < maxRetries) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
try {
|
|
131
|
+
response = await instance({
|
|
132
|
+
url,
|
|
133
|
+
...options,
|
|
134
|
+
});
|
|
135
|
+
break; // If successful, exit the loop
|
|
127
136
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (axios.isAxiosError(error) && error.response) {
|
|
139
|
+
response = error.response;
|
|
140
|
+
if (!(isHttpTooManyRequests(response.status) || isServiceUnavailable(response.status) || isGatewayTimeout(response.status))) {
|
|
141
|
+
throw error; // Don't retry for other error codes
|
|
142
|
+
}
|
|
143
|
+
const requestedRetryAfterSeconds = Number.parseInt(response.headers["retry-after"] ?? "0", 10);
|
|
144
|
+
if (requestedRetryAfterSeconds) {
|
|
145
|
+
retryAfterMilliseconds = requestedRetryAfterSeconds * 1000;
|
|
146
|
+
}
|
|
147
|
+
await sleep(retryAfterMilliseconds);
|
|
148
|
+
retryAfterMilliseconds *= consecutiveRetryDelayMultiplier;
|
|
149
|
+
attempts++; // Increment the attempt counter
|
|
150
|
+
if (attempts >= maxRetries) {
|
|
151
|
+
RequestFailedError.throw(`GraphAPI fetch exceed retry limit of ${maxRetries} attempts.`, args);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// For non-Axios errors or errors without response, just throw
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
131
158
|
}
|
|
132
|
-
await sleep(retryAfterMilliseconds);
|
|
133
|
-
retryAfterMilliseconds *= consecutiveRetryDelayMultiplier;
|
|
134
|
-
attempts++; // Increment the attempt counter
|
|
135
|
-
}
|
|
136
|
-
if (attempts >= maxRetries) {
|
|
137
|
-
RequestFailedError.throw(`GraphAPI fetch exceed retry limit of ${maxRetries} attempts.`, args);
|
|
138
159
|
}
|
|
139
160
|
if (!response) {
|
|
140
161
|
throw new NeverError("Response is null. Should be impossible");
|
|
@@ -142,17 +163,15 @@ async function innerFetch(args) {
|
|
|
142
163
|
if (isHttpTooManyRequests(response.status)) {
|
|
143
164
|
RequestFailedError.throw("GraphAPI fetch failed after 3 retries due to too many requests.", args);
|
|
144
165
|
}
|
|
145
|
-
const replyContentType = response.headers.get("content-type")?.toLowerCase();
|
|
146
|
-
const body = replyContentType?.startsWith("application/json") ? await response.json() : null;
|
|
147
166
|
if (!isHttpOk(response.status)) {
|
|
148
|
-
const bodyError =
|
|
167
|
+
const bodyError = response.data;
|
|
149
168
|
let errorMessage = `${response.status} '${response.statusText}'`;
|
|
150
169
|
if (bodyError?.error) {
|
|
151
170
|
errorMessage += `: [${bodyError.error.code}] '${bodyError.error.message}'`;
|
|
152
171
|
}
|
|
153
|
-
RequestFailedError.throw(`GraphAPI fetch failed: ${errorMessage}`, args,
|
|
172
|
+
RequestFailedError.throw(`GraphAPI fetch failed: ${errorMessage}`, args, response.data);
|
|
154
173
|
}
|
|
155
|
-
return
|
|
174
|
+
return response.data;
|
|
156
175
|
}
|
|
157
176
|
function normalizeBatchBody(contentType, body) {
|
|
158
177
|
if (contentType?.startsWith("application/json") && typeof body === "string") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/getDriveItemContent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"getDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/getDriveItemContent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE;;;;;;;GAOG;AACH,wBAA8B,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAgC7F"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import axios from "axios";
|
|
2
2
|
import { authenticationScope, endpoint } from "../../graphApi.js";
|
|
3
3
|
import { getCurrentAccessToken } from "../../services/accessToken.js";
|
|
4
4
|
import { getContext } from "../../services/context.js";
|
|
5
5
|
import { tryGetHttpAgent } from "../../services/httpAgent.js";
|
|
6
|
+
import { isHttpOk } from "../../services/httpStatus.js";
|
|
6
7
|
import { generatePath } from "../../services/templatedPaths.js";
|
|
7
8
|
/**
|
|
8
9
|
* Download the content of a drive item.
|
|
@@ -17,15 +18,25 @@ export default async function getDriveItemContent(itemRef) {
|
|
|
17
18
|
const url = `${endpoint}${generatePath("/sites/{site-id}/drives/{drive-id}/items/{item-id}/content", itemRef)}`;
|
|
18
19
|
const context = getContext(itemRef.contextId);
|
|
19
20
|
const accessToken = await getCurrentAccessToken(context.tenantId, context.clientId, context.clientSecret, authenticationScope);
|
|
20
|
-
const
|
|
21
|
-
const response = await
|
|
21
|
+
const httpAgent = tryGetHttpAgent(context.httpProxy);
|
|
22
|
+
const response = await axios({
|
|
23
|
+
url,
|
|
24
|
+
method: "GET",
|
|
22
25
|
headers: {
|
|
23
26
|
authorization: `Bearer ${accessToken}`,
|
|
24
27
|
},
|
|
25
|
-
|
|
28
|
+
responseType: "arraybuffer",
|
|
29
|
+
httpsAgent: httpAgent,
|
|
26
30
|
});
|
|
27
|
-
if (!response.
|
|
31
|
+
if (!isHttpOk(response.status)) {
|
|
28
32
|
throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
|
|
29
33
|
}
|
|
30
|
-
|
|
34
|
+
if (!Buffer.isBuffer(response.data)) {
|
|
35
|
+
throw new Error(`Unexpected response type: ${typeof response.data}`);
|
|
36
|
+
}
|
|
37
|
+
const buffer = response.data.buffer.slice(response.data.byteOffset, response.data.byteOffset + response.data.byteLength);
|
|
38
|
+
if (!(buffer instanceof ArrayBuffer)) {
|
|
39
|
+
throw new Error("Failed to convert Buffer to ArrayBuffer");
|
|
40
|
+
}
|
|
41
|
+
return buffer;
|
|
31
42
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { GraphOperation } from "../../models/GraphOperation.ts";
|
|
2
2
|
import type { WorkbookRangeRef } from "../../models/WorkbookRangeRef.ts";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Auto-fit the columns in a range.
|
|
5
5
|
*
|
|
6
6
|
* @param rangeRef - A reference to the range, optionally including session information.
|
|
7
7
|
* @returns Nothing.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { operation } from "../../graphApi.js";
|
|
2
2
|
import { generatePath } from "../../services/templatedPaths.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Auto-fit the columns in a range.
|
|
5
5
|
*
|
|
6
6
|
* @param rangeRef - A reference to the range, optionally including session information.
|
|
7
7
|
* @returns Nothing.
|
|
@@ -16,4 +16,10 @@ export declare function isHttpTooManyRequests(status: number): boolean;
|
|
|
16
16
|
* @returns True if the status code is 503, otherwise false.
|
|
17
17
|
*/
|
|
18
18
|
export declare function isServiceUnavailable(status: number): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the HTTP status code indicates a gateway has timed out.
|
|
21
|
+
* @param status - The HTTP status code.
|
|
22
|
+
* @returns True if the status code is 504, otherwise false.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isGatewayTimeout(status: number): boolean;
|
|
19
25
|
//# sourceMappingURL=httpStatus.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpStatus.d.ts","sourceRoot":"","sources":["../../../src/services/httpStatus.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D"}
|
|
1
|
+
{"version":3,"file":"httpStatus.d.ts","sourceRoot":"","sources":["../../../src/services/httpStatus.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD"}
|
|
@@ -22,3 +22,11 @@ export function isHttpTooManyRequests(status) {
|
|
|
22
22
|
export function isServiceUnavailable(status) {
|
|
23
23
|
return status === 503;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Checks if the HTTP status code indicates a gateway has timed out.
|
|
27
|
+
* @param status - The HTTP status code.
|
|
28
|
+
* @returns True if the status code is 504, otherwise false.
|
|
29
|
+
*/
|
|
30
|
+
export function isGatewayTimeout(status) {
|
|
31
|
+
return status === 504;
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "microsoft-graph",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.1",
|
|
4
4
|
"description": "Microsoft GraphAPI SDK for NodeJS",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@azure/identity": "^4.8.0",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
41
|
+
"axios": "^1.7.9",
|
|
42
|
+
"https-proxy-agent": "^7.0.6"
|
|
43
43
|
},
|
|
44
44
|
"exports": {
|
|
45
45
|
".": {
|