microsoft-graph 3.9.1 → 3.9.3

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.
@@ -6,12 +6,29 @@
6
6
  import type { DriveItem } from "@microsoft/microsoft-graph-types";
7
7
  import type { DriveRef } from "../../models/Drive.ts";
8
8
  import type { DriveItemPath, DriveItemRef } from "../../models/DriveItem.ts";
9
+ /**
10
+ * The required chunk size multiple for upload sessions.
11
+ * @remarks Microsoft Graph requires that each upload chunk is a multiple of 320 KiB (327,680 bytes).
12
+ * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
13
+ */
14
+ export declare const chunkSizeMultiple: number;
15
+ /**
16
+ * Options for creating a drive item with content upload.
17
+ * @property conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Can be 'fail', 'replace', or 'rename'.
18
+ * @property chunkSize Optional. The size of each upload chunk in bytes. Must be a multiple of 320 KiB (327,680 bytes).
19
+ * @property progress Optional. Callback function called with the number of bytes uploaded after each chunk.
20
+ */
21
+ export interface CreateDriveItemContentOptions {
22
+ conflictBehavior?: "fail" | "replace" | "rename";
23
+ chunkSize?: number;
24
+ progress?: (bytes: number) => void;
25
+ }
9
26
  /**
10
27
  * Creates a new drive item in the specified parent drive or folder using a stream as content.
11
28
  * @param parentRef Reference to the parent drive or folder where the drive item will be created.
12
29
  * @param itemPath Path (including the filename) for the new drive item within the given parent.
13
30
  * @param contentStream A Node.js readable stream containing the file content.
14
- * @param totalSize The total size in bytes of the content to be uploaded.
31
+ * @param contentLength The total size in bytes of the content to be uploaded.
15
32
  * @param options Optional. Additional options for the upload operation.
16
33
  * @param options.conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
17
34
  * @param options.chunkSize Optional. The size of each chunk to be uploaded in bytes. Default is 10MB.
@@ -20,10 +37,5 @@ import type { DriveItemPath, DriveItemRef } from "../../models/DriveItem.ts";
20
37
  * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
21
38
  * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
22
39
  */
23
- export interface CreateDriveItemContentOptions {
24
- conflictBehavior?: "fail" | "replace" | "rename";
25
- chunkSize?: number;
26
- progress?: (pct: number) => void;
27
- }
28
- export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, totalSize: number, options?: CreateDriveItemContentOptions): Promise<DriveItem & DriveItemRef>;
40
+ export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, contentLength: number, options?: CreateDriveItemContentOptions): Promise<DriveItem & DriveItemRef>;
29
41
  //# sourceMappingURL=createDriveItemContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/createDriveItemContent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAElE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAe,aAAa,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAkB1F;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,6BAA6B;IAC7C,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,wBAA8B,sBAAsB,CAAC,SAAS,EAAE,QAAQ,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,CAwGzP"}
1
+ {"version":3,"file":"createDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/createDriveItemContent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAGlE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAe,aAAa,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAM1F;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAc5C;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC7C,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAA8B,sBAAsB,CAAC,SAAS,EAAE,QAAQ,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,CA+E7P"}
@@ -8,15 +8,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
8
8
  return (mod && mod.__esModule) ? mod : { "default": mod };
9
9
  };
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.chunkSizeMultiple = void 0;
11
12
  exports.default = createDriveItemContent;
13
+ const InvalidArgumentError_ts_1 = __importDefault(require("../../errors/InvalidArgumentError.js"));
12
14
  const ProtocolError_ts_1 = __importDefault(require("../../errors/ProtocolError.js"));
13
15
  const driveItem_ts_1 = require("../../services/driveItem.js");
14
16
  const http_ts_1 = require("../../services/http.js");
15
17
  const operationInvoker_ts_1 = require("../../services/operationInvoker.js");
16
18
  const templatedPaths_ts_1 = require("../../services/templatedPaths.js");
17
- const defaultChunkSize = 10 * 1024 * 1024;
18
- async function createDriveItemContent(parentRef, itemPath, contentStream, totalSize, options = {}) {
19
- const { conflictBehavior = "fail", chunkSize = defaultChunkSize, progress } = options;
19
+ /**
20
+ * The required chunk size multiple for upload sessions.
21
+ * @remarks Microsoft Graph requires that each upload chunk is a multiple of 320 KiB (327,680 bytes).
22
+ * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
23
+ */
24
+ exports.chunkSizeMultiple = 320 * 1024;
25
+ const defaultChunkSize = exports.chunkSizeMultiple * 32;
26
+ /**
27
+ * Creates a new drive item in the specified parent drive or folder using a stream as content.
28
+ * @param parentRef Reference to the parent drive or folder where the drive item will be created.
29
+ * @param itemPath Path (including the filename) for the new drive item within the given parent.
30
+ * @param contentStream A Node.js readable stream containing the file content.
31
+ * @param contentLength The total size in bytes of the content to be uploaded.
32
+ * @param options Optional. Additional options for the upload operation.
33
+ * @param options.conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
34
+ * @param options.chunkSize Optional. The size of each chunk to be uploaded in bytes. Default is 10MB.
35
+ * @param options.progress Optional. A callback function that is called periodically with the upload progress as a percentage.
36
+ * @returns The newly created drive item.
37
+ * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
38
+ * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
39
+ */
40
+ async function createDriveItemContent(parentRef, itemPath, contentStream, contentLength, options = {}) {
41
+ const { conflictBehavior = "fail", chunkSize = defaultChunkSize, progress = () => { } } = options;
42
+ if (chunkSize % exports.chunkSizeMultiple !== 0) {
43
+ throw new InvalidArgumentError_ts_1.default(`Chunk size (${chunkSize.toLocaleString()}) must be a multiple of ${(exports.chunkSizeMultiple / 1024).toLocaleString()} KiB *${exports.chunkSizeMultiple.toLocaleString()} bytes).`);
44
+ }
20
45
  const pathSegment = parentRef.itemId ? "items/{item-id}" : "root";
21
46
  const uploadSessionUrl = `${operationInvoker_ts_1.endpoint}${(0, templatedPaths_ts_1.generatePath)(`/sites/{site-id}/drives/{drive-id}/${pathSegment}:/${itemPath}:/createUploadSession`, parentRef)}`;
22
47
  const accessToken = await parentRef.context.generateAccessToken();
@@ -36,80 +61,58 @@ async function createDriveItemContent(parentRef, itemPath, contentStream, totalS
36
61
  }),
37
62
  responseType: "json",
38
63
  });
39
- let position = 0;
40
- let driveItem = null;
41
- let streamEnded = false;
42
- const chunks = [];
43
- contentStream.on("data", (chunk) => {
44
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
45
- });
46
- contentStream.on("end", () => {
47
- streamEnded = true;
48
- });
49
- contentStream.on("error", () => {
50
- // error will be handled in readChunk
51
- });
52
- let chunk = await readChunk();
53
- while (chunk !== null) {
54
- let currentChunk = chunk;
55
- while (currentChunk.length > 0) {
56
- const thisChunk = currentChunk.subarray(0, chunkSize);
57
- const start = position;
58
- const end = position + thisChunk.length - 1;
59
- const contentRange = `bytes ${start}-${end}/${totalSize}`;
60
- const res = await (0, http_ts_1.execute)({
61
- url: uploadUrl,
62
- method: "PUT",
63
- headers: {
64
- "Content-Length": thisChunk.length.toString(),
65
- "Content-Range": contentRange,
66
- },
67
- data: thisChunk,
68
- responseType: "json",
69
- });
70
- position += thisChunk.length;
71
- if (progress && totalSize > 0) {
72
- progress(Math.min(100, (position / totalSize) * 100));
73
- }
74
- currentChunk = currentChunk.subarray(chunkSize);
75
- if (isDriveItem(res)) {
76
- driveItem = res;
77
- break;
78
- }
79
- }
80
- if (driveItem)
64
+ const reader = contentStream[Symbol.asyncIterator] ? contentStream[Symbol.asyncIterator]() : null;
65
+ if (!reader) {
66
+ throw new InvalidArgumentError_ts_1.default("contentStream is not an async iterable");
67
+ }
68
+ const buffer = Buffer.alloc(chunkSize);
69
+ let contentPosition = 0;
70
+ let item = null;
71
+ while (contentPosition < contentLength) {
72
+ const used = await read(chunkSize, contentPosition, contentLength, reader, buffer);
73
+ const subBuffer = buffer.subarray(0, used);
74
+ const start = contentPosition;
75
+ const end = contentPosition + subBuffer.length - 1;
76
+ const contentRange = `bytes ${start}-${end}/${contentLength}`;
77
+ const response = await (0, http_ts_1.execute)({
78
+ url: uploadUrl,
79
+ method: "PUT",
80
+ headers: {
81
+ "Content-Length": subBuffer.length.toString(),
82
+ "Content-Range": contentRange,
83
+ },
84
+ data: subBuffer,
85
+ responseType: "json",
86
+ });
87
+ contentPosition += used;
88
+ progress(contentPosition);
89
+ if (isDriveItem(response)) {
90
+ item = response;
81
91
  break;
82
- chunk = await readChunk();
92
+ }
83
93
  }
84
- if (!driveItem) {
85
- throw new ProtocolError_ts_1.default(`Upload did not complete successfully. Last position: ${position}`);
94
+ if (!item) {
95
+ throw new ProtocolError_ts_1.default(`Upload did not complete successfully. Last position: ${contentPosition}`);
86
96
  }
87
- const itemRef = (0, driveItem_ts_1.createDriveItemRef)(parentRef, driveItem.id);
97
+ const itemRef = (0, driveItem_ts_1.createDriveItemRef)(parentRef, item.id);
88
98
  return {
89
- ...driveItem,
99
+ ...item,
90
100
  ...itemRef,
91
101
  };
92
102
  function isDriveItem(obj) {
93
103
  return typeof obj === "object" && obj !== null && "id" in obj;
94
104
  }
95
- function readChunk() {
96
- return new Promise((resolve, reject) => {
97
- if (chunks.length > 0) {
98
- const next = chunks.shift();
99
- return resolve(next ?? null);
100
- }
101
- if (streamEnded)
102
- return resolve(null);
103
- contentStream.once("data", (chunk) => {
104
- resolve(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
105
- });
106
- contentStream.once("end", () => {
107
- streamEnded = true;
108
- resolve(null);
109
- });
110
- contentStream.once("error", (err) => {
111
- reject(err);
112
- });
113
- });
105
+ }
106
+ async function read(chunkSize, contentPosition, contentLength, reader, buffer) {
107
+ let length = 0;
108
+ while (length < chunkSize && contentPosition + length < contentLength) {
109
+ const { value, done } = await reader.next();
110
+ if (done)
111
+ break;
112
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
113
+ const toCopy = Math.min(chunk.length, chunkSize - length, contentLength - contentPosition - length);
114
+ chunk.copy(buffer, length, 0, toCopy);
115
+ length += toCopy;
114
116
  }
117
+ return length;
115
118
  }
@@ -201,14 +201,19 @@ function waitToString(milliseconds) {
201
201
  function errorObjectToString(obj) {
202
202
  const maxLength = 1024;
203
203
  const ellipses = "...";
204
- let str = JSON.stringify(obj, null, 2)
205
- .split("\n")
206
- .map((line) => ` ${line}`)
207
- .join("\n");
208
- if (str.length > maxLength) {
209
- str = `${str.substring(0, maxLength - ellipses.length)}${ellipses}`;
210
- }
211
- return `${str}\n`;
204
+ try {
205
+ let str = JSON.stringify(obj, null, 2)
206
+ .split("\n")
207
+ .map((line) => ` ${line}`)
208
+ .join("\n");
209
+ if (str.length > maxLength) {
210
+ str = `${str.substring(0, maxLength - ellipses.length)}${ellipses}`;
211
+ }
212
+ return `${str}\n`;
213
+ }
214
+ catch (_) {
215
+ return "<not displayable>\n";
216
+ }
212
217
  }
213
218
  function handleResponseError(response, errorLog, attempts, operationIndex = null) {
214
219
  const error = response.data;
@@ -6,12 +6,29 @@
6
6
  import type { DriveItem } from "@microsoft/microsoft-graph-types";
7
7
  import type { DriveRef } from "../../models/Drive.ts";
8
8
  import type { DriveItemPath, DriveItemRef } from "../../models/DriveItem.ts";
9
+ /**
10
+ * The required chunk size multiple for upload sessions.
11
+ * @remarks Microsoft Graph requires that each upload chunk is a multiple of 320 KiB (327,680 bytes).
12
+ * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
13
+ */
14
+ export declare const chunkSizeMultiple: number;
15
+ /**
16
+ * Options for creating a drive item with content upload.
17
+ * @property conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Can be 'fail', 'replace', or 'rename'.
18
+ * @property chunkSize Optional. The size of each upload chunk in bytes. Must be a multiple of 320 KiB (327,680 bytes).
19
+ * @property progress Optional. Callback function called with the number of bytes uploaded after each chunk.
20
+ */
21
+ export interface CreateDriveItemContentOptions {
22
+ conflictBehavior?: "fail" | "replace" | "rename";
23
+ chunkSize?: number;
24
+ progress?: (bytes: number) => void;
25
+ }
9
26
  /**
10
27
  * Creates a new drive item in the specified parent drive or folder using a stream as content.
11
28
  * @param parentRef Reference to the parent drive or folder where the drive item will be created.
12
29
  * @param itemPath Path (including the filename) for the new drive item within the given parent.
13
30
  * @param contentStream A Node.js readable stream containing the file content.
14
- * @param totalSize The total size in bytes of the content to be uploaded.
31
+ * @param contentLength The total size in bytes of the content to be uploaded.
15
32
  * @param options Optional. Additional options for the upload operation.
16
33
  * @param options.conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
17
34
  * @param options.chunkSize Optional. The size of each chunk to be uploaded in bytes. Default is 10MB.
@@ -20,10 +37,5 @@ import type { DriveItemPath, DriveItemRef } from "../../models/DriveItem.ts";
20
37
  * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
21
38
  * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
22
39
  */
23
- export interface CreateDriveItemContentOptions {
24
- conflictBehavior?: "fail" | "replace" | "rename";
25
- chunkSize?: number;
26
- progress?: (pct: number) => void;
27
- }
28
- export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, totalSize: number, options?: CreateDriveItemContentOptions): Promise<DriveItem & DriveItemRef>;
40
+ export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, contentLength: number, options?: CreateDriveItemContentOptions): Promise<DriveItem & DriveItemRef>;
29
41
  //# sourceMappingURL=createDriveItemContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/createDriveItemContent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAElE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAe,aAAa,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAkB1F;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,6BAA6B;IAC7C,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,wBAA8B,sBAAsB,CAAC,SAAS,EAAE,QAAQ,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,CAwGzP"}
1
+ {"version":3,"file":"createDriveItemContent.d.ts","sourceRoot":"","sources":["../../../../src/operations/driveItem/createDriveItemContent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAGlE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAe,aAAa,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAM1F;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAc5C;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC7C,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAA8B,sBAAsB,CAAC,SAAS,EAAE,QAAQ,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,CA+E7P"}
@@ -3,14 +3,38 @@
3
3
  * @module createDriveItemContent
4
4
  * @category Operations
5
5
  */
6
+ import InvalidArgumentError from "../../errors/InvalidArgumentError.js";
6
7
  import ProtocolError from "../../errors/ProtocolError.js";
7
8
  import { createDriveItemRef } from "../../services/driveItem.js";
8
9
  import { execute } from "../../services/http.js";
9
10
  import { endpoint } from "../../services/operationInvoker.js";
10
11
  import { generatePath } from "../../services/templatedPaths.js";
11
- const defaultChunkSize = 10 * 1024 * 1024;
12
- export default async function createDriveItemContent(parentRef, itemPath, contentStream, totalSize, options = {}) {
13
- const { conflictBehavior = "fail", chunkSize = defaultChunkSize, progress } = options;
12
+ /**
13
+ * The required chunk size multiple for upload sessions.
14
+ * @remarks Microsoft Graph requires that each upload chunk is a multiple of 320 KiB (327,680 bytes).
15
+ * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
16
+ */
17
+ export const chunkSizeMultiple = 320 * 1024;
18
+ const defaultChunkSize = chunkSizeMultiple * 32;
19
+ /**
20
+ * Creates a new drive item in the specified parent drive or folder using a stream as content.
21
+ * @param parentRef Reference to the parent drive or folder where the drive item will be created.
22
+ * @param itemPath Path (including the filename) for the new drive item within the given parent.
23
+ * @param contentStream A Node.js readable stream containing the file content.
24
+ * @param contentLength The total size in bytes of the content to be uploaded.
25
+ * @param options Optional. Additional options for the upload operation.
26
+ * @param options.conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
27
+ * @param options.chunkSize Optional. The size of each chunk to be uploaded in bytes. Default is 10MB.
28
+ * @param options.progress Optional. A callback function that is called periodically with the upload progress as a percentage.
29
+ * @returns The newly created drive item.
30
+ * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
31
+ * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
32
+ */
33
+ export default async function createDriveItemContent(parentRef, itemPath, contentStream, contentLength, options = {}) {
34
+ const { conflictBehavior = "fail", chunkSize = defaultChunkSize, progress = () => { } } = options;
35
+ if (chunkSize % chunkSizeMultiple !== 0) {
36
+ throw new InvalidArgumentError(`Chunk size (${chunkSize.toLocaleString()}) must be a multiple of ${(chunkSizeMultiple / 1024).toLocaleString()} KiB *${chunkSizeMultiple.toLocaleString()} bytes).`);
37
+ }
14
38
  const pathSegment = parentRef.itemId ? "items/{item-id}" : "root";
15
39
  const uploadSessionUrl = `${endpoint}${generatePath(`/sites/{site-id}/drives/{drive-id}/${pathSegment}:/${itemPath}:/createUploadSession`, parentRef)}`;
16
40
  const accessToken = await parentRef.context.generateAccessToken();
@@ -30,80 +54,58 @@ export default async function createDriveItemContent(parentRef, itemPath, conten
30
54
  }),
31
55
  responseType: "json",
32
56
  });
33
- let position = 0;
34
- let driveItem = null;
35
- let streamEnded = false;
36
- const chunks = [];
37
- contentStream.on("data", (chunk) => {
38
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
39
- });
40
- contentStream.on("end", () => {
41
- streamEnded = true;
42
- });
43
- contentStream.on("error", () => {
44
- // error will be handled in readChunk
45
- });
46
- let chunk = await readChunk();
47
- while (chunk !== null) {
48
- let currentChunk = chunk;
49
- while (currentChunk.length > 0) {
50
- const thisChunk = currentChunk.subarray(0, chunkSize);
51
- const start = position;
52
- const end = position + thisChunk.length - 1;
53
- const contentRange = `bytes ${start}-${end}/${totalSize}`;
54
- const res = await execute({
55
- url: uploadUrl,
56
- method: "PUT",
57
- headers: {
58
- "Content-Length": thisChunk.length.toString(),
59
- "Content-Range": contentRange,
60
- },
61
- data: thisChunk,
62
- responseType: "json",
63
- });
64
- position += thisChunk.length;
65
- if (progress && totalSize > 0) {
66
- progress(Math.min(100, (position / totalSize) * 100));
67
- }
68
- currentChunk = currentChunk.subarray(chunkSize);
69
- if (isDriveItem(res)) {
70
- driveItem = res;
71
- break;
72
- }
73
- }
74
- if (driveItem)
57
+ const reader = contentStream[Symbol.asyncIterator] ? contentStream[Symbol.asyncIterator]() : null;
58
+ if (!reader) {
59
+ throw new InvalidArgumentError("contentStream is not an async iterable");
60
+ }
61
+ const buffer = Buffer.alloc(chunkSize);
62
+ let contentPosition = 0;
63
+ let item = null;
64
+ while (contentPosition < contentLength) {
65
+ const used = await read(chunkSize, contentPosition, contentLength, reader, buffer);
66
+ const subBuffer = buffer.subarray(0, used);
67
+ const start = contentPosition;
68
+ const end = contentPosition + subBuffer.length - 1;
69
+ const contentRange = `bytes ${start}-${end}/${contentLength}`;
70
+ const response = await execute({
71
+ url: uploadUrl,
72
+ method: "PUT",
73
+ headers: {
74
+ "Content-Length": subBuffer.length.toString(),
75
+ "Content-Range": contentRange,
76
+ },
77
+ data: subBuffer,
78
+ responseType: "json",
79
+ });
80
+ contentPosition += used;
81
+ progress(contentPosition);
82
+ if (isDriveItem(response)) {
83
+ item = response;
75
84
  break;
76
- chunk = await readChunk();
85
+ }
77
86
  }
78
- if (!driveItem) {
79
- throw new ProtocolError(`Upload did not complete successfully. Last position: ${position}`);
87
+ if (!item) {
88
+ throw new ProtocolError(`Upload did not complete successfully. Last position: ${contentPosition}`);
80
89
  }
81
- const itemRef = createDriveItemRef(parentRef, driveItem.id);
90
+ const itemRef = createDriveItemRef(parentRef, item.id);
82
91
  return {
83
- ...driveItem,
92
+ ...item,
84
93
  ...itemRef,
85
94
  };
86
95
  function isDriveItem(obj) {
87
96
  return typeof obj === "object" && obj !== null && "id" in obj;
88
97
  }
89
- function readChunk() {
90
- return new Promise((resolve, reject) => {
91
- if (chunks.length > 0) {
92
- const next = chunks.shift();
93
- return resolve(next ?? null);
94
- }
95
- if (streamEnded)
96
- return resolve(null);
97
- contentStream.once("data", (chunk) => {
98
- resolve(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
99
- });
100
- contentStream.once("end", () => {
101
- streamEnded = true;
102
- resolve(null);
103
- });
104
- contentStream.once("error", (err) => {
105
- reject(err);
106
- });
107
- });
98
+ }
99
+ async function read(chunkSize, contentPosition, contentLength, reader, buffer) {
100
+ let length = 0;
101
+ while (length < chunkSize && contentPosition + length < contentLength) {
102
+ const { value, done } = await reader.next();
103
+ if (done)
104
+ break;
105
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
106
+ const toCopy = Math.min(chunk.length, chunkSize - length, contentLength - contentPosition - length);
107
+ chunk.copy(buffer, length, 0, toCopy);
108
+ length += toCopy;
108
109
  }
110
+ return length;
109
111
  }
@@ -193,14 +193,19 @@ function waitToString(milliseconds) {
193
193
  function errorObjectToString(obj) {
194
194
  const maxLength = 1024;
195
195
  const ellipses = "...";
196
- let str = JSON.stringify(obj, null, 2)
197
- .split("\n")
198
- .map((line) => ` ${line}`)
199
- .join("\n");
200
- if (str.length > maxLength) {
201
- str = `${str.substring(0, maxLength - ellipses.length)}${ellipses}`;
202
- }
203
- return `${str}\n`;
196
+ try {
197
+ let str = JSON.stringify(obj, null, 2)
198
+ .split("\n")
199
+ .map((line) => ` ${line}`)
200
+ .join("\n");
201
+ if (str.length > maxLength) {
202
+ str = `${str.substring(0, maxLength - ellipses.length)}${ellipses}`;
203
+ }
204
+ return `${str}\n`;
205
+ }
206
+ catch (_) {
207
+ return "<not displayable>\n";
208
+ }
204
209
  }
205
210
  function handleResponseError(response, errorLog, attempts, operationIndex = null) {
206
211
  const error = response.data;
@@ -10,44 +10,7 @@ Creates a new drive item in the specified parent drive or folder using a stream
10
10
 
11
11
  Defined in: [src/operations/driveItem/createDriveItemContent.ts:42](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L42)
12
12
 
13
- Creates a new drive item in the specified parent drive or folder using a stream as content.
14
-
15
- #### Param
16
-
17
- Reference to the parent drive or folder where the drive item will be created.
18
-
19
- #### Param
20
-
21
- Path (including the filename) for the new drive item within the given parent.
22
-
23
- #### Param
24
-
25
- A Node.js readable stream containing the file content.
26
-
27
- #### Param
28
-
29
- The total size in bytes of the content to be uploaded.
30
-
31
- #### Param
32
-
33
- Optional. Additional options for the upload operation.
34
-
35
- #### Param
36
-
37
- Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
38
-
39
- #### Param
40
-
41
- Optional. The size of each chunk to be uploaded in bytes. Default is 10MB.
42
-
43
- #### Param
44
-
45
- Optional. A callback function that is called periodically with the upload progress as a percentage.
46
-
47
- #### See
48
-
49
- - https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
50
- - https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
13
+ Options for creating a drive item with content upload.
51
14
 
52
15
  #### Properties
53
16
 
@@ -57,46 +20,79 @@ Optional. A callback function that is called periodically with the upload progre
57
20
 
58
21
  Defined in: [src/operations/driveItem/createDriveItemContent.ts:44](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L44)
59
22
 
23
+ Optional. The size of each upload chunk in bytes. Must be a multiple of 320 KiB (327,680 bytes).
24
+
60
25
  ##### conflictBehavior?
61
26
 
62
27
  > `optional` **conflictBehavior**: `"replace"` \| `"fail"` \| `"rename"`
63
28
 
64
29
  Defined in: [src/operations/driveItem/createDriveItemContent.ts:43](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L43)
65
30
 
31
+ Optional. Specifies how to handle conflicts if the file already exists. Can be 'fail', 'replace', or 'rename'.
32
+
66
33
  ##### progress()?
67
34
 
68
- > `optional` **progress**: (`pct`) => `void`
35
+ > `optional` **progress**: (`bytes`) => `void`
69
36
 
70
37
  Defined in: [src/operations/driveItem/createDriveItemContent.ts:45](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L45)
71
38
 
39
+ Optional. Callback function called with the number of bytes uploaded after each chunk.
40
+
72
41
  ###### Parameters
73
42
 
74
43
  | Parameter | Type |
75
44
  | ------ | ------ |
76
- | `pct` | `number` |
45
+ | `bytes` | `number` |
77
46
 
78
47
  ###### Returns
79
48
 
80
49
  `void`
81
50
 
51
+ ## Variables
52
+
53
+ ### chunkSizeMultiple
54
+
55
+ > `const` **chunkSizeMultiple**: `number`
56
+
57
+ Defined in: [src/operations/driveItem/createDriveItemContent.ts:22](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L22)
58
+
59
+ The required chunk size multiple for upload sessions.
60
+
61
+ #### Remarks
62
+
63
+ Microsoft Graph requires that each upload chunk is a multiple of 320 KiB (327,680 bytes).
64
+
65
+ #### See
66
+
67
+ https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
68
+
82
69
  ## Functions
83
70
 
84
71
  ### createDriveItemContent()
85
72
 
86
- > **createDriveItemContent**(`parentRef`, `itemPath`, `contentStream`, `totalSize`, `options`): [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`DriveItem` & [`SiteRef`](Site-1.md#siteref) & `object` & `object`\>
73
+ > **createDriveItemContent**(`parentRef`, `itemPath`, `contentStream`, `contentLength`, `options`): [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`DriveItem` & [`SiteRef`](Site-1.md#siteref) & `object` & `object`\>
74
+
75
+ Defined in: [src/operations/driveItem/createDriveItemContent.ts:62](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L62)
87
76
 
88
- Defined in: [src/operations/driveItem/createDriveItemContent.ts:48](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L48)
77
+ Creates a new drive item in the specified parent drive or folder using a stream as content.
89
78
 
90
79
  #### Parameters
91
80
 
92
- | Parameter | Type |
93
- | ------ | ------ |
94
- | `parentRef` | [`DriveRef`](Drive-1.md#driveref) \| [`DriveItemRef`](DriveItem-1.md#driveitemref) |
95
- | `itemPath` | [`DriveItemPath`](DriveItem-1.md#driveitempath) |
96
- | `contentStream` | [`ReadableStream`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/globals.d.ts#L202) |
97
- | `totalSize` | `number` |
98
- | `options` | [`CreateDriveItemContentOptions`](#createdriveitemcontentoptions) |
81
+ | Parameter | Type | Description |
82
+ | ------ | ------ | ------ |
83
+ | `parentRef` | [`DriveRef`](Drive-1.md#driveref) \| [`DriveItemRef`](DriveItem-1.md#driveitemref) | Reference to the parent drive or folder where the drive item will be created. |
84
+ | `itemPath` | [`DriveItemPath`](DriveItem-1.md#driveitempath) | Path (including the filename) for the new drive item within the given parent. |
85
+ | `contentStream` | [`ReadableStream`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/globals.d.ts#L202) | A Node.js readable stream containing the file content. |
86
+ | `contentLength` | `number` | The total size in bytes of the content to be uploaded. |
87
+ | `options` | [`CreateDriveItemContentOptions`](#createdriveitemcontentoptions) | Optional. Additional options for the upload operation. |
99
88
 
100
89
  #### Returns
101
90
 
102
91
  [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)\<`DriveItem` & [`SiteRef`](Site-1.md#siteref) & `object` & `object`\>
92
+
93
+ The newly created drive item.
94
+
95
+ #### See
96
+
97
+ - https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
98
+ - https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "microsoft-graph",
3
- "version": "3.9.1",
3
+ "version": "3.9.3",
4
4
  "description": "Microsoft GraphAPI SDK for NodeJS",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",