@pipedream/google_drive 4.0.0 → 5.0.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 (72) hide show
  1. package/actions/add-comment/add-comment.mjs +1 -1
  2. package/actions/add-file-sharing-preference/add-file-sharing-preference.mjs +1 -1
  3. package/actions/copy-file/copy-file.mjs +1 -1
  4. package/actions/create-file-from-template/create-file-from-template.mjs +1 -1
  5. package/actions/create-file-from-text/create-file-from-text.mjs +1 -1
  6. package/actions/create-folder/create-folder.mjs +1 -1
  7. package/actions/create-shared-drive/create-shared-drive.mjs +1 -1
  8. package/actions/create-text-file/create-text-file.mjs +1 -1
  9. package/actions/delete-comment/delete-comment.mjs +1 -1
  10. package/actions/delete-file/delete-file.mjs +1 -1
  11. package/actions/delete-reply/delete-reply.mjs +1 -1
  12. package/actions/delete-shared-drive/delete-shared-drive.mjs +1 -1
  13. package/actions/download-file/download-file.mjs +26 -7
  14. package/actions/find-file/find-file.mjs +1 -1
  15. package/actions/find-folder/find-folder.mjs +1 -1
  16. package/actions/find-forms/find-forms.mjs +1 -1
  17. package/actions/find-spreadsheets/find-spreadsheets.mjs +1 -1
  18. package/actions/get-comment/get-comment.mjs +1 -1
  19. package/actions/get-current-user/get-current-user.mjs +1 -1
  20. package/actions/get-file/get-file.mjs +1 -1
  21. package/actions/get-file-by-id/get-file-by-id.mjs +1 -1
  22. package/actions/get-folder-id-for-path/get-folder-id-for-path.mjs +1 -1
  23. package/actions/get-reply/get-reply.mjs +1 -1
  24. package/actions/get-shared-drive/get-shared-drive.mjs +1 -1
  25. package/actions/get-user-details/get-user-details.mjs +1 -1
  26. package/actions/is-folder-ancestor/is-folder-ancestor.mjs +1 -1
  27. package/actions/list-access-proposals/list-access-proposals.mjs +1 -1
  28. package/actions/list-comments/list-comments.mjs +1 -1
  29. package/actions/list-files/list-files.mjs +1 -1
  30. package/actions/list-mime-type-options/list-mime-type-options.mjs +1 -1
  31. package/actions/list-permissions/list-permissions.mjs +1 -1
  32. package/actions/list-replies/list-replies.mjs +1 -1
  33. package/actions/list-shared-drives/list-shared-drives.mjs +1 -1
  34. package/actions/list-theme-id-options/list-theme-id-options.mjs +1 -1
  35. package/actions/move-file/move-file.mjs +1 -1
  36. package/actions/move-file-to-trash/move-file-to-trash.mjs +1 -1
  37. package/actions/remove-file-sharing-permission/remove-file-sharing-permission.mjs +1 -1
  38. package/actions/remove-sharing/remove-sharing.mjs +1 -1
  39. package/actions/reply-to-comment/reply-to-comment.mjs +1 -1
  40. package/actions/resolve-access-proposal/resolve-access-proposal.mjs +1 -1
  41. package/actions/resolve-comment/resolve-comment.mjs +1 -1
  42. package/actions/search-files/search-files.mjs +1 -1
  43. package/actions/search-shared-drives/search-shared-drives.mjs +1 -1
  44. package/actions/share-file/share-file.mjs +1 -1
  45. package/actions/trash-file/trash-file.mjs +1 -1
  46. package/actions/update-comment/update-comment.mjs +1 -1
  47. package/actions/update-file/update-file.mjs +1 -1
  48. package/actions/update-reply/update-reply.mjs +1 -1
  49. package/actions/update-shared-drive/update-shared-drive.mjs +1 -1
  50. package/actions/upload-file/upload-file.mjs +1 -1
  51. package/common/constants.mjs +22 -12
  52. package/common/utils.mjs +32 -0
  53. package/google_drive.app.mjs +90 -11
  54. package/package.json +1 -1
  55. package/sources/changes-to-files-in-drive/changes-to-files-in-drive.mjs +9 -6
  56. package/sources/changes-to-specific-files/changes-to-specific-files.mjs +1 -1
  57. package/sources/changes-to-specific-files-shared-drive/changes-to-specific-files-shared-drive.mjs +9 -6
  58. package/sources/common-dedupe-changes.mjs +22 -11
  59. package/sources/common-webhook.mjs +104 -40
  60. package/sources/new-access-proposal/new-access-proposal.mjs +1 -1
  61. package/sources/new-files-instant/new-files-instant.mjs +4 -1
  62. package/sources/new-files-instant-polling/new-files-instant-polling.mjs +38 -47
  63. package/sources/new-files-shared-drive/new-files-shared-drive.mjs +2 -16
  64. package/sources/new-or-modified-comments/new-or-modified-comments.mjs +10 -7
  65. package/sources/new-or-modified-comments-polling/new-or-modified-comments-polling.mjs +1 -1
  66. package/sources/new-or-modified-files/new-or-modified-files.mjs +20 -1
  67. package/sources/new-or-modified-files-polling/new-or-modified-files-polling.mjs +37 -36
  68. package/sources/new-or-modified-folders/new-or-modified-folders.mjs +52 -50
  69. package/sources/new-or-modified-folders-polling/new-or-modified-folders-polling.mjs +55 -63
  70. package/sources/new-shared-drive/new-shared-drive.mjs +1 -1
  71. package/sources/new-spreadsheet/new-spreadsheet.mjs +1 -1
  72. package/sources/new-spreadsheet-polling/new-spreadsheet-polling.mjs +38 -47
@@ -1,14 +1,17 @@
1
1
  import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
2
2
  import googleDrive from "../../google_drive.app.mjs";
3
3
  import { getListFilesOpts } from "../../common/utils.mjs";
4
- import { GOOGLE_DRIVE_FOLDER_MIME_TYPE } from "../../common/constants.mjs";
4
+ import {
5
+ CHANGE_FILTER_FILE_FIELDS,
6
+ GOOGLE_DRIVE_FOLDER_MIME_TYPE,
7
+ } from "../../common/constants.mjs";
5
8
  import sampleEmit from "./test-event.mjs";
6
9
 
7
10
  export default {
8
11
  key: "google_drive-new-files-instant-polling",
9
12
  name: "New Files (Polling)",
10
13
  description: "Emit new event when a new file is added in your linked Google Drive",
11
- version: "0.0.14",
14
+ version: "0.1.0",
12
15
  type: "source",
13
16
  dedupe: "unique",
14
17
  props: {
@@ -51,6 +54,12 @@ export default {
51
54
  "changesPageSize",
52
55
  ],
53
56
  },
57
+ maxEmitsPerRun: {
58
+ propDefinition: [
59
+ googleDrive,
60
+ "maxEmitsPerRun",
61
+ ],
62
+ },
54
63
  },
55
64
  hooks: {
56
65
  async deploy() {
@@ -143,54 +152,36 @@ export default {
143
152
  const currentRunTimestamp = Date.now();
144
153
  const lastRunTimestamp = this._getLastRunTimestamp();
145
154
 
146
- const pageToken = this._getPageToken();
147
- const driveId = this.getDriveId();
148
-
149
- const changedFilesStream =
150
- this.googleDrive.listChanges(pageToken, driveId, this.changesPageSize);
151
-
152
- for await (const changedFilesPage of changedFilesStream) {
153
- const {
154
- changedFiles,
155
- nextPageToken,
156
- } = changedFilesPage;
157
-
158
- console.log(changedFiles.length
159
- ? `Processing ${changedFiles.length} changed files`
160
- : "No changed files since last run");
161
-
162
- for (const file of changedFiles) {
163
- // Skip folders
164
- if (file.mimeType === GOOGLE_DRIVE_FOLDER_MIME_TYPE) {
165
- continue;
155
+ const caughtUp = await this.googleDrive.processChangesPages({
156
+ pageToken: this._getPageToken(),
157
+ driveId: this.getDriveId(),
158
+ pageSize: this.changesPageSize,
159
+ fileFields: CHANGE_FILTER_FILE_FIELDS,
160
+ maxEmits: this.maxEmitsPerRun,
161
+ changeFilter: ({ file }) => Date.parse(file.createdTime) > lastRunTimestamp
162
+ && this.shouldProcess(file),
163
+ processPage: async (changedFiles) => {
164
+ console.log(changedFiles.length
165
+ ? `Processing ${changedFiles.length} new files`
166
+ : "No new files since last run");
167
+
168
+ let emitted = 0;
169
+ for (const file of changedFiles) {
170
+ const fullFile = await this.googleDrive.getFile(file.id, {
171
+ fields: "*",
172
+ });
173
+ await this.emitFile(fullFile);
174
+ emitted++;
166
175
  }
176
+ return emitted;
177
+ },
178
+ savePageToken: (nextPageToken) => this._setPageToken(nextPageToken),
179
+ });
167
180
 
168
- // Get full file metadata including parents
169
- const fullFile = await this.googleDrive.getFile(file.id, {
170
- fields: "*",
171
- });
172
-
173
- // Check if it's a new file (created after last run)
174
- const fileCreatedTime = Date.parse(fullFile.createdTime);
175
- if (fileCreatedTime <= lastRunTimestamp) {
176
- console.log(`Skipping existing file ${fullFile.name || fullFile.id}`);
177
- continue;
178
- }
179
-
180
- if (!this.shouldProcess(fullFile)) {
181
- console.log(`Skipping file ${fullFile.name || fullFile.id}`);
182
- continue;
183
- }
184
-
185
- await this.emitFile(fullFile);
186
- }
187
-
188
- // Save the next page token after successfully processing
189
- this._setPageToken(nextPageToken);
181
+ // Hold until caught up so backlog files aren't skipped
182
+ if (caughtUp) {
183
+ this._setLastRunTimestamp(currentRunTimestamp);
190
184
  }
191
-
192
- // Update the last run timestamp after processing all changes
193
- this._setLastRunTimestamp(currentRunTimestamp);
194
185
  },
195
186
  sampleEmit,
196
187
  };
@@ -7,7 +7,7 @@ export default {
7
7
  key: "google_drive-new-files-shared-drive",
8
8
  name: "New Files (Shared Drive)",
9
9
  description: "Emit new event when a new file is added in your shared Google Drive",
10
- version: "0.1.16",
10
+ version: "0.1.18",
11
11
  type: "source",
12
12
  dedupe: "unique",
13
13
  props: {
@@ -69,21 +69,7 @@ export default {
69
69
  },
70
70
  methods: sourceComponent.methods,
71
71
  async run() {
72
- const pageToken = this._getPageToken();
73
-
74
- const driveId = this.getDriveId();
75
- const changedFilesStream =
76
- this.googleDrive.listChanges(pageToken, driveId, this.changesPageSize);
77
- for await (const changedFilesPage of changedFilesStream) {
78
- const { nextPageToken } = changedFilesPage;
79
-
80
- // Process all the changed files retrieved from the current page
81
- await this.processChanges();
82
-
83
- // After successfully processing the changed files, we store the page
84
- // token of the next page
85
- this._setPageToken(nextPageToken);
86
- }
72
+ await this.processChanges();
87
73
  },
88
74
  sampleEmit,
89
75
  };
@@ -18,10 +18,8 @@ export default {
18
18
  name: "New or Modified Comments (Instant)",
19
19
  description:
20
20
  "Emit new event when a comment is created or modified in the selected file",
21
- version: "1.0.25",
21
+ version: "1.1.0",
22
22
  type: "source",
23
- // Dedupe events based on the "x-goog-message-number" header for the target channel:
24
- // https://developers.google.com/drive/api/v3/push#making-watch-requests
25
23
  dedupe: "unique",
26
24
  props: {
27
25
  ...common.props,
@@ -72,17 +70,19 @@ export default {
72
70
  GOOGLE_DRIVE_NOTIFICATION_CHANGE,
73
71
  ];
74
72
  },
75
- generateMeta(data, headers) {
73
+ isRelevantChange({ file }) {
74
+ return file.id === this.fileId;
75
+ },
76
+ generateMeta(data) {
76
77
  const {
77
78
  id: commentId,
78
79
  content: summary,
79
80
  modifiedTime: tsString,
80
81
  } = data;
81
82
  const ts = Date.parse(tsString);
82
- const eventId = headers && headers["x-goog-message-number"];
83
83
 
84
84
  return {
85
- id: md5(`${commentId}-${eventId || ts}`),
85
+ id: md5(`${commentId}-${ts}`),
86
86
  summary,
87
87
  ts,
88
88
  };
@@ -109,6 +109,7 @@ export default {
109
109
  changedFiles = changedFiles.filter(({ id }) => id === this.fileId);
110
110
  }
111
111
 
112
+ let emitted = 0;
112
113
  for (const file of changedFiles) {
113
114
  const lastCommentTimeForFile = this._getLastCommentTimeForFile(file.id);
114
115
  let maxModifiedTime = lastCommentTimeForFile;
@@ -127,13 +128,15 @@ export default {
127
128
  comment,
128
129
  ...changes,
129
130
  };
130
- const meta = this.generateMeta(comment, headers);
131
+ const meta = this.generateMeta(comment);
131
132
  this.$emit(eventToEmit, meta);
133
+ emitted++;
132
134
 
133
135
  maxModifiedTime = Math.max(maxModifiedTime, commentTime);
134
136
  this._updateLastCommentTimeForFile(file.id, maxModifiedTime);
135
137
  }
136
138
  }
139
+ return emitted;
137
140
  },
138
141
  },
139
142
  };
@@ -7,7 +7,7 @@ export default {
7
7
  key: "google_drive-new-or-modified-comments-polling",
8
8
  name: "New or Modified Comments (Polling)",
9
9
  description: "Emit new event when a comment is created or modified in the selected file",
10
- version: "0.0.14",
10
+ version: "0.0.16",
11
11
  type: "source",
12
12
  dedupe: "unique",
13
13
  props: {
@@ -14,6 +14,7 @@ import {
14
14
  GOOGLE_DRIVE_NOTIFICATION_ADD,
15
15
  GOOGLE_DRIVE_NOTIFICATION_CHANGE,
16
16
  GOOGLE_DRIVE_NOTIFICATION_UPDATE,
17
+ MASS_CHANGE_MAX_AGE_MILLISECONDS,
17
18
  PDF_EXPORTABLE_MIME_TYPES,
18
19
  } from "../../common/constants.mjs";
19
20
  import commonDedupeChanges from "../common-dedupe-changes.mjs";
@@ -28,7 +29,7 @@ export default {
28
29
  key: "google_drive-new-or-modified-files",
29
30
  name: "New or Modified Files (Instant)",
30
31
  description: "Emit new event when a file in the selected Drive is created, modified or trashed.",
31
- version: "1.0.0",
32
+ version: "2.0.0",
32
33
  type: "source",
33
34
  dedupe: "unique",
34
35
  props: {
@@ -92,6 +93,7 @@ export default {
92
93
  const { files } = await this.googleDrive.listFilesInPage(null, args);
93
94
 
94
95
  await this.processChanges(files);
96
+ this.flushFileIntervals();
95
97
  },
96
98
  ...common.hooks,
97
99
  },
@@ -116,6 +118,22 @@ export default {
116
118
  getChangesFileFields() {
117
119
  return CHANGED_FILE_FIELDS;
118
120
  },
121
+ // Skip bulk moves/sharing of old files; createdTime keeps uploads with an old modifiedTime
122
+ isRelevantChange({
123
+ time, file,
124
+ }) {
125
+ if (!this.shouldProcess(file)) {
126
+ return false;
127
+ }
128
+ if (this.watchForPropertiesChanges || file.trashed || !time) {
129
+ return true;
130
+ }
131
+ const changedAt = Date.parse(time);
132
+ return [
133
+ file.modifiedTime,
134
+ file.createdTime,
135
+ ].some((t) => !t || changedAt - Date.parse(t) <= MASS_CHANGE_MAX_AGE_MILLISECONDS);
136
+ },
119
137
  generateMeta({
120
138
  id, name, modifiedTime, trashed,
121
139
  }) {
@@ -187,6 +205,7 @@ export default {
187
205
  } finally {
188
206
  this.recordFileEmits(emittedFileIds);
189
207
  }
208
+ return emittedFileIds.length;
190
209
  },
191
210
  },
192
211
  sampleEmit,
@@ -2,14 +2,17 @@ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
2
2
  import googleDrive from "../../google_drive.app.mjs";
3
3
  import { getListFilesOpts } from "../../common/utils.mjs";
4
4
  import sampleEmit from "./test-event.mjs";
5
- import { GOOGLE_DRIVE_FOLDER_MIME_TYPE } from "../../common/constants.mjs";
5
+ import {
6
+ CHANGE_FILTER_FILE_FIELDS,
7
+ GOOGLE_DRIVE_FOLDER_MIME_TYPE,
8
+ } from "../../common/constants.mjs";
6
9
  import md5 from "md5";
7
10
 
8
11
  export default {
9
12
  key: "google_drive-new-or-modified-files-polling",
10
13
  name: "New or Modified Files (Polling)",
11
14
  description: "Emit new event when a file in the selected Drive is created, modified or trashed. [See the documentation](https://developers.google.com/drive/api/v3/reference/changes/list)",
12
- version: "0.0.16",
15
+ version: "0.1.0",
13
16
  type: "source",
14
17
  dedupe: "unique",
15
18
  props: {
@@ -72,6 +75,12 @@ export default {
72
75
  "changesPageSize",
73
76
  ],
74
77
  },
78
+ maxEmitsPerRun: {
79
+ propDefinition: [
80
+ googleDrive,
81
+ "maxEmitsPerRun",
82
+ ],
83
+ },
75
84
  },
76
85
  hooks: {
77
86
  async deploy() {
@@ -177,46 +186,38 @@ export default {
177
186
  },
178
187
  },
179
188
  async run() {
180
- // Store the current run timestamp at the start
181
189
  const currentRunTimestamp = Date.now();
182
190
  const lastRunTimestamp = this._getLastRunTimestamp();
183
191
 
184
- const pageToken = this._getPageToken();
185
- const driveId = this.getDriveId();
186
-
187
- const changedFilesStream =
188
- this.googleDrive.listChanges(pageToken, driveId, this.changesPageSize);
189
-
190
- for await (const changedFilesPage of changedFilesStream) {
191
- const {
192
- changedFiles,
193
- nextPageToken,
194
- } = changedFilesPage;
195
-
196
- console.log(changedFiles.length
197
- ? `Processing ${changedFiles.length} changed files`
198
- : "No changed files since last run");
199
-
200
- for (const file of changedFiles) {
201
- // Get full file metadata including parents
202
- const fullFile = await this.googleDrive.getFile(file.id, {
203
- fields: "*",
204
- });
205
-
206
- if (!this.shouldProcess(fullFile, lastRunTimestamp)) {
207
- console.log(`Skipping file ${fullFile.name || fullFile.id}`);
208
- continue;
192
+ const caughtUp = await this.googleDrive.processChangesPages({
193
+ pageToken: this._getPageToken(),
194
+ driveId: this.getDriveId(),
195
+ pageSize: this.changesPageSize,
196
+ fileFields: CHANGE_FILTER_FILE_FIELDS,
197
+ maxEmits: this.maxEmitsPerRun,
198
+ changeFilter: ({ file }) => this.shouldProcess(file, lastRunTimestamp),
199
+ processPage: async (changedFiles) => {
200
+ console.log(changedFiles.length
201
+ ? `Processing ${changedFiles.length} changed files`
202
+ : "No changed files since last run");
203
+
204
+ let emitted = 0;
205
+ for (const file of changedFiles) {
206
+ const fullFile = await this.googleDrive.getFile(file.id, {
207
+ fields: "*",
208
+ });
209
+ await this.emitFile(fullFile);
210
+ emitted++;
209
211
  }
212
+ return emitted;
213
+ },
214
+ savePageToken: (nextPageToken) => this._setPageToken(nextPageToken),
215
+ });
210
216
 
211
- await this.emitFile(fullFile);
212
- }
213
-
214
- // Save the next page token after successfully processing
215
- this._setPageToken(nextPageToken);
217
+ // Hold until caught up so backlog files aren't skipped
218
+ if (caughtUp) {
219
+ this._setLastRunTimestamp(currentRunTimestamp);
216
220
  }
217
-
218
- // Update the last run timestamp after processing all changes
219
- this._setLastRunTimestamp(currentRunTimestamp);
220
221
  },
221
222
  sampleEmit,
222
223
  };
@@ -9,6 +9,8 @@
9
9
  // 2) A timer that runs on regular intervals, renewing the notification channel as needed
10
10
 
11
11
  import {
12
+ CHANGE_FILTER_FILE_FIELDS,
13
+ GOOGLE_DRIVE_FOLDER_MIME_TYPE,
12
14
  GOOGLE_DRIVE_NOTIFICATION_ADD,
13
15
  GOOGLE_DRIVE_NOTIFICATION_CHANGE,
14
16
  GOOGLE_DRIVE_NOTIFICATION_UPDATE,
@@ -21,7 +23,7 @@ export default {
21
23
  key: "google_drive-new-or-modified-folders",
22
24
  name: "New or Modified Folders (Instant)",
23
25
  description: "Emit new event when a folder is created or modified in the selected Drive",
24
- version: "0.2.19",
26
+ version: "1.0.0",
25
27
  type: "source",
26
28
  // Dedupe events based on the "x-goog-message-number" header for the target channel:
27
29
  // https://developers.google.com/drive/api/v3/push#making-watch-requests
@@ -55,12 +57,21 @@ export default {
55
57
 
56
58
  const args = this.getListFilesOpts({
57
59
  q: `mimeType = "application/vnd.google-apps.folder" and modifiedTime > "${timeString}" and trashed = false`,
58
- fields: "files(id, mimeType)",
60
+ fields: `files(${CHANGE_FILTER_FILE_FIELDS})`,
59
61
  });
60
62
 
61
63
  const { files } = await this.googleDrive.listFilesInPage(null, args);
62
64
 
63
- await this.processChanges(files, null, 5);
65
+ const changeFilter = await this.getChangeFilter();
66
+ const folders = [];
67
+ for (const file of files) {
68
+ if (folders.length < 5 && await changeFilter({
69
+ file,
70
+ })) {
71
+ folders.push(file);
72
+ }
73
+ }
74
+ await this.processChanges(folders);
64
75
  },
65
76
  ...common.hooks,
66
77
  },
@@ -79,20 +90,24 @@ export default {
79
90
  GOOGLE_DRIVE_NOTIFICATION_UPDATE,
80
91
  ];
81
92
  },
82
- async getAllParents(folderId) {
93
+ getChangesFileFields() {
94
+ return CHANGE_FILTER_FILE_FIELDS;
95
+ },
96
+ async getAllParents(folderId, parentsCache = new Map()) {
83
97
  const allParents = [];
84
98
  let currentId = folderId;
85
99
 
86
100
  while (currentId) {
87
- const folder = await this.googleDrive.getFile(currentId, {
88
- fields: "parents",
89
- });
90
- const parents = folder.parents;
91
-
92
- if (parents && parents.length > 0) {
93
- allParents.push(parents[0]);
101
+ if (!parentsCache.has(currentId)) {
102
+ const { parents } = await this.googleDrive.getFile(currentId, {
103
+ fields: "parents",
104
+ });
105
+ parentsCache.set(currentId, parents?.[0]);
106
+ }
107
+ currentId = parentsCache.get(currentId);
108
+ if (currentId) {
109
+ allParents.push(currentId);
94
110
  }
95
- currentId = parents?.[0];
96
111
  }
97
112
 
98
113
  return allParents;
@@ -108,16 +123,13 @@ export default {
108
123
  ts,
109
124
  };
110
125
  },
111
- async getChanges(headers) {
126
+ getChanges(headers) {
112
127
  if (!headers) {
113
128
  return {
114
129
  change: { },
115
130
  };
116
131
  }
117
- const resourceUri = headers["x-goog-resource-uri"];
118
- const metadata = await this.googleDrive.getFileMetadata(`${resourceUri}&fields=*`);
119
132
  return {
120
- ...metadata,
121
133
  change: {
122
134
  state: headers["x-goog-resource-state"],
123
135
  resourceURI: headers["x-goog-resource-uri"],
@@ -125,45 +137,34 @@ export default {
125
137
  },
126
138
  };
127
139
  },
128
- async processChanges(changedFiles, headers, maxResults) {
129
- const files = changedFiles.filter(
130
- // API docs that define Google Drive folders:
131
- // https://developers.google.com/drive/api/v3/folder
132
- (file) => file.mimeType === "application/vnd.google-apps.folder",
133
- );
134
-
135
- const filteredFiles = [];
136
- for (const file of files) {
140
+ async getChangeFilter() {
141
+ let targetId = this.folderId;
142
+ const parentsCache = new Map();
143
+ return async ({ file }) => {
137
144
  // The changelog is updated each time a folder is opened. Check the
138
145
  // folder's `modifiedTime` to see if the folder has been modified.
139
- const fileInfo = await this.googleDrive.getFile(file.id);
140
- const root = await this.googleDrive.getFile(this.drive === "My Drive"
141
- ? "root"
142
- : this.drive);
143
-
144
- const allParents = [];
145
- if (this.includeSubfolders) {
146
- allParents.push(...(await this.getAllParents(file.id)));
147
- } else if (fileInfo.parents) {
148
- allParents.push(fileInfo.parents[0]);
146
+ if (file.mimeType !== GOOGLE_DRIVE_FOLDER_MIME_TYPE
147
+ || this._getLastModifiedTimeForFile(file.id) == Date.parse(file.modifiedTime)) {
148
+ return false;
149
149
  }
150
-
151
- if (!allParents.includes(this.folderId || root.id)) {
152
- continue;
150
+ if (!targetId) {
151
+ ({ id: targetId } = await this.googleDrive.getFile(this.isMyDrive()
152
+ ? "root"
153
+ : this.drive, {
154
+ fields: "id",
155
+ }));
153
156
  }
154
-
155
- filteredFiles.push(fileInfo);
156
- }
157
-
158
- if (maxResults && filteredFiles.length >= maxResults) {
159
- filteredFiles.length = maxResults;
160
- }
161
- for (const file of filteredFiles) {
162
- const lastModifiedTimeForFile = this._getLastModifiedTimeForFile(file.id);
157
+ const allParents = this.includeSubfolders
158
+ ? await this.getAllParents(file.id, parentsCache)
159
+ : (file.parents ?? []).slice(0, 1);
160
+ return allParents.includes(targetId);
161
+ };
162
+ },
163
+ async processChanges(changedFiles, headers) {
164
+ const changes = this.getChanges(headers);
165
+ for (const { id } of changedFiles) {
166
+ const file = await this.googleDrive.getFile(id);
163
167
  const modifiedTime = Date.parse(file.modifiedTime);
164
- if (lastModifiedTimeForFile == modifiedTime) continue;
165
-
166
- const changes = await this.getChanges(headers);
167
168
 
168
169
  const eventToEmit = {
169
170
  file,
@@ -175,6 +176,7 @@ export default {
175
176
 
176
177
  this._setModifiedTimeForFile(file.id, modifiedTime);
177
178
  }
179
+ return changedFiles.length;
178
180
  },
179
181
  },
180
182
  };