chub-dev 0.1.0 → 0.1.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1421 @@
1
+ ---
2
+ name: onedrive
3
+ description: "Microsoft OneDrive API coding guidelines for JavaScript/TypeScript using the official Microsoft Graph SDK"
4
+ metadata:
5
+ languages: "javascript"
6
+ versions: "3.0.7"
7
+ updated-on: "2026-03-02"
8
+ source: maintainer
9
+ tags: "microsoft,onedrive,storage,graph-api,files"
10
+ ---
11
+
12
+ # Microsoft OneDrive API Coding Guidelines (JavaScript/TypeScript)
13
+
14
+ You are a **Microsoft OneDrive API coding expert**. Help me write correct, idiomatic JavaScript/TypeScript that accesses OneDrive files and folders using the official Microsoft Graph SDK.
15
+
16
+ Use **only official Microsoft sources** for behavior, fields, and constraints. This guide summarizes key patterns for both **Node.js** and **browser** applications.
17
+
18
+ > Ground truth: Microsoft Graph OneDrive API documentation on learn.microsoft.com.
19
+
20
+
21
+ ## Golden Rule: Use the Official Microsoft Graph SDK
22
+
23
+ **ALWAYS use `@microsoft/microsoft-graph-client` version 3.0.7 or later** for OneDrive operations. This is the official Microsoft Graph JavaScript SDK that provides access to OneDrive, SharePoint, and all other Microsoft Graph APIs.
24
+
25
+ **DO NOT use**:
26
+ - Deprecated `onedrivesdk` package (obsolete)
27
+ - Direct REST calls without the SDK (unless absolutely necessary)
28
+ - Unofficial third-party OneDrive libraries
29
+
30
+ **Install (Node.js):**
31
+ ```bash
32
+ npm install @microsoft/microsoft-graph-client
33
+ npm install @azure/identity
34
+ npm install @microsoft/microsoft-graph-client/authProviders/azureTokenCredentials
35
+ ```
36
+
37
+ **For TypeScript projects, add type definitions:**
38
+ ```bash
39
+ npm install --save-dev @microsoft/microsoft-graph-types
40
+ ```
41
+
42
+
43
+ ## Installation
44
+
45
+ ### Complete Setup for Node.js Applications
46
+
47
+ ```bash
48
+ # Core Microsoft Graph SDK
49
+ npm install @microsoft/microsoft-graph-client
50
+
51
+ # Azure authentication library
52
+ npm install @azure/identity
53
+
54
+ # Install isomorphic-fetch for Node.js environments
55
+ npm install isomorphic-fetch
56
+
57
+ # TypeScript types (optional but recommended)
58
+ npm install --save-dev @microsoft/microsoft-graph-types
59
+ ```
60
+
61
+ ### Browser Applications
62
+
63
+ For browser-based applications, you can load the SDK via CDN or bundle it with your application:
64
+
65
+ ```html
66
+ <!-- Microsoft Graph Client -->
67
+ <script src="https://cdn.jsdelivr.net/npm/@microsoft/microsoft-graph-client/lib/graph-js-sdk.js"></script>
68
+
69
+ <!-- For authentication in browser, use MSAL -->
70
+ <script src="https://alcdn.msauth.net/browser/2.32.0/js/msal-browser.min.js"></script>
71
+ ```
72
+
73
+
74
+ ## Authentication
75
+
76
+ OneDrive access through Microsoft Graph requires OAuth 2.0 authentication. You need to register an application in Azure Active Directory (Azure AD) to obtain credentials.
77
+
78
+ ### Azure AD App Registration
79
+
80
+ 1. Go to [Azure Portal](https://portal.azure.com) → Azure Active Directory → App registrations
81
+ 2. Create a new registration
82
+ 3. Note your **Application (client) ID** and **Directory (tenant) ID**
83
+ 4. Create a client secret under "Certificates & secrets"
84
+ 5. Add API permissions: Microsoft Graph → **Files.Read**, **Files.ReadWrite**, **Files.Read.All**, **Files.ReadWrite.All**
85
+ 6. Grant admin consent for the permissions
86
+
87
+ ### Required Scopes
88
+
89
+ Common OneDrive permission scopes:
90
+
91
+ ```javascript
92
+ // Read-only access to user's files
93
+ const SCOPES_READONLY = ['https://graph.microsoft.com/Files.Read'];
94
+
95
+ // Read/write access to user's files
96
+ const SCOPES_READWRITE = ['https://graph.microsoft.com/Files.ReadWrite'];
97
+
98
+ // Read all files user can access (including shared)
99
+ const SCOPES_READ_ALL = ['https://graph.microsoft.com/Files.Read.All'];
100
+
101
+ // Full access to all files user can access
102
+ const SCOPES_READWRITE_ALL = ['https://graph.microsoft.com/Files.ReadWrite.All'];
103
+
104
+ // Application permissions (no user context, requires admin consent)
105
+ const SCOPES_APP = ['https://graph.microsoft.com/.default'];
106
+ ```
107
+
108
+
109
+ ## Initialization
110
+
111
+ ### Node.js with Client Credentials (Service/Daemon Apps)
112
+
113
+ For server-side applications using application permissions:
114
+
115
+ ```typescript
116
+ import { Client } from '@microsoft/microsoft-graph-client';
117
+ import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
118
+ import { ClientSecretCredential } from '@azure/identity';
119
+ import 'isomorphic-fetch';
120
+
121
+ // Environment variables
122
+ const tenantId = process.env.AZURE_TENANT_ID;
123
+ const clientId = process.env.AZURE_CLIENT_ID;
124
+ const clientSecret = process.env.AZURE_CLIENT_SECRET;
125
+
126
+ // Create credential
127
+ const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
128
+
129
+ // Create authentication provider
130
+ const authProvider = new TokenCredentialAuthenticationProvider(credential, {
131
+ scopes: ['https://graph.microsoft.com/.default']
132
+ });
133
+
134
+ // Initialize Microsoft Graph client
135
+ const client = Client.initWithMiddleware({ authProvider });
136
+
137
+ // Example: List files in user's OneDrive root
138
+ async function listFiles(userId) {
139
+ const response = await client
140
+ .api(`/users/${userId}/drive/root/children`)
141
+ .get();
142
+
143
+ return response.value;
144
+ }
145
+ ```
146
+
147
+ ### Node.js with Device Code Flow (Interactive)
148
+
149
+ For CLI applications that need user interaction:
150
+
151
+ ```typescript
152
+ import { Client } from '@microsoft/microsoft-graph-client';
153
+ import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
154
+ import { DeviceCodeCredential } from '@azure/identity';
155
+ import 'isomorphic-fetch';
156
+
157
+ const credential = new DeviceCodeCredential({
158
+ tenantId: process.env.AZURE_TENANT_ID,
159
+ clientId: process.env.AZURE_CLIENT_ID,
160
+ userPromptCallback: (info) => {
161
+ console.log(info.message);
162
+ }
163
+ });
164
+
165
+ const authProvider = new TokenCredentialAuthenticationProvider(credential, {
166
+ scopes: ['Files.ReadWrite', 'Files.Read.All']
167
+ });
168
+
169
+ const client = Client.initWithMiddleware({ authProvider });
170
+ ```
171
+
172
+ ### Node.js with On-Behalf-Of Flow (Web APIs)
173
+
174
+ For web APIs that act on behalf of a signed-in user:
175
+
176
+ ```typescript
177
+ import { Client } from '@microsoft/microsoft-graph-client';
178
+ import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
179
+ import { OnBehalfOfCredential } from '@azure/identity';
180
+
181
+ const credential = new OnBehalfOfCredential({
182
+ tenantId: process.env.AZURE_TENANT_ID,
183
+ clientId: process.env.AZURE_CLIENT_ID,
184
+ clientSecret: process.env.AZURE_CLIENT_SECRET,
185
+ userAssertionToken: userToken // Token from incoming request
186
+ });
187
+
188
+ const authProvider = new TokenCredentialAuthenticationProvider(credential, {
189
+ scopes: ['https://graph.microsoft.com/Files.ReadWrite']
190
+ });
191
+
192
+ const client = Client.initWithMiddleware({ authProvider });
193
+ ```
194
+
195
+ ### Browser with MSAL (Interactive User Sign-In)
196
+
197
+ For single-page applications:
198
+
199
+ ```typescript
200
+ import * as msal from '@azure/msal-browser';
201
+ import { Client } from '@microsoft/microsoft-graph-client';
202
+
203
+ // MSAL configuration
204
+ const msalConfig = {
205
+ auth: {
206
+ clientId: 'YOUR_CLIENT_ID',
207
+ authority: 'https://login.microsoftonline.com/YOUR_TENANT_ID',
208
+ redirectUri: 'http://localhost:3000'
209
+ }
210
+ };
211
+
212
+ const msalInstance = new msal.PublicClientApplication(msalConfig);
213
+
214
+ // Custom authentication provider for MSAL
215
+ class MsalAuthenticationProvider {
216
+ constructor(msalInstance, scopes) {
217
+ this.msalInstance = msalInstance;
218
+ this.scopes = scopes;
219
+ }
220
+
221
+ async getAccessToken() {
222
+ const accounts = this.msalInstance.getAllAccounts();
223
+ if (accounts.length === 0) {
224
+ await this.msalInstance.loginPopup({ scopes: this.scopes });
225
+ }
226
+
227
+ const request = {
228
+ scopes: this.scopes,
229
+ account: this.msalInstance.getAllAccounts()[0]
230
+ };
231
+
232
+ try {
233
+ const response = await this.msalInstance.acquireTokenSilent(request);
234
+ return response.accessToken;
235
+ } catch (error) {
236
+ const response = await this.msalInstance.acquireTokenPopup(request);
237
+ return response.accessToken;
238
+ }
239
+ }
240
+ }
241
+
242
+ // Initialize Graph client
243
+ const authProvider = new MsalAuthenticationProvider(
244
+ msalInstance,
245
+ ['Files.ReadWrite']
246
+ );
247
+
248
+ const client = Client.initWithMiddleware({
249
+ authProvider: (done) => {
250
+ authProvider.getAccessToken().then(token => {
251
+ done(null, token);
252
+ }).catch(err => done(err, null));
253
+ }
254
+ });
255
+ ```
256
+
257
+ ### Environment Variables Setup
258
+
259
+ Create a `.env` file:
260
+
261
+ ```bash
262
+ AZURE_TENANT_ID=your-tenant-id
263
+ AZURE_CLIENT_ID=your-client-id
264
+ AZURE_CLIENT_SECRET=your-client-secret
265
+ USER_ID=user@domain.com
266
+ ```
267
+
268
+ Load environment variables:
269
+
270
+ ```typescript
271
+ import dotenv from 'dotenv';
272
+ dotenv.config();
273
+ ```
274
+
275
+
276
+ ## Core API Surfaces
277
+
278
+
279
+ ### 1. Listing Files and Folders
280
+
281
+ #### List Root Folder Contents
282
+
283
+ ```typescript
284
+ // Current user's OneDrive root
285
+ const result = await client.api('/me/drive/root/children').get();
286
+
287
+ console.log(result.value); // Array of DriveItem objects
288
+ ```
289
+
290
+ #### List Specific Folder Contents
291
+
292
+ ```typescript
293
+ // By item ID
294
+ const result = await client
295
+ .api(`/me/drive/items/{item-id}/children`)
296
+ .get();
297
+
298
+ // By path
299
+ const result = await client
300
+ .api('/me/drive/root:/Documents/Projects:/children')
301
+ .get();
302
+
303
+ // With pagination
304
+ let items = [];
305
+ let nextLink = '/me/drive/root/children';
306
+
307
+ while (nextLink) {
308
+ const response = await client.api(nextLink).get();
309
+ items = items.concat(response.value);
310
+ nextLink = response['@odata.nextLink'];
311
+ }
312
+ ```
313
+
314
+ #### Advanced Listing with Query Parameters
315
+
316
+ ```typescript
317
+ // Select specific fields
318
+ const result = await client
319
+ .api('/me/drive/root/children')
320
+ .select('id,name,size,createdDateTime,lastModifiedDateTime')
321
+ .get();
322
+
323
+ // Filter files by type
324
+ const result = await client
325
+ .api('/me/drive/root/children')
326
+ .filter('file ne null')
327
+ .get();
328
+
329
+ // Order by name
330
+ const result = await client
331
+ .api('/me/drive/root/children')
332
+ .orderby('name asc')
333
+ .get();
334
+
335
+ // Limit results
336
+ const result = await client
337
+ .api('/me/drive/root/children')
338
+ .top(10)
339
+ .get();
340
+
341
+ // Expand related properties
342
+ const result = await client
343
+ .api('/me/drive/root/children')
344
+ .expand('thumbnails')
345
+ .get();
346
+
347
+ // Combine multiple query options
348
+ const result = await client
349
+ .api('/me/drive/root/children')
350
+ .select('id,name,size,file')
351
+ .filter('file ne null')
352
+ .orderby('lastModifiedDateTime desc')
353
+ .top(20)
354
+ .get();
355
+ ```
356
+
357
+ #### List All Drives
358
+
359
+ ```typescript
360
+ // List all drives accessible to user
361
+ const drives = await client.api('/me/drives').get();
362
+
363
+ // Get specific drive
364
+ const drive = await client.api('/drives/{drive-id}').get();
365
+
366
+ // Get default drive
367
+ const defaultDrive = await client.api('/me/drive').get();
368
+ ```
369
+
370
+
371
+ ### 2. Getting File/Folder Metadata
372
+
373
+ #### Get Item Metadata
374
+
375
+ ```typescript
376
+ // By item ID
377
+ const item = await client
378
+ .api(`/me/drive/items/{item-id}`)
379
+ .get();
380
+
381
+ console.log(item.id);
382
+ console.log(item.name);
383
+ console.log(item.size);
384
+ console.log(item.createdDateTime);
385
+ console.log(item.lastModifiedDateTime);
386
+ console.log(item.webUrl);
387
+
388
+ // By path
389
+ const item = await client
390
+ .api('/me/drive/root:/Documents/report.pdf')
391
+ .get();
392
+ ```
393
+
394
+ #### Get File with Specific Properties
395
+
396
+ ```typescript
397
+ const item = await client
398
+ .api('/me/drive/items/{item-id}')
399
+ .select('id,name,size,file,@microsoft.graph.downloadUrl')
400
+ .get();
401
+
402
+ // Access file-specific properties
403
+ if (item.file) {
404
+ console.log('MIME type:', item.file.mimeType);
405
+ console.log('Hashes:', item.file.hashes);
406
+ }
407
+
408
+ // Get download URL
409
+ console.log('Download URL:', item['@microsoft.graph.downloadUrl']);
410
+ ```
411
+
412
+
413
+ ### 3. Downloading Files
414
+
415
+ #### Simple Download (Small Files)
416
+
417
+ ```typescript
418
+ import fs from 'fs';
419
+ import { Readable } from 'stream';
420
+
421
+ // Download file content
422
+ const fileStream = await client
423
+ .api(`/me/drive/items/{item-id}/content`)
424
+ .getStream();
425
+
426
+ // Save to disk
427
+ const writeStream = fs.createWriteStream('./downloaded-file.pdf');
428
+ fileStream.pipe(writeStream);
429
+
430
+ await new Promise((resolve, reject) => {
431
+ writeStream.on('finish', resolve);
432
+ writeStream.on('error', reject);
433
+ });
434
+ ```
435
+
436
+ #### Download with Pre-Authenticated URL
437
+
438
+ ```typescript
439
+ import fetch from 'node-fetch';
440
+ import fs from 'fs';
441
+
442
+ // Get item with download URL
443
+ const item = await client
444
+ .api('/me/drive/items/{item-id}')
445
+ .select('@microsoft.graph.downloadUrl')
446
+ .get();
447
+
448
+ const downloadUrl = item['@microsoft.graph.downloadUrl'];
449
+
450
+ // Download using the URL (valid for a few minutes)
451
+ const response = await fetch(downloadUrl);
452
+ const buffer = await response.buffer();
453
+ fs.writeFileSync('./file.dat', buffer);
454
+ ```
455
+
456
+ #### Download Specific Byte Range
457
+
458
+ ```typescript
459
+ // Download partial file content
460
+ const stream = await client
461
+ .api(`/me/drive/items/{item-id}/content`)
462
+ .header('Range', 'bytes=0-1023')
463
+ .getStream();
464
+ ```
465
+
466
+
467
+ ### 4. Uploading Files
468
+
469
+ #### Simple Upload (Files < 4MB)
470
+
471
+ ```typescript
472
+ import fs from 'fs';
473
+
474
+ // Upload file from buffer or stream
475
+ const fileContent = fs.readFileSync('./local-file.pdf');
476
+
477
+ const uploadedFile = await client
478
+ .api('/me/drive/root:/Documents/uploaded-file.pdf:/content')
479
+ .putStream(fs.createReadStream('./local-file.pdf'));
480
+
481
+ console.log('Uploaded file ID:', uploadedFile.id);
482
+
483
+ // Or upload with buffer
484
+ const uploadedFile = await client
485
+ .api('/me/drive/items/{parent-folder-id}:/filename.txt:/content')
486
+ .put(fileContent);
487
+ ```
488
+
489
+ #### Upload to Specific Folder
490
+
491
+ ```typescript
492
+ // Upload to folder by ID
493
+ const file = await client
494
+ .api(`/me/drive/items/{folder-id}:/newfile.txt:/content`)
495
+ .put('File content here');
496
+
497
+ // Upload to folder by path
498
+ const file = await client
499
+ .api('/me/drive/root:/Documents/Projects:/report.pdf:/content')
500
+ .putStream(fs.createReadStream('./report.pdf'));
501
+ ```
502
+
503
+ #### Large File Upload (Files > 4MB) - Resumable Upload Session
504
+
505
+ ```typescript
506
+ import { LargeFileUploadTask, StreamUpload } from '@microsoft/microsoft-graph-client';
507
+ import fs from 'fs';
508
+
509
+ // Step 1: Create upload session
510
+ const uploadSession = await client
511
+ .api('/me/drive/root:/large-file.zip:/createUploadSession')
512
+ .post({
513
+ item: {
514
+ '@microsoft.graph.conflictBehavior': 'rename',
515
+ name: 'large-file.zip'
516
+ }
517
+ });
518
+
519
+ // Step 2: Upload file in chunks
520
+ const fileObject = new StreamUpload(
521
+ fs.createReadStream('./large-file.zip'),
522
+ 'large-file.zip',
523
+ fs.statSync('./large-file.zip').size
524
+ );
525
+
526
+ const task = new LargeFileUploadTask(client, fileObject, uploadSession);
527
+
528
+ const uploadResult = await task.upload();
529
+
530
+ console.log('Upload complete:', uploadResult);
531
+ ```
532
+
533
+ #### Advanced Large File Upload with Progress Tracking
534
+
535
+ ```typescript
536
+ import { LargeFileUploadTask, StreamUpload, UploadEventHandlers } from '@microsoft/microsoft-graph-client';
537
+ import fs from 'fs';
538
+
539
+ const fileName = 'video.mp4';
540
+ const filePath = './video.mp4';
541
+ const stats = fs.statSync(filePath);
542
+ const fileSize = stats.size;
543
+
544
+ // Create upload session with conflict resolution
545
+ const uploadSession = await client
546
+ .api('/me/drive/root:/Videos:/video.mp4:/createUploadSession')
547
+ .post({
548
+ item: {
549
+ '@microsoft.graph.conflictBehavior': 'replace', // or 'fail', 'rename'
550
+ name: fileName
551
+ }
552
+ });
553
+
554
+ // Configure upload
555
+ const fileStream = fs.createReadStream(filePath);
556
+ const fileObject = new StreamUpload(fileStream, fileName, fileSize);
557
+
558
+ // Upload with custom chunk size (must be multiple of 320 KB)
559
+ const options = {
560
+ rangeSize: 1024 * 1024 * 10, // 10 MB chunks (recommended: 5-10 MB)
561
+ uploadEventHandlers: {
562
+ progress: (range, extraCallbackParam) => {
563
+ const percentage = ((range?.minValue || 0) / fileSize) * 100;
564
+ console.log(`Uploaded ${percentage.toFixed(2)}%`);
565
+ },
566
+ extraCallbackParam: null
567
+ }
568
+ };
569
+
570
+ const task = new LargeFileUploadTask(client, fileObject, uploadSession);
571
+ const uploadResult = await task.upload();
572
+
573
+ console.log('File uploaded successfully:', uploadResult.id);
574
+ ```
575
+
576
+ #### Resume Interrupted Upload
577
+
578
+ ```typescript
579
+ // If upload fails, you can resume from where it stopped
580
+ const uploadSession = await client
581
+ .api('/me/drive/root:/large-file.zip:/createUploadSession')
582
+ .post({
583
+ item: {
584
+ '@microsoft.graph.conflictBehavior': 'replace',
585
+ name: 'large-file.zip'
586
+ }
587
+ });
588
+
589
+ const fileObject = new StreamUpload(
590
+ fs.createReadStream('./large-file.zip'),
591
+ 'large-file.zip',
592
+ fs.statSync('./large-file.zip').size
593
+ );
594
+
595
+ const task = new LargeFileUploadTask(client, fileObject, uploadSession);
596
+
597
+ try {
598
+ const uploadResult = await task.upload();
599
+ console.log('Upload complete');
600
+ } catch (error) {
601
+ console.error('Upload failed, attempting to resume...');
602
+
603
+ // Resume upload
604
+ const resumeResult = await task.resume();
605
+ console.log('Resumed and completed:', resumeResult);
606
+ }
607
+ ```
608
+
609
+
610
+ ### 5. Creating Folders
611
+
612
+ ```typescript
613
+ // Create folder in root
614
+ const folder = await client
615
+ .api('/me/drive/root/children')
616
+ .post({
617
+ name: 'New Folder',
618
+ folder: {},
619
+ '@microsoft.graph.conflictBehavior': 'rename'
620
+ });
621
+
622
+ // Create folder at specific path
623
+ const folder = await client
624
+ .api('/me/drive/root:/Documents/Projects:/children')
625
+ .post({
626
+ name: 'Project Alpha',
627
+ folder: {},
628
+ '@microsoft.graph.conflictBehavior': 'fail' // or 'replace', 'rename'
629
+ });
630
+
631
+ // Create nested folder structure
632
+ const parentFolder = await client
633
+ .api('/me/drive/root/children')
634
+ .post({
635
+ name: 'Parent',
636
+ folder: {}
637
+ });
638
+
639
+ const childFolder = await client
640
+ .api(`/me/drive/items/${parentFolder.id}/children`)
641
+ .post({
642
+ name: 'Child',
643
+ folder: {}
644
+ });
645
+ ```
646
+
647
+
648
+ ### 6. Searching Files
649
+
650
+ ```typescript
651
+ // Search in entire drive
652
+ const results = await client
653
+ .api('/me/drive/root/search(q=\'{search-query}\')')
654
+ .get();
655
+
656
+ // Example: Search for PDFs
657
+ const pdfFiles = await client
658
+ .api('/me/drive/root/search(q=\'.pdf\')')
659
+ .get();
660
+
661
+ // Search in specific folder
662
+ const results = await client
663
+ .api('/me/drive/items/{folder-id}/search(q=\'quarterly report\')')
664
+ .get();
665
+
666
+ // Search with select and filter
667
+ const results = await client
668
+ .api('/me/drive/root/search(q=\'presentation\')')
669
+ .select('id,name,size,webUrl')
670
+ .filter('file ne null')
671
+ .top(10)
672
+ .get();
673
+ ```
674
+
675
+
676
+ ### 7. Updating/Renaming Files and Folders
677
+
678
+ ```typescript
679
+ // Rename file
680
+ const updated = await client
681
+ .api('/me/drive/items/{item-id}')
682
+ .patch({
683
+ name: 'new-name.pdf'
684
+ });
685
+
686
+ // Update file metadata
687
+ const updated = await client
688
+ .api('/me/drive/items/{item-id}')
689
+ .patch({
690
+ description: 'Updated description',
691
+ name: 'renamed-file.docx'
692
+ });
693
+
694
+ // Move file to different folder
695
+ const moved = await client
696
+ .api('/me/drive/items/{item-id}')
697
+ .patch({
698
+ parentReference: {
699
+ id: '{new-parent-folder-id}'
700
+ }
701
+ });
702
+
703
+ // Move and rename simultaneously
704
+ const updated = await client
705
+ .api('/me/drive/items/{item-id}')
706
+ .patch({
707
+ name: 'new-name.xlsx',
708
+ parentReference: {
709
+ id: '{new-parent-folder-id}'
710
+ }
711
+ });
712
+ ```
713
+
714
+
715
+ ### 8. Copying Files
716
+
717
+ ```typescript
718
+ // Copy file to another location
719
+ const copyOperation = await client
720
+ .api('/me/drive/items/{item-id}/copy')
721
+ .post({
722
+ parentReference: {
723
+ id: '{destination-folder-id}'
724
+ },
725
+ name: 'copied-file.pdf'
726
+ });
727
+
728
+ // Monitor copy operation status
729
+ const monitorUrl = copyOperation.headers.get('Location');
730
+
731
+ // Poll for completion
732
+ async function waitForCopy(monitorUrl) {
733
+ while (true) {
734
+ const response = await fetch(monitorUrl);
735
+ const status = await response.json();
736
+
737
+ if (status.status === 'completed') {
738
+ return status.resourceId;
739
+ } else if (status.status === 'failed') {
740
+ throw new Error('Copy failed: ' + status.error);
741
+ }
742
+
743
+ await new Promise(resolve => setTimeout(resolve, 1000));
744
+ }
745
+ }
746
+ ```
747
+
748
+
749
+ ### 9. Deleting Files and Folders
750
+
751
+ ```typescript
752
+ // Delete file or folder
753
+ await client
754
+ .api('/me/drive/items/{item-id}')
755
+ .delete();
756
+
757
+ // Delete by path
758
+ await client
759
+ .api('/me/drive/root:/Documents/old-file.pdf')
760
+ .delete();
761
+ ```
762
+
763
+
764
+ ### 10. Sharing and Permissions
765
+
766
+ #### Create Sharing Link
767
+
768
+ ```typescript
769
+ // Create anonymous view link
770
+ const link = await client
771
+ .api('/me/drive/items/{item-id}/createLink')
772
+ .post({
773
+ type: 'view', // 'view', 'edit', 'embed'
774
+ scope: 'anonymous' // 'anonymous', 'organization'
775
+ });
776
+
777
+ console.log('Share link:', link.link.webUrl);
778
+
779
+ // Create organization-wide edit link
780
+ const link = await client
781
+ .api('/me/drive/items/{item-id}/createLink')
782
+ .post({
783
+ type: 'edit',
784
+ scope: 'organization'
785
+ });
786
+
787
+ // Create link with expiration
788
+ const link = await client
789
+ .api('/me/drive/items/{item-id}/createLink')
790
+ .post({
791
+ type: 'view',
792
+ scope: 'anonymous',
793
+ expirationDateTime: '2025-12-31T23:59:59Z',
794
+ password: 'SecurePass123' // Optional password protection
795
+ });
796
+ ```
797
+
798
+ #### Grant Permissions to Specific Users
799
+
800
+ ```typescript
801
+ // Invite user with edit permissions
802
+ const permission = await client
803
+ .api('/me/drive/items/{item-id}/invite')
804
+ .post({
805
+ requireSignIn: true,
806
+ sendInvitation: true,
807
+ roles: ['write'], // 'read' or 'write'
808
+ recipients: [
809
+ { email: 'user@example.com' }
810
+ ],
811
+ message: 'Here is the file I mentioned'
812
+ });
813
+
814
+ // Add multiple recipients
815
+ const permission = await client
816
+ .api('/me/drive/items/{item-id}/invite')
817
+ .post({
818
+ requireSignIn: false,
819
+ sendInvitation: true,
820
+ roles: ['read'],
821
+ recipients: [
822
+ { email: 'user1@example.com' },
823
+ { email: 'user2@example.com' }
824
+ ]
825
+ });
826
+ ```
827
+
828
+ #### List Permissions
829
+
830
+ ```typescript
831
+ // Get all permissions for an item
832
+ const permissions = await client
833
+ .api('/me/drive/items/{item-id}/permissions')
834
+ .get();
835
+
836
+ permissions.value.forEach(permission => {
837
+ console.log('Permission ID:', permission.id);
838
+ console.log('Roles:', permission.roles);
839
+ if (permission.grantedTo) {
840
+ console.log('Granted to:', permission.grantedTo.user.displayName);
841
+ }
842
+ if (permission.link) {
843
+ console.log('Share link:', permission.link.webUrl);
844
+ }
845
+ });
846
+ ```
847
+
848
+ #### Remove Permissions
849
+
850
+ ```typescript
851
+ // Delete specific permission
852
+ await client
853
+ .api('/me/drive/items/{item-id}/permissions/{permission-id}')
854
+ .delete();
855
+ ```
856
+
857
+ #### List Files Shared With Me
858
+
859
+ ```typescript
860
+ // Get files shared with the current user
861
+ const sharedItems = await client
862
+ .api('/me/drive/sharedWithMe')
863
+ .get();
864
+
865
+ sharedItems.value.forEach(item => {
866
+ console.log('Shared file:', item.name);
867
+ console.log('Owner:', item.remoteItem.createdBy.user.displayName);
868
+ console.log('Parent path:', item.remoteItem.parentReference.path);
869
+ });
870
+ ```
871
+
872
+
873
+ ### 11. Thumbnails
874
+
875
+ ```typescript
876
+ // Get thumbnails for an item
877
+ const thumbnails = await client
878
+ .api('/me/drive/items/{item-id}/thumbnails')
879
+ .get();
880
+
881
+ // Access different sizes
882
+ const thumbs = thumbnails.value[0];
883
+ console.log('Small:', thumbs.small.url);
884
+ console.log('Medium:', thumbs.medium.url);
885
+ console.log('Large:', thumbs.large.url);
886
+
887
+ // Get specific thumbnail size
888
+ const thumbnail = await client
889
+ .api('/me/drive/items/{item-id}/thumbnails/0/medium')
890
+ .get();
891
+
892
+ console.log('Thumbnail URL:', thumbnail.url);
893
+ ```
894
+
895
+
896
+ ### 12. Delta (Change Tracking)
897
+
898
+ ```typescript
899
+ // Get initial delta token and items
900
+ let deltaUrl = '/me/drive/root/delta';
901
+ let allItems = [];
902
+
903
+ while (deltaUrl) {
904
+ const response = await client.api(deltaUrl).get();
905
+
906
+ allItems = allItems.concat(response.value);
907
+
908
+ if (response['@odata.nextLink']) {
909
+ deltaUrl = response['@odata.nextLink'];
910
+ } else {
911
+ // Store delta token for next sync
912
+ const deltaToken = response['@odata.deltaLink'];
913
+ console.log('Delta token:', deltaToken);
914
+ break;
915
+ }
916
+ }
917
+
918
+ // Later, use the delta token to get only changes
919
+ const changes = await client
920
+ .api('/me/drive/root/delta?token={previous-delta-token}')
921
+ .get();
922
+
923
+ changes.value.forEach(item => {
924
+ if (item.deleted) {
925
+ console.log('Deleted:', item.id);
926
+ } else {
927
+ console.log('Added/Modified:', item.name);
928
+ }
929
+ });
930
+ ```
931
+
932
+
933
+ ### 13. Special Folders
934
+
935
+ ```typescript
936
+ // Access special folders
937
+ const documents = await client
938
+ .api('/me/drive/special/documents')
939
+ .get();
940
+
941
+ const photos = await client
942
+ .api('/me/drive/special/photos')
943
+ .get();
944
+
945
+ const cameraRoll = await client
946
+ .api('/me/drive/special/cameraroll')
947
+ .get();
948
+
949
+ const appRoot = await client
950
+ .api('/me/drive/special/approot')
951
+ .get();
952
+
953
+ // List children of special folder
954
+ const files = await client
955
+ .api('/me/drive/special/documents/children')
956
+ .get();
957
+ ```
958
+
959
+
960
+ ### 14. Working with SharePoint Document Libraries
961
+
962
+ ```typescript
963
+ // Access SharePoint site drive
964
+ const drive = await client
965
+ .api('/sites/{site-id}/drive')
966
+ .get();
967
+
968
+ // List document library contents
969
+ const items = await client
970
+ .api('/sites/{site-id}/drive/root/children')
971
+ .get();
972
+
973
+ // Upload to SharePoint
974
+ const file = await client
975
+ .api('/sites/{site-id}/drive/root:/folder/file.pdf:/content')
976
+ .put(fileContent);
977
+
978
+ // Get site by path
979
+ const site = await client
980
+ .api('/sites/{hostname}:/{server-relative-path}')
981
+ .get();
982
+
983
+ // Example: Get site by URL
984
+ const site = await client
985
+ .api('/sites/contoso.sharepoint.com:/sites/marketing')
986
+ .get();
987
+ ```
988
+
989
+
990
+ ### 15. Batch Requests
991
+
992
+ ```typescript
993
+ // Batch multiple requests
994
+ const batch = {
995
+ requests: [
996
+ {
997
+ id: '1',
998
+ method: 'GET',
999
+ url: '/me/drive/root/children'
1000
+ },
1001
+ {
1002
+ id: '2',
1003
+ method: 'GET',
1004
+ url: '/me/drive/special/documents'
1005
+ },
1006
+ {
1007
+ id: '3',
1008
+ method: 'GET',
1009
+ url: '/me/drive/root/search(q=\'report\')'
1010
+ }
1011
+ ]
1012
+ };
1013
+
1014
+ const batchResponse = await client
1015
+ .api('/$batch')
1016
+ .post(batch);
1017
+
1018
+ batchResponse.responses.forEach(response => {
1019
+ console.log(`Request ${response.id}:`, response.status);
1020
+ console.log('Body:', response.body);
1021
+ });
1022
+
1023
+ // Batch with dependencies
1024
+ const batchWithDeps = {
1025
+ requests: [
1026
+ {
1027
+ id: '1',
1028
+ method: 'POST',
1029
+ url: '/me/drive/root/children',
1030
+ body: {
1031
+ name: 'NewFolder',
1032
+ folder: {}
1033
+ },
1034
+ headers: {
1035
+ 'Content-Type': 'application/json'
1036
+ }
1037
+ },
1038
+ {
1039
+ id: '2',
1040
+ dependsOn: ['1'],
1041
+ method: 'PUT',
1042
+ url: '/me/drive/items/{$1.id}:/file.txt:/content',
1043
+ body: 'File content',
1044
+ headers: {
1045
+ 'Content-Type': 'text/plain'
1046
+ }
1047
+ }
1048
+ ]
1049
+ };
1050
+ ```
1051
+
1052
+
1053
+ ## Error Handling
1054
+
1055
+ ```typescript
1056
+ import { GraphError } from '@microsoft/microsoft-graph-client';
1057
+
1058
+ try {
1059
+ const item = await client
1060
+ .api('/me/drive/items/{item-id}')
1061
+ .get();
1062
+ } catch (error) {
1063
+ if (error instanceof GraphError) {
1064
+ console.error('Graph error code:', error.code);
1065
+ console.error('Status code:', error.statusCode);
1066
+ console.error('Message:', error.message);
1067
+
1068
+ // Handle specific errors
1069
+ if (error.statusCode === 404) {
1070
+ console.error('Item not found');
1071
+ } else if (error.statusCode === 401) {
1072
+ console.error('Unauthorized - check authentication');
1073
+ } else if (error.statusCode === 403) {
1074
+ console.error('Forbidden - check permissions');
1075
+ } else if (error.statusCode === 429) {
1076
+ console.error('Too many requests - rate limited');
1077
+ const retryAfter = error.headers?.get('Retry-After');
1078
+ console.log(`Retry after ${retryAfter} seconds`);
1079
+ }
1080
+ } else {
1081
+ console.error('Unexpected error:', error);
1082
+ }
1083
+ }
1084
+ ```
1085
+
1086
+
1087
+ ## Complete Working Examples
1088
+
1089
+
1090
+ ### Example 1: File Upload and Share Workflow
1091
+
1092
+ ```typescript
1093
+ import { Client } from '@microsoft/microsoft-graph-client';
1094
+ import { ClientSecretCredential } from '@azure/identity';
1095
+ import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
1096
+ import fs from 'fs';
1097
+ import 'isomorphic-fetch';
1098
+
1099
+ async function uploadAndShare() {
1100
+ // Initialize client
1101
+ const credential = new ClientSecretCredential(
1102
+ process.env.AZURE_TENANT_ID!,
1103
+ process.env.AZURE_CLIENT_ID!,
1104
+ process.env.AZURE_CLIENT_SECRET!
1105
+ );
1106
+
1107
+ const authProvider = new TokenCredentialAuthenticationProvider(credential, {
1108
+ scopes: ['https://graph.microsoft.com/.default']
1109
+ });
1110
+
1111
+ const client = Client.initWithMiddleware({ authProvider });
1112
+
1113
+ const userId = process.env.USER_ID!;
1114
+
1115
+ // Create folder
1116
+ const folder = await client
1117
+ .api(`/users/${userId}/drive/root/children`)
1118
+ .post({
1119
+ name: 'Shared Documents',
1120
+ folder: {},
1121
+ '@microsoft.graph.conflictBehavior': 'rename'
1122
+ });
1123
+
1124
+ console.log('Created folder:', folder.id);
1125
+
1126
+ // Upload file
1127
+ const fileContent = fs.readFileSync('./document.pdf');
1128
+ const uploadedFile = await client
1129
+ .api(`/users/${userId}/drive/items/${folder.id}:/document.pdf:/content`)
1130
+ .put(fileContent);
1131
+
1132
+ console.log('Uploaded file:', uploadedFile.id);
1133
+
1134
+ // Create share link
1135
+ const shareLink = await client
1136
+ .api(`/users/${userId}/drive/items/${uploadedFile.id}/createLink`)
1137
+ .post({
1138
+ type: 'view',
1139
+ scope: 'organization',
1140
+ expirationDateTime: '2025-12-31T23:59:59Z'
1141
+ });
1142
+
1143
+ console.log('Share URL:', shareLink.link.webUrl);
1144
+
1145
+ return shareLink.link.webUrl;
1146
+ }
1147
+ ```
1148
+
1149
+
1150
+ ### Example 2: Download All Files from Folder
1151
+
1152
+ ```typescript
1153
+ import { Client } from '@microsoft/microsoft-graph-client';
1154
+ import fs from 'fs';
1155
+ import path from 'path';
1156
+
1157
+ async function downloadFolder(client, folderId, localPath) {
1158
+ // Create local directory
1159
+ if (!fs.existsSync(localPath)) {
1160
+ fs.mkdirSync(localPath, { recursive: true });
1161
+ }
1162
+
1163
+ // Get folder contents
1164
+ const items = await client
1165
+ .api(`/me/drive/items/${folderId}/children`)
1166
+ .get();
1167
+
1168
+ for (const item of items.value) {
1169
+ if (item.folder) {
1170
+ // Recursively download subfolder
1171
+ const subPath = path.join(localPath, item.name);
1172
+ await downloadFolder(client, item.id, subPath);
1173
+ } else if (item.file) {
1174
+ // Download file
1175
+ console.log(`Downloading ${item.name}...`);
1176
+
1177
+ const stream = await client
1178
+ .api(`/me/drive/items/${item.id}/content`)
1179
+ .getStream();
1180
+
1181
+ const filePath = path.join(localPath, item.name);
1182
+ const writeStream = fs.createWriteStream(filePath);
1183
+ stream.pipe(writeStream);
1184
+
1185
+ await new Promise((resolve, reject) => {
1186
+ writeStream.on('finish', resolve);
1187
+ writeStream.on('error', reject);
1188
+ });
1189
+
1190
+ console.log(`Downloaded to ${filePath}`);
1191
+ }
1192
+ }
1193
+ }
1194
+ ```
1195
+
1196
+
1197
+ ### Example 3: Sync Local Folder to OneDrive
1198
+
1199
+ ```typescript
1200
+ import { Client } from '@microsoft/microsoft-graph-client';
1201
+ import fs from 'fs';
1202
+ import path from 'path';
1203
+ import { LargeFileUploadTask, StreamUpload } from '@microsoft/microsoft-graph-client';
1204
+
1205
+ async function syncFolderToOneDrive(client, localPath, oneDrivePath) {
1206
+ const files = fs.readdirSync(localPath);
1207
+
1208
+ for (const file of files) {
1209
+ const filePath = path.join(localPath, file);
1210
+ const stats = fs.statSync(filePath);
1211
+
1212
+ if (stats.isDirectory()) {
1213
+ // Create folder in OneDrive
1214
+ const folder = await client
1215
+ .api(`/me/drive/root:/${oneDrivePath}:/children`)
1216
+ .post({
1217
+ name: file,
1218
+ folder: {},
1219
+ '@microsoft.graph.conflictBehavior': 'rename'
1220
+ });
1221
+
1222
+ // Recursively sync subfolder
1223
+ await syncFolderToOneDrive(
1224
+ client,
1225
+ filePath,
1226
+ `${oneDrivePath}/${file}`
1227
+ );
1228
+ } else {
1229
+ // Upload file
1230
+ console.log(`Uploading ${file}...`);
1231
+
1232
+ if (stats.size < 4 * 1024 * 1024) {
1233
+ // Small file - simple upload
1234
+ const content = fs.readFileSync(filePath);
1235
+ await client
1236
+ .api(`/me/drive/root:/${oneDrivePath}/${file}:/content`)
1237
+ .put(content);
1238
+ } else {
1239
+ // Large file - resumable upload
1240
+ const uploadSession = await client
1241
+ .api(`/me/drive/root:/${oneDrivePath}/${file}:/createUploadSession`)
1242
+ .post({
1243
+ item: {
1244
+ '@microsoft.graph.conflictBehavior': 'replace'
1245
+ }
1246
+ });
1247
+
1248
+ const fileObject = new StreamUpload(
1249
+ fs.createReadStream(filePath),
1250
+ file,
1251
+ stats.size
1252
+ );
1253
+
1254
+ const task = new LargeFileUploadTask(client, fileObject, uploadSession);
1255
+ await task.upload();
1256
+ }
1257
+
1258
+ console.log(`Uploaded ${file}`);
1259
+ }
1260
+ }
1261
+ }
1262
+ ```
1263
+
1264
+
1265
+ ### Example 4: Search and Download Files by Type
1266
+
1267
+ ```typescript
1268
+ async function downloadFilesByType(client, fileExtension, downloadPath) {
1269
+ if (!fs.existsSync(downloadPath)) {
1270
+ fs.mkdirSync(downloadPath, { recursive: true });
1271
+ }
1272
+
1273
+ // Search for files
1274
+ const results = await client
1275
+ .api(`/me/drive/root/search(q='.${fileExtension}')`)
1276
+ .select('id,name,size,@microsoft.graph.downloadUrl')
1277
+ .get();
1278
+
1279
+ console.log(`Found ${results.value.length} ${fileExtension} files`);
1280
+
1281
+ for (const file of results.value) {
1282
+ if (file.file) {
1283
+ console.log(`Downloading ${file.name}...`);
1284
+
1285
+ const stream = await client
1286
+ .api(`/me/drive/items/${file.id}/content`)
1287
+ .getStream();
1288
+
1289
+ const filePath = path.join(downloadPath, file.name);
1290
+ const writeStream = fs.createWriteStream(filePath);
1291
+ stream.pipe(writeStream);
1292
+
1293
+ await new Promise((resolve, reject) => {
1294
+ writeStream.on('finish', resolve);
1295
+ writeStream.on('error', reject);
1296
+ });
1297
+ }
1298
+ }
1299
+
1300
+ console.log('Download complete');
1301
+ }
1302
+
1303
+ // Usage
1304
+ await downloadFilesByType(client, 'pdf', './downloads/pdfs');
1305
+ ```
1306
+
1307
+
1308
+ ## Rate Limiting and Throttling
1309
+
1310
+ Microsoft Graph implements throttling to maintain service health:
1311
+
1312
+ ```typescript
1313
+ async function makeRequestWithRetry(client, apiPath, maxRetries = 3) {
1314
+ let retries = 0;
1315
+
1316
+ while (retries < maxRetries) {
1317
+ try {
1318
+ return await client.api(apiPath).get();
1319
+ } catch (error) {
1320
+ if (error.statusCode === 429) {
1321
+ const retryAfter = parseInt(error.headers?.get('Retry-After') || '5');
1322
+ console.log(`Rate limited. Waiting ${retryAfter} seconds...`);
1323
+
1324
+ await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
1325
+ retries++;
1326
+ } else {
1327
+ throw error;
1328
+ }
1329
+ }
1330
+ }
1331
+
1332
+ throw new Error('Max retries exceeded');
1333
+ }
1334
+ ```
1335
+
1336
+
1337
+ ## Advanced Configuration
1338
+
1339
+ ### Custom Middleware
1340
+
1341
+ ```typescript
1342
+ import { Middleware } from '@microsoft/microsoft-graph-client';
1343
+
1344
+ // Custom logging middleware
1345
+ class LoggingMiddleware implements Middleware {
1346
+ async execute(context) {
1347
+ console.log(`Request: ${context.request}`);
1348
+
1349
+ await this.nextMiddleware.execute(context);
1350
+
1351
+ console.log(`Response: ${context.response.status}`);
1352
+ }
1353
+ }
1354
+
1355
+ // Register middleware
1356
+ const client = Client.initWithMiddleware({
1357
+ authProvider,
1358
+ middleware: new LoggingMiddleware()
1359
+ });
1360
+ ```
1361
+
1362
+ ### Custom Headers
1363
+
1364
+ ```typescript
1365
+ // Add custom headers to requests
1366
+ const result = await client
1367
+ .api('/me/drive/root/children')
1368
+ .header('Prefer', 'HonorNonIndexedQueriesWarningMayFailRandomly')
1369
+ .header('ConsistencyLevel', 'eventual')
1370
+ .get();
1371
+ ```
1372
+
1373
+
1374
+ ## Working with Different Drive Types
1375
+
1376
+ ```typescript
1377
+ // Personal OneDrive
1378
+ const personalDrive = await client.api('/me/drive').get();
1379
+
1380
+ // User's OneDrive (requires admin permissions)
1381
+ const userDrive = await client.api('/users/{user-id}/drive').get();
1382
+
1383
+ // Group drive
1384
+ const groupDrive = await client.api('/groups/{group-id}/drive').get();
1385
+
1386
+ // SharePoint site drive
1387
+ const siteDrive = await client.api('/sites/{site-id}/drive').get();
1388
+
1389
+ // Specific drive by ID
1390
+ const drive = await client.api('/drives/{drive-id}').get();
1391
+ ```
1392
+
1393
+
1394
+ ## Webhooks and Change Notifications
1395
+
1396
+ ```typescript
1397
+ // Subscribe to changes in a drive
1398
+ const subscription = await client
1399
+ .api('/subscriptions')
1400
+ .post({
1401
+ changeType: 'updated',
1402
+ notificationUrl: 'https://your-webhook-endpoint.com/notifications',
1403
+ resource: '/me/drive/root',
1404
+ expirationDateTime: '2025-12-31T18:23:45.9356913Z',
1405
+ clientState: 'secretClientState'
1406
+ });
1407
+
1408
+ console.log('Subscription ID:', subscription.id);
1409
+
1410
+ // Renew subscription
1411
+ const renewed = await client
1412
+ .api(`/subscriptions/${subscription.id}`)
1413
+ .patch({
1414
+ expirationDateTime: '2026-01-31T18:23:45.9356913Z'
1415
+ });
1416
+
1417
+ // Delete subscription
1418
+ await client
1419
+ .api(`/subscriptions/${subscription.id}`)
1420
+ .delete();
1421
+ ```