@pipedream/sharepoint 0.8.0 → 0.8.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.
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-create-folder",
5
5
  name: "Create Folder",
6
6
  description: "Create a new folder in SharePoint. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_post_children?view=odsp-graph-online)",
7
- version: "0.0.5",
7
+ version: "0.0.6",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-create-item",
5
5
  name: "Create Item",
6
6
  description: "Create a new item in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/listitem-create?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.11",
7
+ version: "0.0.12",
8
8
  annotations: {
9
9
  destructiveHint: false,
10
10
  openWorldHint: true,
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-create-link",
6
6
  name: "Create Link",
7
7
  description: "Create a sharing link for a DriveItem. [See the documentation](https://docs.microsoft.com/en-us/graph/api/driveitem-createlink?view=graph-rest-1.0&tabs=http)",
8
- version: "0.0.7",
8
+ version: "0.0.8",
9
9
  type: "action",
10
10
  annotations: {
11
11
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-create-list",
5
5
  name: "Create List",
6
6
  description: "Create a new list in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/list-create?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.11",
7
+ version: "0.0.12",
8
8
  annotations: {
9
9
  destructiveHint: false,
10
10
  openWorldHint: true,
@@ -8,7 +8,7 @@ export default {
8
8
  key: "sharepoint-download-file",
9
9
  name: "Download File",
10
10
  description: "Download a Microsoft Sharepoint file to the /tmp directory. [See the documentation](https://learn.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest-1.0&tabs=http)",
11
- version: "0.0.12",
11
+ version: "0.0.13",
12
12
  annotations: {
13
13
  destructiveHint: false,
14
14
  openWorldHint: true,
@@ -116,31 +116,25 @@ export default {
116
116
  this.validateConversionFormat(originalExtension);
117
117
  }
118
118
 
119
- let response;
120
- let args = {
121
- $,
119
+ const response = await this.sharepoint.getFile({
122
120
  driveId: this.driveId,
123
121
  fileId: this.fileId,
124
122
  params: {
125
123
  format: this.convertToFormat,
126
124
  },
127
- };
128
- try {
129
- response = await this.sharepoint.getFile({
130
- ...args,
131
- responseType: "arraybuffer",
132
- });
133
- } catch {
134
- // throw error without buffer encoding
135
- await this.sharepoint.getFile(args);
136
- }
125
+ });
137
126
 
138
- const rawcontent = response.toString("base64");
139
- const buffer = Buffer.from(rawcontent, "base64");
140
127
  // Since the filepath is not returned as one of the standard keys (filePath
141
128
  // or path), save the file to STASH_DIR, if defined, so it is synced at the
142
129
  // end of execution.
143
130
  const downloadedFilepath = `${process.env.STASH_DIR || "/tmp"}/${filename}`;
131
+
132
+ const chunks = [];
133
+ for await (const chunk of response) {
134
+ chunks.push(chunk);
135
+ }
136
+
137
+ const buffer = Buffer.concat(chunks);
144
138
  fs.writeFileSync(downloadedFilepath, buffer);
145
139
 
146
140
  const data = {
@@ -6,7 +6,7 @@ export default {
6
6
  key: "sharepoint-download-files",
7
7
  name: "Download Files",
8
8
  description: "Browse and select files from SharePoint and get their metadata along with pre-authenticated download URLs (valid ~1 hour). [See the documentation](https://learn.microsoft.com/en-us/graph/api/driveitem-get)",
9
- version: "0.0.1",
9
+ version: "0.0.2",
10
10
  type: "action",
11
11
  annotations: {
12
12
  destructiveHint: false,
@@ -6,7 +6,7 @@ export default {
6
6
  key: "sharepoint-find-file-by-name",
7
7
  name: "Find File by Name",
8
8
  description: "Search for a file or folder by name. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_search)",
9
- version: "0.1.4",
9
+ version: "0.1.5",
10
10
  type: "action",
11
11
  annotations: {
12
12
  destructiveHint: false,
@@ -5,7 +5,7 @@ export default {
5
5
  name: "Find Files in List with Metadata",
6
6
  description:
7
7
  "Search and filter items in a SharePoint list based on metadata and custom columns. [See docs here](https://learn.microsoft.com/en-us/graph/api/listitem-list)",
8
- version: "0.0.2",
8
+ version: "0.0.3",
9
9
  type: "action",
10
10
  annotations: {
11
11
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-get-excel-table",
5
5
  name: "Get Excel Table",
6
6
  description: "Retrieve a table from an Excel spreadsheet stored in Sharepoint [See the documentation](https://learn.microsoft.com/en-us/graph/api/table-range?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.6",
7
+ version: "0.0.7",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-get-file-by-id",
5
5
  name: "Get File by ID",
6
6
  description: "Retrieves a file by ID. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get)",
7
- version: "0.0.5",
7
+ version: "0.0.6",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-get-site",
5
5
  name: "Get Site",
6
6
  description: "Get a site in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/site-get?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.3",
7
+ version: "0.0.4",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-list-files-in-folder",
5
5
  name: "List Files in Folder",
6
6
  description: "Retrieves a list of the files and/or folders directly within a folder. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_list_children)",
7
- version: "0.0.5",
7
+ version: "0.0.6",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-list-sites",
5
5
  name: "List Sites",
6
6
  description: "List all sites in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/site-list?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.3",
7
+ version: "0.0.4",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -8,7 +8,7 @@ export default {
8
8
  key: "sharepoint-retrieve-file-metadata",
9
9
  name: "Retrieve File Metadata",
10
10
  description: "Browse and select files from SharePoint to retrieve their metadata (name, size, dates, etc.) without download URLs. [See the documentation](https://learn.microsoft.com/en-us/graph/api/driveitem-get)",
11
- version: "0.0.1",
11
+ version: "0.0.2",
12
12
  type: "action",
13
13
  annotations: {
14
14
  destructiveHint: false,
@@ -6,7 +6,7 @@ export default {
6
6
  name: "Search and Filter Files",
7
7
  description:
8
8
  "Search and filter SharePoint files based on metadata and custom columns. This action allows you to query files using SharePoint's custom properties, managed metadata, and other column values. [See the documentation](https://learn.microsoft.com/en-us/graph/api/listitem-list)",
9
- version: "0.0.2",
9
+ version: "0.0.3",
10
10
  type: "action",
11
11
  annotations: {
12
12
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-search-files",
5
5
  name: "Search Files",
6
6
  description: "Search for files in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/search-query?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.3",
7
+ version: "0.0.4",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "sharepoint-search-sites",
5
5
  name: "Search Sites",
6
6
  description: "Search for sites in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/site-search?view=graph-rest-1.0&tabs=http)",
7
- version: "0.0.3",
7
+ version: "0.0.4",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-update-item",
6
6
  name: "Update Item",
7
7
  description: "Updates an existing item in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/listitem-update?view=graph-rest-1.0&tabs=http)",
8
- version: "0.0.11",
8
+ version: "0.0.12",
9
9
  annotations: {
10
10
  destructiveHint: true,
11
11
  openWorldHint: true,
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-upload-file",
6
6
  name: "Upload File",
7
7
  description: "Upload a file to OneDrive. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_put_content?view=odsp-graph-online)",
8
- version: "0.0.5",
8
+ version: "0.0.6",
9
9
  type: "action",
10
10
  annotations: {
11
11
  destructiveHint: false,
@@ -68,13 +68,18 @@ export default {
68
68
  } = await getFileStreamAndMetadata(filePath);
69
69
  const name = filename || metadata.name;
70
70
 
71
+ const chunks = [];
72
+ for await (const chunk of stream) {
73
+ chunks.push(chunk);
74
+ }
75
+ const buffer = Buffer.concat(chunks);
76
+
71
77
  const response = await this.sharepoint.uploadFile({
72
78
  siteId,
73
79
  driveId,
74
80
  uploadFolderId,
75
81
  name,
76
- data: stream,
77
- $,
82
+ data: buffer,
78
83
  });
79
84
 
80
85
  if (response?.id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/sharepoint",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Pipedream Microsoft Sharepoint Online Components",
5
5
  "main": "sharepoint.app.mjs",
6
6
  "keywords": [
@@ -13,9 +13,9 @@
13
13
  "access": "public"
14
14
  },
15
15
  "dependencies": {
16
- "@pipedream/platform": "^3.1.1",
17
16
  "@microsoft/microsoft-graph-client": "^3.0.7",
18
- "async-retry": "^1.3.3",
19
- "isomorphic-fetch": "^3.0.0"
17
+ "@pipedream/platform": "^3.1.1",
18
+ "isomorphic-fetch": "^3.0.0",
19
+ "lodash.pickby": "^4.6.0"
20
20
  }
21
21
  }
@@ -1,8 +1,7 @@
1
- import { axios } from "@pipedream/platform";
2
1
  import { Client } from "@microsoft/microsoft-graph-client";
3
- import retry from "async-retry";
4
2
  import "isomorphic-fetch";
5
3
  import { WEBHOOK_SUBSCRIPTION_EXPIRATION_TIME_MILLISECONDS } from "./common/constants.mjs";
4
+ import pickBy from "lodash.pickby";
6
5
 
7
6
  export default {
8
7
  type: "app",
@@ -360,7 +359,7 @@ export default {
360
359
  driveId: resolvedDriveId,
361
360
  });
362
361
  return response.value?.map(({
363
- id, name, folder, size, lastModifiedDateTime,
362
+ id, name, folder, size, lastModifiedDateTime, webUrl, description,
364
363
  }) => ({
365
364
  value: JSON.stringify({
366
365
  id,
@@ -369,6 +368,8 @@ export default {
369
368
  size,
370
369
  childCount: folder?.childCount,
371
370
  lastModifiedDateTime,
371
+ webUrl,
372
+ description,
372
373
  }),
373
374
  label: folder
374
375
  ? `📁 ${name}`
@@ -378,7 +379,6 @@ export default {
378
379
  },
379
380
  },
380
381
  methods: {
381
- _graphClient: null,
382
382
  /**
383
383
  * Resolves a potentially wrapped labeled value to its actual value.
384
384
  * Pipedream props with withLabel: true wrap values in a special format.
@@ -431,399 +431,187 @@ export default {
431
431
  * and includes built-in pagination and type safety.
432
432
  */
433
433
  client() {
434
- if (!this._graphClient) {
435
- this._graphClient = Client.initWithMiddleware({
436
- authProvider: {
437
- getAccessToken: () => Promise.resolve(this._getAccessToken()),
438
- },
439
- });
440
- }
441
- return this._graphClient;
442
- },
443
- /**
444
- * Makes a request to Microsoft Graph API with automatic retry logic.
445
- * Retries on transient errors (5xx, 429) but not on auth/client
446
- * errors (4xx).
447
- *
448
- * @param {Object} options - Request options
449
- * @param {string} options.path - API path (e.g., "/sites/{siteId}")
450
- * @param {string} [options.method="GET"] - HTTP method
451
- * @param {*} [options.content] - Request body for POST/PATCH
452
- * @param {number} [options.retries=3] - Number of retry attempts
453
- * @returns {Promise<*>} API response
454
- */
455
- async graphRequest({
456
- path, method = "GET", content, retries = 3,
457
- }) {
458
- return retry(
459
- async (bail) => {
460
- try {
461
- const api = this.client().api(path);
462
-
463
- switch (method.toUpperCase()) {
464
- case "GET":
465
- return await api.get();
466
- case "POST":
467
- return await api.post(content);
468
- case "PATCH":
469
- return await api.patch(content);
470
- case "DELETE":
471
- return await api.delete();
472
- default:
473
- throw new Error(`Unsupported HTTP method: ${method}`);
474
- }
475
- } catch (error) {
476
- // Don't retry on auth errors or client errors (4xx except 429)
477
- const status = error.statusCode || error.response?.status;
478
- if ([
479
- 400,
480
- 401,
481
- 403,
482
- 404,
483
- ].includes(status)) {
484
- bail(error); // Throw immediately, don't retry
485
- return;
486
- }
487
- throw error; // Retry on other errors
488
- }
489
- },
490
- {
491
- retries,
492
- minTimeout: 1000,
493
- maxTimeout: 10000,
494
- onRetry: (error, attempt) => {
495
- console.log(`Retry attempt ${attempt} after error: ${error.message}`);
496
- },
434
+ return Client.initWithMiddleware({
435
+ authProvider: {
436
+ getAccessToken: () => Promise.resolve(this._getAccessToken()),
497
437
  },
498
- );
499
- },
500
- _baseUrl() {
501
- return "https://graph.microsoft.com/v1.0";
502
- },
503
- _headers(headers) {
504
- return {
505
- Authorization: `Bearer ${this._getAccessToken()}`,
506
- ...headers,
507
- };
508
- },
509
- _makeRequest({
510
- $ = this,
511
- path,
512
- url,
513
- headers,
514
- ...args
515
- }) {
516
- return axios($, {
517
- url: url || `${this._baseUrl()}${path}`,
518
- headers: this._headers(headers),
519
- ...args,
520
- });
521
- },
522
- /**
523
- * Makes a request to SharePoint REST API (not Microsoft Graph).
524
- * Use this for SharePoint-specific features not available in Graph API,
525
- * such as native SharePoint site groups.
526
- *
527
- * @param {Object} options - Request options
528
- * @param {string} options.siteWebUrl - Full site URL (e.g., "https://tenant.sharepoint.com/sites/MySite")
529
- * @param {string} options.path - REST API path (e.g., "/web/sitegroups")
530
- * @param {Object} [options.headers] - Additional headers
531
- * @returns {Promise<Object>} API response
532
- * @example
533
- * // Get SharePoint site groups
534
- * await this._makeSharePointRestRequest({
535
- * siteWebUrl: "https://contoso.sharepoint.com/sites/TeamSite",
536
- * path: "/web/sitegroups"
537
- * })
538
- */
539
- _makeSharePointRestRequest({
540
- $ = this,
541
- siteWebUrl,
542
- path,
543
- headers,
544
- ...args
545
- }) {
546
- // SharePoint REST API uses the site's webUrl as base
547
- // e.g., https://tenant.sharepoint.com/sites/MySite/_api/web/sitegroups
548
- const baseUrl = siteWebUrl.replace(/\/$/, ""); // Remove trailing slash if present
549
- return axios($, {
550
- url: `${baseUrl}/_api${path}`,
551
- headers: this._headers({
552
- Accept: "application/json;odata=verbose",
553
- ...headers,
554
- }),
555
- ...args,
556
438
  });
557
439
  },
558
440
  getSite({
559
- siteId, ...args
560
- }) {
561
- return this._makeRequest({
562
- path: `/sites/${siteId}`,
563
- ...args,
564
- });
565
- },
566
- /**
567
- * Lists SharePoint-native site groups using the SharePoint REST API.
568
- * These are different from Microsoft 365 Groups and can only be accessed via REST API.
569
- *
570
- * @param {Object} options - Request options
571
- * @param {string} options.siteWebUrl - Full site URL
572
- * @returns {Promise<Object>} Response with groups in d.results array
573
- * @example
574
- * const groups = await this.listSharePointSiteGroups({
575
- * siteWebUrl: "https://contoso.sharepoint.com/sites/TeamSite"
576
- * });
577
- * // Returns: { d: { results: [{ Id: 5, Title: "Team Site Members" }, ...] } }
578
- */
579
- listSharePointSiteGroups({
580
- siteWebUrl, ...args
581
- }) {
582
- return this._makeSharePointRestRequest({
583
- siteWebUrl,
584
- path: "/web/sitegroups",
585
- ...args,
586
- });
587
- },
588
- /**
589
- * Gets members of a SharePoint-native site group using the SharePoint REST API.
590
- * Returns user details including email, display name, and login name.
591
- *
592
- * @param {Object} options - Request options
593
- * @param {string} options.siteWebUrl - Full site URL
594
- * @param {number} options.groupId - SharePoint group ID
595
- * @returns {Promise<Object>} Response with users in d.results array
596
- * @example
597
- * const members = await this.getSharePointSiteGroupMembers({
598
- * siteWebUrl: "https://contoso.sharepoint.com/sites/TeamSite",
599
- * groupId: 5
600
- * });
601
- * // Returns: { d: { results: [{ Email: "user@contoso.com", Title: "John Doe" }, ...] } }
602
- */
603
- getSharePointSiteGroupMembers({
604
- siteWebUrl, groupId, ...args
605
- }) {
606
- return this._makeSharePointRestRequest({
607
- siteWebUrl,
608
- path: `/web/sitegroups/getbyid(${groupId})/users`,
609
- ...args,
610
- });
441
+ siteId, params = {},
442
+ } = {}) {
443
+ return this.client().api(`/sites/${siteId}`)
444
+ .query(pickBy(params))
445
+ .get();
611
446
  },
612
- listSites(args = {}) {
613
- return this._makeRequest({
614
- path: "/me/followedSites",
615
- ...args,
616
- });
447
+ listSites({ params = {} } = {}) {
448
+ return this.client().api("/me/followedSites")
449
+ .query(pickBy(params))
450
+ .get();
617
451
  },
618
- listAllSites({
619
- params = {}, ...args
620
- } = {}) {
452
+ listAllSites({ params = {} } = {}) {
621
453
  if (!params.search) {
622
454
  params.search = "*";
623
455
  }
624
- return this._makeRequest({
625
- path: "/sites",
626
- params,
627
- ...args,
628
- });
456
+ return this.client().api("/sites")
457
+ .query(pickBy(params))
458
+ .get();
629
459
  },
630
460
  listLists({
631
- siteId, ...args
632
- }) {
633
- return this._makeRequest({
634
- path: `/sites/${siteId}/lists`,
635
- ...args,
636
- });
461
+ siteId, params = {},
462
+ } = {}) {
463
+ return this.client().api(`/sites/${siteId}/lists`)
464
+ .query(pickBy(params))
465
+ .get();
637
466
  },
638
467
  listColumns({
639
- siteId, listId, ...args
640
- }) {
641
- return this._makeRequest({
642
- path: `/sites/${siteId}/lists/${listId}/columns`,
643
- ...args,
644
- });
468
+ siteId, listId, params = {},
469
+ } = {}) {
470
+ return this.client().api(`/sites/${siteId}/lists/${listId}/columns`)
471
+ .query(pickBy(params))
472
+ .get();
645
473
  },
646
474
  listItems({
647
- siteId, listId, ...args
648
- }) {
649
- return this._makeRequest({
650
- path: `/sites/${siteId}/lists/${listId}/items`,
651
- ...args,
652
- });
475
+ siteId, listId, params = {},
476
+ } = {}) {
477
+ return this.client().api(`/sites/${siteId}/lists/${listId}/items`)
478
+ .query(pickBy(params))
479
+ .get();
653
480
  },
654
481
  getListItem({
655
- siteId, listId, itemId, ...args
656
- }) {
657
- return this._makeRequest({
658
- path: `/sites/${siteId}/lists/${listId}/items/${itemId}`,
659
- ...args,
660
- });
482
+ siteId, listId, itemId, params = {},
483
+ } = {}) {
484
+ return this.client().api(`/sites/${siteId}/lists/${listId}/items/${itemId}`)
485
+ .query(pickBy(params))
486
+ .get();
661
487
  },
662
488
  listSiteDrives({
663
- siteId, ...args
664
- }) {
665
- return this._makeRequest({
666
- path: `/sites/${siteId}/drives`,
667
- ...args,
668
- });
489
+ siteId, params = {},
490
+ } = {}) {
491
+ return this.client().api(`/sites/${siteId}/drives`)
492
+ .query(pickBy(params))
493
+ .get();
669
494
  },
670
495
  listDriveItems({
671
- siteId, driveId, ...args
672
- }) {
673
- return this._makeRequest({
674
- path: `/sites/${siteId}/drives/${driveId}/root/children`,
675
- ...args,
676
- });
496
+ siteId, driveId, params = {},
497
+ } = {}) {
498
+ return this.client().api(`/sites/${siteId}/drives/${driveId}/root/children`)
499
+ .query(pickBy(params))
500
+ .get();
677
501
  },
678
502
  listDriveItemsInFolder({
679
- driveId, folderId, ...args
680
- }) {
681
- return this._makeRequest({
682
- path: `/drives/${driveId}/items/${folderId}/children`,
683
- ...args,
684
- });
503
+ driveId, folderId, params = {},
504
+ } = {}) {
505
+ return this.client().api(`/drives/${driveId}/items/${folderId}/children`)
506
+ .query(pickBy(params))
507
+ .get();
685
508
  },
686
509
  createDriveItem({
687
- siteId, driveId, ...args
688
- }) {
689
- return this._makeRequest({
690
- path: `/sites/${siteId}/drives/${driveId}/root/children`,
691
- method: "POST",
692
- ...args,
693
- });
510
+ siteId, driveId, data = {},
511
+ } = {}) {
512
+ return this.client().api(`/sites/${siteId}/drives/${driveId}/root/children`)
513
+ .post(data);
694
514
  },
695
515
  createDriveItemInFolder({
696
- siteId, folderId, ...args
697
- }) {
698
- return this._makeRequest({
699
- path: `/sites/${siteId}/drive/items/${folderId}/children`,
700
- method: "POST",
701
- ...args,
702
- });
516
+ siteId, folderId, data = {},
517
+ } = {}) {
518
+ return this.client().api(`/sites/${siteId}/drive/items/${folderId}/children`)
519
+ .post(data);
703
520
  },
704
521
  createLink({
705
- siteId, fileId, ...args
706
- }) {
707
- return this._makeRequest({
708
- path: `/sites/${siteId}/drive/items/${fileId}/createLink`,
709
- method: "POST",
710
- ...args,
711
- });
522
+ siteId, fileId, data = {},
523
+ } = {}) {
524
+ return this.client().api(`/sites/${siteId}/drive/items/${fileId}/createLink`)
525
+ .post(data);
712
526
  },
713
527
  listExcelTables({
714
- siteId, itemId, ...args
715
- }) {
716
- return this._makeRequest({
717
- path: `/sites/${siteId}/drive/items/${itemId}/workbook/tables`,
718
- ...args,
719
- });
528
+ siteId, itemId, params = {},
529
+ } = {}) {
530
+ return this.client().api(`/sites/${siteId}/drive/items/${itemId}/workbook/tables`)
531
+ .query(pickBy(params))
532
+ .get();
720
533
  },
721
534
  getExcelTable({
722
- siteId, itemId, tableName, ...args
723
- }) {
724
- return this._makeRequest({
725
- path: `/sites/${siteId}/drive/items/${itemId}/workbook/tables/${tableName}/range`,
726
- ...args,
727
- });
535
+ siteId, itemId, tableName, params = {},
536
+ } = {}) {
537
+ return this.client().api(`/sites/${siteId}/drive/items/${itemId}/workbook/tables/${tableName}/range`)
538
+ .query(pickBy(params))
539
+ .get();
728
540
  },
729
541
  uploadFile({
730
- siteId, driveId, uploadFolderId, name, ...args
731
- }) {
732
- return this._makeRequest({
733
- path: uploadFolderId
734
- ? `/sites/${siteId}/drives/${driveId}/items/${uploadFolderId}:/${encodeURI(name)}:/content`
735
- : `/sites/${siteId}/drives/${driveId}/root:/${encodeURI(name)}:/content`,
736
- method: "PUT",
737
- headers: {
738
- "Authorization": `Bearer ${this._getAccessToken()}`,
739
- },
740
- ...args,
741
- });
542
+ siteId, driveId, uploadFolderId, name, data,
543
+ } = {}) {
544
+ const path = uploadFolderId
545
+ ? `/sites/${siteId}/drives/${driveId}/items/${uploadFolderId}:/${encodeURI(name)}:/content`
546
+ : `/sites/${siteId}/drives/${driveId}/root:/${encodeURI(name)}:/content`;
547
+ return this.client().api(path)
548
+ .put(data);
742
549
  },
743
550
  getDriveItem({
744
- siteId, driveId, fileId, ...args
745
- }) {
746
- // Use driveId if provided, otherwise fall back to site's default drive
551
+ siteId, driveId, fileId, params = {},
552
+ } = {}) {
747
553
  const path = driveId
748
554
  ? `/drives/${driveId}/items/${fileId}`
749
555
  : `/sites/${siteId}/drive/items/${fileId}`;
750
- return this._makeRequest({
751
- path,
752
- ...args,
753
- });
556
+ return this.client().api(path)
557
+ .query(pickBy(params))
558
+ .get();
754
559
  },
755
560
  listDriveItemPermissions({
756
- driveId, itemId, ...args
757
- }) {
758
- return this._makeRequest({
759
- path: `/drives/${driveId}/items/${itemId}/permissions`,
760
- ...args,
761
- });
561
+ driveId, itemId, params = {},
562
+ } = {}) {
563
+ return this.client().api(`/drives/${driveId}/items/${itemId}/permissions`)
564
+ .query(pickBy(params))
565
+ .get();
762
566
  },
763
567
  searchDriveItems({
764
- siteId, query, ...args
765
- }) {
766
- return this._makeRequest({
767
- path: `/sites/${siteId}/drive/root/search(q='${encodeURIComponent(
768
- query,
769
- )}')`,
770
- ...args,
771
- });
568
+ siteId, query, params = {},
569
+ } = {}) {
570
+ return this.client().api(`/sites/${siteId}/drive/root/search(q='${encodeURIComponent(query)}')`)
571
+ .query(pickBy(params))
572
+ .get();
772
573
  },
773
574
  getFile({
774
- driveId, fileId, ...args
775
- }) {
776
- return this._makeRequest({
777
- path: `/drives/${driveId}/items/${fileId}/content`,
778
- ...args,
779
- });
575
+ driveId, fileId, params = {},
576
+ } = {}) {
577
+ return this.client().api(`/drives/${driveId}/items/${fileId}/content`)
578
+ .query(pickBy(params))
579
+ .get();
780
580
  },
781
581
  createList({
782
- siteId, ...args
783
- }) {
784
- return this._makeRequest({
785
- path: `/sites/${siteId}/lists`,
786
- method: "POST",
787
- ...args,
788
- });
582
+ siteId, data = {},
583
+ } = {}) {
584
+ return this.client().api(`/sites/${siteId}/lists`)
585
+ .post(data);
789
586
  },
790
587
  createItem({
791
- siteId, listId, ...args
792
- }) {
793
- return this._makeRequest({
794
- path: `/sites/${siteId}/lists/${listId}/items`,
795
- method: "POST",
796
- ...args,
797
- });
588
+ siteId, listId, data = {},
589
+ } = {}) {
590
+ return this.client().api(`/sites/${siteId}/lists/${listId}/items`)
591
+ .post(data);
798
592
  },
799
593
  updateItem({
800
- siteId, listId, itemId, ...args
801
- }) {
802
- return this._makeRequest({
803
- path: `/sites/${siteId}/lists/${listId}/items/${itemId}/fields`,
804
- method: "PATCH",
805
- ...args,
806
- });
594
+ siteId, listId, itemId, data = {},
595
+ } = {}) {
596
+ return this.client().api(`/sites/${siteId}/lists/${listId}/items/${itemId}/fields`)
597
+ .patch(data);
807
598
  },
808
- listGroups(args = {}) {
809
- return this._makeRequest({
810
- path: "/groups",
811
- ...args,
812
- });
599
+ listGroups({ params = {} } = {}) {
600
+ return this.client().api("/groups")
601
+ .query(pickBy(params))
602
+ .get();
813
603
  },
814
- listUsers(args = {}) {
815
- return this._makeRequest({
816
- path: "/users",
817
- ...args,
818
- });
604
+ listUsers({ params = {} } = {}) {
605
+ return this.client().api("/users")
606
+ .query(pickBy(params))
607
+ .get();
819
608
  },
820
609
  listGroupMembers({
821
- groupId, ...args
822
- }) {
823
- return this._makeRequest({
824
- path: `/groups/${groupId}/members`,
825
- ...args,
826
- });
610
+ groupId, params = {},
611
+ } = {}) {
612
+ return this.client().api(`/groups/${groupId}/members`)
613
+ .query(pickBy(params))
614
+ .get();
827
615
  },
828
616
  /**
829
617
  * Get delta changes for a drive using Microsoft Graph delta query.
@@ -847,26 +635,19 @@ export default {
847
635
  * });
848
636
  */
849
637
  getDriveDelta({
850
- driveId, deltaLink, ...args
851
- }) {
852
- // If we have a deltaLink/nextLink, use it as full URL; otherwise build path
638
+ driveId, deltaLink,
639
+ } = {}) {
853
640
  if (deltaLink) {
854
- return this._makeRequest({
855
- url: deltaLink,
856
- ...args,
857
- });
641
+ const path = deltaLink.replace(/^https:\/\/graph\.microsoft\.com\/v[^/]+/, "");
642
+ return this.client().api(path)
643
+ .get();
858
644
  }
859
- return this._makeRequest({
860
- path: `/drives/${driveId}/root/delta`,
861
- ...args,
862
- });
645
+ return this.client().api(`/drives/${driveId}/root/delta`)
646
+ .get();
863
647
  },
864
- searchQuery(args = {}) {
865
- return this._makeRequest({
866
- method: "POST",
867
- path: "/search/query",
868
- ...args,
869
- });
648
+ searchQuery({ data = {} } = {}) {
649
+ return this.client().api("/search/query")
650
+ .post(data);
870
651
  },
871
652
  async *paginate({
872
653
  fn, args,
@@ -913,24 +694,19 @@ export default {
913
694
  * });
914
695
  */
915
696
  createSubscription({
916
- resource, notificationUrl, changeType = "updated", clientState, ...args
917
- }) {
697
+ resource, notificationUrl, changeType = "updated", clientState,
698
+ } = {}) {
918
699
  const expirationDateTime = new Date(
919
700
  Date.now() + WEBHOOK_SUBSCRIPTION_EXPIRATION_TIME_MILLISECONDS,
920
701
  ).toISOString();
921
-
922
- return this._makeRequest({
923
- method: "POST",
924
- path: "/subscriptions",
925
- data: {
702
+ return this.client().api("/subscriptions")
703
+ .post({
926
704
  changeType,
927
705
  notificationUrl,
928
706
  resource,
929
707
  expirationDateTime,
930
708
  clientState,
931
- },
932
- ...args,
933
- });
709
+ });
934
710
  },
935
711
  /**
936
712
  * Updates a subscription's expiration time (renewal).
@@ -945,21 +721,14 @@ export default {
945
721
  * subscriptionId: "abc123-def456"
946
722
  * });
947
723
  */
948
- updateSubscription({
949
- subscriptionId, ...args
950
- }) {
724
+ updateSubscription({ subscriptionId } = {}) {
951
725
  const expirationDateTime = new Date(
952
726
  Date.now() + WEBHOOK_SUBSCRIPTION_EXPIRATION_TIME_MILLISECONDS,
953
727
  ).toISOString();
954
-
955
- return this._makeRequest({
956
- method: "PATCH",
957
- path: `/subscriptions/${subscriptionId}`,
958
- data: {
728
+ return this.client().api(`/subscriptions/${subscriptionId}`)
729
+ .patch({
959
730
  expirationDateTime,
960
- },
961
- ...args,
962
- });
731
+ });
963
732
  },
964
733
  /**
965
734
  * Deletes a subscription. Call this when deactivating a webhook source
@@ -974,14 +743,9 @@ export default {
974
743
  * subscriptionId: "abc123-def456"
975
744
  * });
976
745
  */
977
- deleteSubscription({
978
- subscriptionId, ...args
979
- }) {
980
- return this._makeRequest({
981
- method: "DELETE",
982
- path: `/subscriptions/${subscriptionId}`,
983
- ...args,
984
- });
746
+ deleteSubscription({ subscriptionId } = {}) {
747
+ return this.client().api(`/subscriptions/${subscriptionId}`)
748
+ .delete();
985
749
  },
986
750
  },
987
751
  };
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-new-file-created",
6
6
  name: "New File Created",
7
7
  description: "Emit new event when a new file is created in Microsoft Sharepoint.",
8
- version: "0.0.5",
8
+ version: "0.0.6",
9
9
  type: "source",
10
10
  dedupe: "unique",
11
11
  props: {
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-new-folder-created",
6
6
  name: "New Folder Created",
7
7
  description: "Emit new event when a new folder is created in Microsoft Sharepoint.",
8
- version: "0.0.5",
8
+ version: "0.0.6",
9
9
  type: "source",
10
10
  dedupe: "unique",
11
11
  props: {
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-new-list-item",
6
6
  name: "New List Item",
7
7
  description: "Emit new event when a new list item is created in Microsoft Sharepoint.",
8
- version: "0.0.10",
8
+ version: "0.0.11",
9
9
  type: "source",
10
10
  dedupe: "unique",
11
11
  props: {
@@ -4,9 +4,9 @@ import { WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS } from "../../common/constants.mjs
4
4
 
5
5
  export default {
6
6
  key: "sharepoint-updated-file-instant",
7
- name: "New File Updated (Instant)",
8
- description: "Emit new event when specific files are updated in a SharePoint document library",
9
- version: "0.0.1",
7
+ name: "File Updated or Deleted (Instant)",
8
+ description: "Emit a new event when specific files are updated or deleted in a SharePoint document library",
9
+ version: "0.0.3",
10
10
  type: "source",
11
11
  dedupe: "unique",
12
12
  props: {
@@ -67,8 +67,8 @@ export default {
67
67
  ],
68
68
  label: "Files to Monitor",
69
69
  description:
70
- "Select one or more files to monitor for updates. " +
71
- "You'll receive a real-time event whenever any of these files are modified.\n\n" +
70
+ "Select one or more files to monitor for changes. " +
71
+ "You'll receive a real-time event whenever any of these files are modified or deleted.\n\n" +
72
72
  "**Important:** Only the selected files will trigger events. Changes to other files in the drive will be ignored. " +
73
73
  "This ensures you only receive notifications for the documents you care about.",
74
74
  },
@@ -101,8 +101,39 @@ export default {
101
101
  clientState,
102
102
  });
103
103
 
104
- // Store the file IDs we're monitoring (unwrap labeled values)
105
- const fileIds = this.sharepoint.resolveWrappedArrayValues(this.fileIds);
104
+ // Store the file IDs we're monitoring (unwrap labeled values and parse JSON)
105
+ const wrappedFileIds = this.sharepoint.resolveWrappedArrayValues(this.fileIds);
106
+ // Parse JSON strings to extract just the IDs, handle objects, and trim strings
107
+ const fileIds = wrappedFileIds.map((fileId) => {
108
+ // Handle object values directly
109
+ if (typeof fileId === "object" && fileId !== null) {
110
+ if (!fileId.id) {
111
+ console.log(`Warning: Object fileId missing 'id' field: ${JSON.stringify(fileId)}`);
112
+ return String(fileId);
113
+ }
114
+ return fileId.id;
115
+ }
116
+
117
+ // Handle string values - trim whitespace first
118
+ if (typeof fileId === "string") {
119
+ const trimmedFileId = fileId.trim();
120
+ if (trimmedFileId.startsWith("{")) {
121
+ try {
122
+ const parsed = JSON.parse(trimmedFileId);
123
+ if (!parsed || !parsed.id) {
124
+ throw new Error("Parsed object missing 'id' field");
125
+ }
126
+ return parsed.id;
127
+ } catch (e) {
128
+ console.log(`Warning: Failed to parse fileId: ${trimmedFileId}, error: ${e.message}`);
129
+ return trimmedFileId;
130
+ }
131
+ }
132
+ return trimmedFileId;
133
+ }
134
+
135
+ return fileId;
136
+ });
106
137
  this._setMonitoredFileIds(fileIds);
107
138
 
108
139
  // Initialize delta tracking - get current state so we only see future changes
@@ -220,10 +251,23 @@ export default {
220
251
  }
221
252
  },
222
253
  generateMeta(file) {
223
- const ts = Date.parse(file.lastModifiedDateTime);
254
+ // Use lastModifiedDateTime for updated files, deletedDateTime for deleted files
255
+ // Fall back to current time only if neither is available
256
+ let ts;
257
+ if (file.lastModifiedDateTime) {
258
+ ts = Date.parse(file.lastModifiedDateTime);
259
+ } else if (file.deletedDateTime) {
260
+ ts = Date.parse(file.deletedDateTime);
261
+ } else {
262
+ ts = Date.now();
263
+ }
264
+
265
+ const action = file.deleted
266
+ ? "deleted"
267
+ : "updated";
224
268
  return {
225
269
  id: `${file.id}-${ts}`,
226
- summary: `File updated: ${file.name}`,
270
+ summary: `File ${action}: ${file.name}`,
227
271
  ts,
228
272
  };
229
273
  },
@@ -272,8 +316,8 @@ export default {
272
316
 
273
317
  const validNotifications = body.value.filter((notification) => {
274
318
  if (notification.clientState !== clientState) {
275
- console.warn(
276
- `Ignoring notification with unexpected clientState: ${notification.clientState}`,
319
+ console.log(
320
+ `Warning: Ignoring notification with unexpected clientState: ${notification.clientState}`,
277
321
  );
278
322
  return false;
279
323
  }
@@ -313,8 +357,9 @@ export default {
313
357
  });
314
358
 
315
359
  // Find files that changed and are in our monitored list
360
+ // Include both updated files (item.file) and deleted files (item.deleted)
316
361
  for (const item of deltaResponse.value || []) {
317
- if (item.file && monitoredFileIds.includes(item.id)) {
362
+ if ((item.file || item.deleted) && monitoredFileIds.includes(item.id)) {
318
363
  changedFiles.push(item);
319
364
  }
320
365
  }
@@ -336,8 +381,9 @@ export default {
336
381
  // Emit events for each changed file
337
382
  for (const file of changedFiles) {
338
383
  // Delta response may not include downloadUrl - fetch fresh if needed
384
+ // Skip fetching download URL for deleted files (they no longer exist)
339
385
  let downloadUrl = file["@microsoft.graph.downloadUrl"];
340
- if (!downloadUrl) {
386
+ if (!downloadUrl && !file.deleted) {
341
387
  try {
342
388
  const freshFile = await this.sharepoint.getDriveItem({
343
389
  driveId,
@@ -5,7 +5,7 @@ export default {
5
5
  key: "sharepoint-updated-list-item",
6
6
  name: "Updated List Item",
7
7
  description: "Emit new event when a list item is updated in Microsoft Sharepoint.",
8
- version: "0.0.10",
8
+ version: "0.0.11",
9
9
  type: "source",
10
10
  dedupe: "unique",
11
11
  props: {