microsoft-graph 3.9.0 → 3.9.2

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,16 +6,36 @@
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.
15
- * @param conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
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.
16
36
  * @returns The newly created drive item.
17
37
  * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
18
38
  * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
19
39
  */
20
- export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, totalSize: number, conflictBehavior?: "fail" | "replace" | "rename", chunkSize?: number): Promise<DriveItem & DriveItemRef>;
40
+ export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, contentLength: number, options?: CreateDriveItemContentOptions): Promise<DriveItem & DriveItemRef>;
21
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;;;;;;;;;;GAUG;AACH,wBAA8B,sBAAsB,CAAC,SAAS,EAAE,QAAQ,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAM,GAAG,SAAS,GAAG,QAAiB,EAAE,SAAS,SAAmB,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,CAmGpS"}
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,25 +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;
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;
18
26
  /**
19
27
  * Creates a new drive item in the specified parent drive or folder using a stream as content.
20
28
  * @param parentRef Reference to the parent drive or folder where the drive item will be created.
21
29
  * @param itemPath Path (including the filename) for the new drive item within the given parent.
22
30
  * @param contentStream A Node.js readable stream containing the file content.
23
- * @param totalSize The total size in bytes of the content to be uploaded.
24
- * @param conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
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.
25
36
  * @returns The newly created drive item.
26
37
  * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
27
38
  * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
28
39
  */
29
- async function createDriveItemContent(parentRef, itemPath, contentStream, totalSize, conflictBehavior = "fail", chunkSize = defaultChunkSize) {
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
+ }
30
45
  const pathSegment = parentRef.itemId ? "items/{item-id}" : "root";
31
46
  const uploadSessionUrl = `${operationInvoker_ts_1.endpoint}${(0, templatedPaths_ts_1.generatePath)(`/sites/{site-id}/drives/{drive-id}/${pathSegment}:/${itemPath}:/createUploadSession`, parentRef)}`;
32
47
  const accessToken = await parentRef.context.generateAccessToken();
@@ -46,77 +61,58 @@ async function createDriveItemContent(parentRef, itemPath, contentStream, totalS
46
61
  }),
47
62
  responseType: "json",
48
63
  });
49
- let position = 0;
50
- let driveItem = null;
51
- let streamEnded = false;
52
- const chunks = [];
53
- contentStream.on("data", (chunk) => {
54
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
55
- });
56
- contentStream.on("end", () => {
57
- streamEnded = true;
58
- });
59
- contentStream.on("error", () => {
60
- // error will be handled in readChunk
61
- });
62
- let chunk = await readChunk();
63
- while (chunk !== null) {
64
- let currentChunk = chunk;
65
- while (currentChunk.length > 0) {
66
- const thisChunk = currentChunk.subarray(0, chunkSize);
67
- const start = position;
68
- const end = position + thisChunk.length - 1;
69
- const contentRange = `bytes ${start}-${end}/${totalSize}`;
70
- const res = await (0, http_ts_1.execute)({
71
- url: uploadUrl,
72
- method: "PUT",
73
- headers: {
74
- "Content-Length": thisChunk.length.toString(),
75
- "Content-Range": contentRange,
76
- },
77
- data: thisChunk,
78
- responseType: "json",
79
- });
80
- position += thisChunk.length;
81
- currentChunk = currentChunk.subarray(chunkSize);
82
- if (isDriveItem(res)) {
83
- driveItem = res;
84
- break;
85
- }
86
- }
87
- 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;
88
91
  break;
89
- chunk = await readChunk();
92
+ }
90
93
  }
91
- if (!driveItem) {
92
- 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}`);
93
96
  }
94
- const itemRef = (0, driveItem_ts_1.createDriveItemRef)(parentRef, driveItem.id);
97
+ const itemRef = (0, driveItem_ts_1.createDriveItemRef)(parentRef, item.id);
95
98
  return {
96
- ...driveItem,
99
+ ...item,
97
100
  ...itemRef,
98
101
  };
99
102
  function isDriveItem(obj) {
100
103
  return typeof obj === "object" && obj !== null && "id" in obj;
101
104
  }
102
- function readChunk() {
103
- return new Promise((resolve, reject) => {
104
- if (chunks.length > 0) {
105
- const next = chunks.shift();
106
- return resolve(next ?? null);
107
- }
108
- if (streamEnded)
109
- return resolve(null);
110
- contentStream.once("data", (chunk) => {
111
- resolve(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
112
- });
113
- contentStream.once("end", () => {
114
- streamEnded = true;
115
- resolve(null);
116
- });
117
- contentStream.once("error", (err) => {
118
- reject(err);
119
- });
120
- });
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;
121
116
  }
117
+ return length;
122
118
  }
@@ -6,16 +6,36 @@
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.
15
- * @param conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
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.
16
36
  * @returns The newly created drive item.
17
37
  * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
18
38
  * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
19
39
  */
20
- export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, totalSize: number, conflictBehavior?: "fail" | "replace" | "rename", chunkSize?: number): Promise<DriveItem & DriveItemRef>;
40
+ export default function createDriveItemContent(parentRef: DriveRef | DriveItemRef, itemPath: DriveItemPath, contentStream: NodeJS.ReadableStream, contentLength: number, options?: CreateDriveItemContentOptions): Promise<DriveItem & DriveItemRef>;
21
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;;;;;;;;;;GAUG;AACH,wBAA8B,sBAAsB,CAAC,SAAS,EAAE,QAAQ,GAAG,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAM,GAAG,SAAS,GAAG,QAAiB,EAAE,SAAS,SAAmB,GAAG,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC,CAmGpS"}
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,24 +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
+ /**
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;
12
19
  /**
13
20
  * Creates a new drive item in the specified parent drive or folder using a stream as content.
14
21
  * @param parentRef Reference to the parent drive or folder where the drive item will be created.
15
22
  * @param itemPath Path (including the filename) for the new drive item within the given parent.
16
23
  * @param contentStream A Node.js readable stream containing the file content.
17
- * @param totalSize The total size in bytes of the content to be uploaded.
18
- * @param conflictBehavior Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'.
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.
19
29
  * @returns The newly created drive item.
20
30
  * @see https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession
21
31
  * @see https://learn.microsoft.com/en-us/graph/api/resources/uploadsession
22
32
  */
23
- export default async function createDriveItemContent(parentRef, itemPath, contentStream, totalSize, conflictBehavior = "fail", chunkSize = defaultChunkSize) {
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
+ }
24
38
  const pathSegment = parentRef.itemId ? "items/{item-id}" : "root";
25
39
  const uploadSessionUrl = `${endpoint}${generatePath(`/sites/{site-id}/drives/{drive-id}/${pathSegment}:/${itemPath}:/createUploadSession`, parentRef)}`;
26
40
  const accessToken = await parentRef.context.generateAccessToken();
@@ -40,77 +54,58 @@ export default async function createDriveItemContent(parentRef, itemPath, conten
40
54
  }),
41
55
  responseType: "json",
42
56
  });
43
- let position = 0;
44
- let driveItem = null;
45
- let streamEnded = false;
46
- const chunks = [];
47
- contentStream.on("data", (chunk) => {
48
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
49
- });
50
- contentStream.on("end", () => {
51
- streamEnded = true;
52
- });
53
- contentStream.on("error", () => {
54
- // error will be handled in readChunk
55
- });
56
- let chunk = await readChunk();
57
- while (chunk !== null) {
58
- let currentChunk = chunk;
59
- while (currentChunk.length > 0) {
60
- const thisChunk = currentChunk.subarray(0, chunkSize);
61
- const start = position;
62
- const end = position + thisChunk.length - 1;
63
- const contentRange = `bytes ${start}-${end}/${totalSize}`;
64
- const res = await execute({
65
- url: uploadUrl,
66
- method: "PUT",
67
- headers: {
68
- "Content-Length": thisChunk.length.toString(),
69
- "Content-Range": contentRange,
70
- },
71
- data: thisChunk,
72
- responseType: "json",
73
- });
74
- position += thisChunk.length;
75
- currentChunk = currentChunk.subarray(chunkSize);
76
- if (isDriveItem(res)) {
77
- driveItem = res;
78
- break;
79
- }
80
- }
81
- 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;
82
84
  break;
83
- chunk = await readChunk();
85
+ }
84
86
  }
85
- if (!driveItem) {
86
- 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}`);
87
89
  }
88
- const itemRef = createDriveItemRef(parentRef, driveItem.id);
90
+ const itemRef = createDriveItemRef(parentRef, item.id);
89
91
  return {
90
- ...driveItem,
92
+ ...item,
91
93
  ...itemRef,
92
94
  };
93
95
  function isDriveItem(obj) {
94
96
  return typeof obj === "object" && obj !== null && "id" in obj;
95
97
  }
96
- function readChunk() {
97
- return new Promise((resolve, reject) => {
98
- if (chunks.length > 0) {
99
- const next = chunks.shift();
100
- return resolve(next ?? null);
101
- }
102
- if (streamEnded)
103
- return resolve(null);
104
- contentStream.once("data", (chunk) => {
105
- resolve(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
106
- });
107
- contentStream.once("end", () => {
108
- streamEnded = true;
109
- resolve(null);
110
- });
111
- contentStream.once("error", (err) => {
112
- reject(err);
113
- });
114
- });
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;
115
109
  }
110
+ return length;
116
111
  }
@@ -4,26 +4,87 @@
4
4
 
5
5
  Creates a new drive item in the specified parent drive or folder using a stream as content.
6
6
 
7
+ ## Interfaces
8
+
9
+ ### CreateDriveItemContentOptions
10
+
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
+
13
+ Options for creating a drive item with content upload.
14
+
15
+ #### Properties
16
+
17
+ ##### chunkSize?
18
+
19
+ > `optional` **chunkSize**: `number`
20
+
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)
22
+
23
+ Optional. The size of each upload chunk in bytes. Must be a multiple of 320 KiB (327,680 bytes).
24
+
25
+ ##### conflictBehavior?
26
+
27
+ > `optional` **conflictBehavior**: `"replace"` \| `"fail"` \| `"rename"`
28
+
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)
30
+
31
+ Optional. Specifies how to handle conflicts if the file already exists. Can be 'fail', 'replace', or 'rename'.
32
+
33
+ ##### progress()?
34
+
35
+ > `optional` **progress**: (`bytes`) => `void`
36
+
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)
38
+
39
+ Optional. Callback function called with the number of bytes uploaded after each chunk.
40
+
41
+ ###### Parameters
42
+
43
+ | Parameter | Type |
44
+ | ------ | ------ |
45
+ | `bytes` | `number` |
46
+
47
+ ###### Returns
48
+
49
+ `void`
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
+
7
69
  ## Functions
8
70
 
9
71
  ### createDriveItemContent()
10
72
 
11
- > **createDriveItemContent**(`parentRef`, `itemPath`, `contentStream`, `totalSize`, `conflictBehavior`, `chunkSize`): [`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`\>
12
74
 
13
- Defined in: [src/operations/driveItem/createDriveItemContent.ts:39](https://github.com/Future-Secure-AI/microsoft-graph/blob/main/src/operations/driveItem/createDriveItemContent.ts#L39)
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)
14
76
 
15
77
  Creates a new drive item in the specified parent drive or folder using a stream as content.
16
78
 
17
79
  #### Parameters
18
80
 
19
- | Parameter | Type | Default value | Description |
20
- | ------ | ------ | ------ | ------ |
21
- | `parentRef` | [`DriveRef`](Drive-1.md#driveref) \| [`DriveItemRef`](DriveItem-1.md#driveitemref) | `undefined` | Reference to the parent drive or folder where the drive item will be created. |
22
- | `itemPath` | [`DriveItemPath`](DriveItem-1.md#driveitempath) | `undefined` | Path (including the filename) for the new drive item within the given parent. |
23
- | `contentStream` | [`ReadableStream`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/globals.d.ts#L202) | `undefined` | A Node.js readable stream containing the file content. |
24
- | `totalSize` | `number` | `undefined` | The total size in bytes of the content to be uploaded. |
25
- | `conflictBehavior` | `"replace"` \| `"fail"` \| `"rename"` | `"fail"` | Optional. Specifies how to handle conflicts if the file already exists. Default is 'fail'. |
26
- | `chunkSize` | `number` | `defaultChunkSize` | - |
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. |
27
88
 
28
89
  #### Returns
29
90
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "microsoft-graph",
3
- "version": "3.9.0",
3
+ "version": "3.9.2",
4
4
  "description": "Microsoft GraphAPI SDK for NodeJS",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",