@pipedream/google_drive 0.3.3 → 0.4.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 (41) hide show
  1. package/actions/add-file-sharing-preference/add-file-sharing-preference.mjs +83 -0
  2. package/actions/copy-file/copy-file.mjs +34 -0
  3. package/actions/create-file/create-file.mjs +242 -0
  4. package/actions/create-file-from-template/create-file-from-template.mjs +98 -0
  5. package/actions/create-file-from-text/create-file-from-text.mjs +67 -0
  6. package/actions/create-folder/create-folder.mjs +54 -0
  7. package/actions/create-shared-drive/create-shared-drive.mjs +25 -0
  8. package/actions/delete-file/delete-file.mjs +37 -0
  9. package/actions/delete-shared-drive/delete-shared-drive.mjs +30 -0
  10. package/actions/download-file/download-file.mjs +120 -0
  11. package/actions/find-file/find-file.mjs +35 -0
  12. package/actions/find-folder/find-folder.mjs +38 -0
  13. package/actions/get-folder-id-for-path/get-folder-id-for-path.mjs +62 -0
  14. package/actions/get-shared-drive/get-shared-drive.mjs +37 -0
  15. package/actions/google-mime-types.mjs +19 -0
  16. package/actions/google-workspace-export-formats.mjs +74 -0
  17. package/actions/language-codes.mjs +742 -0
  18. package/actions/move-file/move-file.mjs +52 -0
  19. package/actions/move-file-to-trash/move-file-to-trash.mjs +41 -0
  20. package/actions/replace-file/replace-file.mjs +90 -0
  21. package/actions/search-shared-drives/search-shared-drives.mjs +34 -0
  22. package/actions/update-file/update-file.mjs +164 -0
  23. package/actions/update-shared-drive/update-shared-drive.mjs +77 -0
  24. package/actions/upload-file/upload-file.mjs +89 -0
  25. package/constants.mjs +190 -0
  26. package/google_drive.app.mjs +1429 -0
  27. package/package.json +23 -20
  28. package/pnpm-lock.yaml +393 -0
  29. package/sources/changes-to-specific-files/changes-to-specific-files.mjs +226 -0
  30. package/sources/changes-to-specific-files-shared-drive/changes-to-specific-files-shared-drive.mjs +110 -0
  31. package/sources/common-webhook.mjs +201 -0
  32. package/sources/new-files-instant/new-files-instant.mjs +95 -0
  33. package/sources/new-or-modified-comments/new-or-modified-comments.mjs +104 -0
  34. package/sources/new-or-modified-files/new-or-modified-files.mjs +66 -0
  35. package/sources/new-or-modified-folders/new-or-modified-folders.mjs +86 -0
  36. package/sources/new-shared-drive/new-shared-drive.mjs +68 -0
  37. package/utils.mjs +247 -0
  38. package/LICENSE +0 -7
  39. package/google_drive.app.js +0 -212
  40. package/sources/changes-to-specific-files/changes-to-specific-files.js +0 -226
  41. package/sources/new-or-modified-files/new-or-modified-files.js +0 -213
@@ -0,0 +1,110 @@
1
+ // This source processes changes to specific files in a user's Google Drive,
2
+ // implementing strategy enumerated in the Push Notifications API docs:
3
+ // https://developers.google.com/drive/api/v3/push .
4
+ //
5
+ // This source has two interfaces:
6
+ //
7
+ // 1) The HTTP requests tied to changes in files in the user's Google Drive
8
+ // 2) A timer that runs on regular intervals, renewing the notification channel as needed
9
+
10
+ import common from "../common-webhook.mjs";
11
+
12
+ import {
13
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
14
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
15
+ GOOGLE_DRIVE_NOTIFICATION_UPDATE,
16
+ } from "../../constants.mjs";
17
+
18
+ /**
19
+ * This source uses the Google Drive API's
20
+ * {@link https://developers.google.com/drive/api/v3/reference/changes/watch changes: watch}
21
+ * endpoint to subscribe to changes to the user's drive or a shard drive.
22
+ */
23
+ export default {
24
+ ...common,
25
+ key: "google_drive-changes-to-specific-files-shared-drive",
26
+ name: "Changes to Specific Files (Shared Drive)",
27
+ description: "Watches for changes to specific files in a shared drive, emitting an event any time a change is made to one of those files",
28
+ version: "0.0.1",
29
+ type: "source",
30
+ // Dedupe events based on the "x-goog-message-number" header for the target channel:
31
+ // https://developers.google.com/drive/api/v3/push#making-watch-requests
32
+ dedupe: "unique",
33
+ props: {
34
+ ...common.props,
35
+ files: {
36
+ type: "string[]",
37
+ label: "Files",
38
+ description: "The files you want to watch for changes.",
39
+ optional: true,
40
+ default: [],
41
+ options({ prevContext }) {
42
+ const { nextPageToken } = prevContext;
43
+ const baseOpts = {};
44
+ const opts = this.isMyDrive()
45
+ ? baseOpts
46
+ : {
47
+ ...baseOpts,
48
+ corpora: "drive",
49
+ driveId: this.getDriveId(),
50
+ includeItemsFromAllDrives: true,
51
+ supportsAllDrives: true,
52
+ };
53
+ return this.googleDrive.listFilesOptions(nextPageToken, opts);
54
+ },
55
+ },
56
+ },
57
+ methods: {
58
+ ...common.methods,
59
+ getUpdateTypes() {
60
+ return [
61
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
62
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
63
+ GOOGLE_DRIVE_NOTIFICATION_UPDATE,
64
+ ];
65
+ },
66
+ generateMeta(data, headers) {
67
+ const {
68
+ id: fileId,
69
+ name: fileName,
70
+ modifiedTime: tsString,
71
+ } = data;
72
+ const {
73
+ "x-goog-message-number": eventId,
74
+ "x-goog-resource-state": resourceState,
75
+ } = headers;
76
+
77
+ return {
78
+ id: `${fileId}-${eventId}`,
79
+ summary: `${resourceState.toUpperCase()} - ${
80
+ fileName || "Untitled"
81
+ }`,
82
+ ts: Date.parse(tsString),
83
+ };
84
+ },
85
+ isFileRelevant(file) {
86
+ return this.files.includes(file.id);
87
+ },
88
+ async processChange(file, headers) {
89
+ const eventToEmit = {
90
+ file,
91
+ change: {
92
+ state: headers["x-goog-resource-state"],
93
+ resourceURI: headers["x-goog-resource-uri"],
94
+ changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
95
+ },
96
+ };
97
+ const meta = this.generateMeta(file, headers);
98
+ this.$emit(eventToEmit, meta);
99
+ },
100
+ async processChanges(changedFiles, headers) {
101
+ for (const file of changedFiles) {
102
+ if (!this.isFileRelevant(file)) {
103
+ console.log(`Skipping event for irrelevant file ${file.id}`);
104
+ continue;
105
+ }
106
+ this.processChange(file, headers);
107
+ }
108
+ },
109
+ },
110
+ };
@@ -0,0 +1,201 @@
1
+ import includes from "lodash/includes.js";
2
+ import { v4 as uuid } from "uuid";
3
+
4
+ import googleDrive from "../google_drive.app.mjs";
5
+ import { WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS } from "../constants.mjs";
6
+
7
+ export default {
8
+ props: {
9
+ googleDrive,
10
+ db: "$.service.db",
11
+ http: "$.interface.http",
12
+ drive: {
13
+ propDefinition: [
14
+ googleDrive,
15
+ "watchedDrive",
16
+ ],
17
+ description: "Defaults to My Drive. To select a [Shared Drive](https://support.google.com/a/users/answer/9310351) instead, select it from this list.",
18
+ optional: false,
19
+ },
20
+ watchForPropertiesChanges: {
21
+ propDefinition: [
22
+ googleDrive,
23
+ "watchForPropertiesChanges",
24
+ ],
25
+ },
26
+ timer: {
27
+ label: "Push notification renewal schedule",
28
+ description:
29
+ "The Google Drive API requires occasional renewal of push notification subscriptions. **This runs in the background, so you should not need to modify this schedule**.",
30
+ type: "$.interface.timer",
31
+ static: {
32
+ intervalSeconds: WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS,
33
+ },
34
+ },
35
+ },
36
+ hooks: {
37
+ async activate() {
38
+ // Called when a component is created or updated. Handles all the logic
39
+ // for starting and stopping watch notifications tied to the desired
40
+ // files.
41
+ const channelID = uuid();
42
+ const {
43
+ startPageToken,
44
+ expiration,
45
+ resourceId,
46
+ } = await this.googleDrive.activateHook(
47
+ channelID,
48
+ this.http.endpoint,
49
+ this.getDriveId(),
50
+ );
51
+
52
+ // We use and increment the pageToken as new changes arrive, in run()
53
+ this._setPageToken(startPageToken);
54
+
55
+ // Save metadata on the subscription so we can stop / renew later
56
+ // Subscriptions are tied to Google's resourceID, "an opaque value that
57
+ // identifies the watched resource". This value is included in request headers
58
+ this._setSubscription({
59
+ resourceId,
60
+ expiration,
61
+ });
62
+ this._setChannelID(channelID);
63
+ },
64
+ async deactivate() {
65
+ const channelID = this._getChannelID();
66
+ const { resourceId } = this._getSubscription();
67
+ await this.googleDrive.deactivateHook(channelID, resourceId);
68
+
69
+ this._setSubscription(null);
70
+ this._setChannelID(null);
71
+ this._setPageToken(null);
72
+ },
73
+ },
74
+ methods: {
75
+ _getSubscription() {
76
+ return this.db.get("subscription");
77
+ },
78
+ _setSubscription(subscription) {
79
+ this.db.set("subscription", subscription);
80
+ },
81
+ _getChannelID() {
82
+ return this.db.get("channelID");
83
+ },
84
+ _setChannelID(channelID) {
85
+ this.db.set("channelID", channelID);
86
+ },
87
+ _getPageToken() {
88
+ return this.db.get("pageToken");
89
+ },
90
+ _setPageToken(pageToken) {
91
+ this.db.set("pageToken", pageToken);
92
+ },
93
+ isMyDrive(drive = this.drive) {
94
+ return googleDrive.methods.isMyDrive(drive);
95
+ },
96
+ getDriveId(drive = this.drive) {
97
+ return googleDrive.methods.getDriveId(drive);
98
+ },
99
+ /**
100
+ * This method returns the types of updates/events from Google Drive that
101
+ * the event source should listen to. This base implementation returns an
102
+ * empty list, which means that any event source that extends this module
103
+ * and that does not refine this implementation will essentially ignore
104
+ * every incoming event from Google Drive.
105
+ *
106
+ * @returns
107
+ * @type {UpdateType[]}
108
+ */
109
+ getUpdateTypes() {
110
+ return [];
111
+ },
112
+ /**
113
+ * This method is responsible for processing a list of changed files
114
+ * according to the event source's purpose. As an abstract method, it must
115
+ * be implemented by every event source that extends this module.
116
+ *
117
+ * @param {object[]} [changedFiles] - the list of file changes, as [defined
118
+ * by the API](https://bit.ly/3h7WeUa)
119
+ * @param {object} [headers] - an object containing the request headers of
120
+ * the webhook call made by Google Drive
121
+ */
122
+ processChanges() {
123
+ throw new Error("processChanges is not implemented");
124
+ },
125
+ },
126
+ async run(event) {
127
+ // This function is polymorphic: it can be triggered as a cron job, to make
128
+ // sure we renew watch requests for specific files, or via HTTP request (the
129
+ // change payloads from Google)
130
+ const subscription = this._getSubscription();
131
+ const channelID = this._getChannelID();
132
+ const pageToken = this._getPageToken();
133
+
134
+ // Component was invoked by timer
135
+ if (event.timestamp) {
136
+ const {
137
+ newChannelID,
138
+ newPageToken,
139
+ expiration,
140
+ resourceId,
141
+ } = await this.googleDrive.renewSubscription(
142
+ this.drive,
143
+ subscription,
144
+ this.http.endpoint,
145
+ channelID,
146
+ pageToken,
147
+ );
148
+
149
+ this._setSubscription({
150
+ expiration,
151
+ resourceId,
152
+ });
153
+ this._setChannelID(newChannelID);
154
+ this._setPageToken(newPageToken);
155
+ return;
156
+ }
157
+
158
+ const { headers } = event;
159
+ if (!this.googleDrive.checkHeaders(headers, subscription, channelID)) {
160
+ return;
161
+ }
162
+
163
+ if (!includes(this.getUpdateTypes(), headers["x-goog-resource-state"])) {
164
+ console.log(
165
+ `Update type ${headers["x-goog-resource-state"]} not in list of updates to watch: `,
166
+ this.getUpdateTypes(),
167
+ );
168
+ return;
169
+ }
170
+
171
+ // We observed false positives where a single change to a document would trigger two changes:
172
+ // one to "properties" and another to "content,properties". But changes to properties
173
+ // alone are legitimate, most users just won't want this source to emit in those cases.
174
+ // If x-goog-changed is _only_ set to "properties", only move on if the user set the prop
175
+ if (
176
+ !this.watchForPropertiesChanges &&
177
+ headers["x-goog-changed"] === "properties"
178
+ ) {
179
+ console.log(
180
+ "Change to properties only, which this component is set to ignore. Exiting",
181
+ );
182
+ return;
183
+ }
184
+
185
+ const driveId = this.getDriveId();
186
+ const changedFilesStream = this.googleDrive.listChanges(pageToken, driveId);
187
+ for await (const changedFilesPage of changedFilesStream) {
188
+ const {
189
+ changedFiles,
190
+ nextPageToken,
191
+ } = changedFilesPage;
192
+
193
+ // Process all the changed files retrieved from the current page
194
+ await this.processChanges(changedFiles, headers);
195
+
196
+ // After successfully processing the changed files, we store the page
197
+ // token of the next page
198
+ this._setPageToken(nextPageToken);
199
+ }
200
+ },
201
+ };
@@ -0,0 +1,95 @@
1
+ import common from "../common-webhook.mjs";
2
+ import {
3
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
4
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
5
+ } from "../../constants.mjs";
6
+
7
+ export default {
8
+ ...common,
9
+ key: "google_drive-new-files-instant",
10
+ name: "New Files (Instant)",
11
+ description: "Emit new event any time a new file is added in your linked Google Drive",
12
+ version: "0.0.15",
13
+ type: "source",
14
+ dedupe: "unique",
15
+ props: {
16
+ ...common.props,
17
+ folders: {
18
+ type: "string[]",
19
+ label: "Folders",
20
+ description:
21
+ "(Optional) The folders you want to watch for changes. Leave blank to watch for any new file in the Drive.",
22
+ optional: true,
23
+ default: [],
24
+ options({ prevContext }) {
25
+ const { nextPageToken } = prevContext;
26
+ const baseOpts = {
27
+ q: "mimeType = 'application/vnd.google-apps.folder'",
28
+ };
29
+ const opts = this.isMyDrive()
30
+ ? baseOpts
31
+ : {
32
+ ...baseOpts,
33
+ corpora: "drive",
34
+ driveId: this.getDriveId(),
35
+ includeItemsFromAllDrives: true,
36
+ supportsAllDrives: true,
37
+ };
38
+ return this.googleDrive.listFilesOptions(nextPageToken, opts);
39
+ },
40
+ },
41
+ },
42
+ hooks: {
43
+ ...common.hooks,
44
+ async activate() {
45
+ await common.hooks.activate.bind(this)();
46
+ this._setLastFileCreatedTime(Date.now());
47
+ },
48
+ },
49
+ methods: {
50
+ ...common.methods,
51
+ _getLastFileCreatedTime() {
52
+ return this.db.get("lastFileCreatedTime");
53
+ },
54
+ _setLastFileCreatedTime(lastFileCreatedTime) {
55
+ this.db.set("lastFileCreatedTime", lastFileCreatedTime);
56
+ },
57
+ shouldProcess(file) {
58
+ const watchedFolders = new Set(this.folders);
59
+ return (
60
+ watchedFolders.size == 0 ||
61
+ (file.parents && file.parents.some((p) => watchedFolders.has(p)))
62
+ );
63
+ },
64
+ getUpdateTypes() {
65
+ return [
66
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
67
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
68
+ ];
69
+ },
70
+ async processChanges(changedFiles) {
71
+ const lastFileCreatedTime = this._getLastFileCreatedTime();
72
+ let maxCreatedTime = lastFileCreatedTime;
73
+
74
+ for (const file of changedFiles) {
75
+ const fileInfo = await this.googleDrive.getFile(file.id);
76
+ const createdTime = Date.parse(fileInfo.createdTime);
77
+ if (
78
+ !this.shouldProcess(fileInfo) ||
79
+ createdTime < lastFileCreatedTime
80
+ ) {
81
+ continue;
82
+ }
83
+
84
+ this.$emit(fileInfo, {
85
+ summary: `New File: ${fileInfo.name}`,
86
+ id: file.id,
87
+ ts: createdTime,
88
+ });
89
+
90
+ maxCreatedTime = Math.max(createdTime, maxCreatedTime);
91
+ this._setLastFileCreatedTime(maxCreatedTime);
92
+ }
93
+ },
94
+ },
95
+ };
@@ -0,0 +1,104 @@
1
+ // This source processes changes to any files in a user's Google Drive,
2
+ // implementing strategy enumerated in the Push Notifications API docs:
3
+ // https://developers.google.com/drive/api/v3/push and here:
4
+ // https://developers.google.com/drive/api/v3/manage-changes
5
+ //
6
+ // This source has two interfaces:
7
+ //
8
+ // 1) The HTTP requests tied to changes in the user's Google Drive
9
+ // 2) A timer that runs on regular intervals, renewing the notification channel as needed
10
+
11
+ import common from "../common-webhook.mjs";
12
+ import { GOOGLE_DRIVE_NOTIFICATION_CHANGE } from "../../constants.mjs";
13
+
14
+ export default {
15
+ ...common,
16
+ key: "google_drive-new-or-modified-comments",
17
+ name: "New or Modified Comments",
18
+ description:
19
+ "Emits a new event any time a file comment is added, modified, or deleted in your linked Google Drive",
20
+ version: "0.0.9",
21
+ type: "source",
22
+ // Dedupe events based on the "x-goog-message-number" header for the target channel:
23
+ // https://developers.google.com/drive/api/v3/push#making-watch-requests
24
+ dedupe: "unique",
25
+ hooks: {
26
+ ...common.hooks,
27
+ async activate() {
28
+ await common.hooks.activate.bind(this)();
29
+ this._setInitTime(Date.now());
30
+ },
31
+ async deactivate() {
32
+ await common.hooks.deactivate.bind(this)();
33
+ this._setInitTime(null);
34
+ },
35
+ },
36
+ methods: {
37
+ ...common.methods,
38
+ _getInitTime() {
39
+ return this.db.get("initTime");
40
+ },
41
+ _setInitTime(initTime) {
42
+ this.db.set("initTime", initTime);
43
+ },
44
+ _getLastCommentTimeForFile(fileId) {
45
+ return this.db.get(fileId) || this._getInitTime();
46
+ },
47
+ _updateLastCommentTimeForFile(fileId, commentTime) {
48
+ this.db.set(fileId, commentTime);
49
+ },
50
+ getUpdateTypes() {
51
+ return [
52
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
53
+ ];
54
+ },
55
+ generateMeta(data, headers) {
56
+ const {
57
+ id: commentId,
58
+ content: summary,
59
+ modifiedTime: tsString,
60
+ } = data;
61
+ const { "x-goog-message-number": eventId } = headers;
62
+ return {
63
+ id: `${commentId}-${eventId}`,
64
+ summary,
65
+ ts: Date.parse(tsString),
66
+ };
67
+ },
68
+ async processChanges(changedFiles, headers) {
69
+ for (const file of changedFiles) {
70
+ const lastCommentTimeForFile = this._getLastCommentTimeForFile(file.id);
71
+ let maxModifiedTime = lastCommentTimeForFile;
72
+ const commentsStream = this.googleDrive.listComments(
73
+ file.id,
74
+ lastCommentTimeForFile,
75
+ );
76
+
77
+ for await (const comment of commentsStream) {
78
+ const commentTime = Date.parse(comment.modifiedTime);
79
+ if (commentTime <= lastCommentTimeForFile) {
80
+ continue;
81
+ }
82
+
83
+ const eventToEmit = {
84
+ comment,
85
+ file,
86
+ change: {
87
+ state: headers["x-goog-resource-state"],
88
+ resourceURI: headers["x-goog-resource-uri"],
89
+
90
+ // Additional details about the changes. Possible values: content,
91
+ // parents, children, permissions.
92
+ changed: headers["x-goog-changed"],
93
+ },
94
+ };
95
+ const meta = this.generateMeta(comment, headers);
96
+ this.$emit(eventToEmit, meta);
97
+
98
+ maxModifiedTime = Math.max(maxModifiedTime, commentTime);
99
+ this._updateLastCommentTimeForFile(file.id, maxModifiedTime);
100
+ }
101
+ }
102
+ },
103
+ },
104
+ };
@@ -0,0 +1,66 @@
1
+ // This source processes changes to any files in a user's Google Drive,
2
+ // implementing strategy enumerated in the Push Notifications API docs:
3
+ // https://developers.google.com/drive/api/v3/push and here:
4
+ // https://developers.google.com/drive/api/v3/manage-changes
5
+ //
6
+ // This source has two interfaces:
7
+ //
8
+ // 1) The HTTP requests tied to changes in the user's Google Drive
9
+ // 2) A timer that runs on regular intervals, renewing the notification channel as needed
10
+
11
+ import common from "../common-webhook.mjs";
12
+ import {
13
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
14
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
15
+ GOOGLE_DRIVE_NOTIFICATION_UPDATE,
16
+ } from "../../constants.mjs";
17
+
18
+ export default {
19
+ ...common,
20
+ key: "google_drive-new-or-modified-files",
21
+ name: "New or Modified Files",
22
+ description:
23
+ "Emits a new event any time any file in your linked Google Drive is added, modified, or deleted",
24
+ version: "0.0.20",
25
+ type: "source",
26
+ // Dedupe events based on the "x-goog-message-number" header for the target channel:
27
+ // https://developers.google.com/drive/api/v3/push#making-watch-requests
28
+ dedupe: "unique",
29
+ methods: {
30
+ ...common.methods,
31
+ getUpdateTypes() {
32
+ return [
33
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
34
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
35
+ GOOGLE_DRIVE_NOTIFICATION_UPDATE,
36
+ ];
37
+ },
38
+ generateMeta(data, headers) {
39
+ const {
40
+ id: fileId,
41
+ name: summary,
42
+ modifiedTime: tsString,
43
+ } = data;
44
+ const { "x-goog-message-number": eventId } = headers;
45
+ return {
46
+ id: `${fileId}-${eventId}`,
47
+ summary,
48
+ ts: Date.parse(tsString),
49
+ };
50
+ },
51
+ async processChanges(changedFiles, headers) {
52
+ for (const file of changedFiles) {
53
+ const eventToEmit = {
54
+ file,
55
+ change: {
56
+ state: headers["x-goog-resource-state"],
57
+ resourceURI: headers["x-goog-resource-uri"],
58
+ changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
59
+ },
60
+ };
61
+ const meta = this.generateMeta(file, headers);
62
+ this.$emit(eventToEmit, meta);
63
+ }
64
+ },
65
+ },
66
+ };
@@ -0,0 +1,86 @@
1
+ // This source processes changes to any files in a user's Google Drive,
2
+ // implementing strategy enumerated in the Push Notifications API docs:
3
+ // https://developers.google.com/drive/api/v3/push and here:
4
+ // https://developers.google.com/drive/api/v3/manage-changes
5
+ //
6
+ // This source has two interfaces:
7
+ //
8
+ // 1) The HTTP requests tied to changes in the user's Google Drive
9
+ // 2) A timer that runs on regular intervals, renewing the notification channel as needed
10
+
11
+ import common from "../common-webhook.mjs";
12
+ import {
13
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
14
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
15
+ GOOGLE_DRIVE_NOTIFICATION_UPDATE,
16
+ } from "../../constants.mjs";
17
+
18
+ export default {
19
+ ...common,
20
+ key: "google_drive-new-or-modified-folders",
21
+ name: "New or Modified Folders",
22
+ description:
23
+ "Emits a new event any time any folder in your linked Google Drive is added, modified, or deleted",
24
+ version: "0.0.9",
25
+ type: "source",
26
+ // Dedupe events based on the "x-goog-message-number" header for the target channel:
27
+ // https://developers.google.com/drive/api/v3/push#making-watch-requests
28
+ dedupe: "unique",
29
+ methods: {
30
+ ...common.methods,
31
+ _getLastModifiedTimeForFile(fileId) {
32
+ return this.db.get(fileId);
33
+ },
34
+ _setModifiedTimeForFile(fileId, modifiedTime) {
35
+ this.db.set(fileId, modifiedTime);
36
+ },
37
+ getUpdateTypes() {
38
+ return [
39
+ GOOGLE_DRIVE_NOTIFICATION_ADD,
40
+ GOOGLE_DRIVE_NOTIFICATION_CHANGE,
41
+ GOOGLE_DRIVE_NOTIFICATION_UPDATE,
42
+ ];
43
+ },
44
+ generateMeta(data, ts) {
45
+ const {
46
+ id: fileId,
47
+ name: summary,
48
+ } = data;
49
+ return {
50
+ id: `${fileId}-${ts}`,
51
+ summary,
52
+ ts,
53
+ };
54
+ },
55
+ async processChanges(changedFiles, headers) {
56
+ const files = changedFiles.filter(
57
+ // API docs that define Google Drive folders:
58
+ // https://developers.google.com/drive/api/v3/folder
59
+ (file) => file.mimeType === "application/vnd.google-apps.folder",
60
+ );
61
+
62
+ for (const file of files) {
63
+ // The changelog is updated each time a folder is opened. Check the
64
+ // folder's `modifiedTime` to see if the folder has been modified.
65
+ const fileInfo = await this.googleDrive.getFile(file.id);
66
+
67
+ const lastModifiedTimeForFile = this._getLastModifiedTimeForFile(file.id);
68
+ const modifiedTime = Date.parse(fileInfo.modifiedTime);
69
+ if (lastModifiedTimeForFile == modifiedTime) continue;
70
+
71
+ const eventToEmit = {
72
+ file,
73
+ change: {
74
+ state: headers["x-goog-resource-state"],
75
+ resourceURI: headers["x-goog-resource-uri"],
76
+ changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
77
+ },
78
+ };
79
+ const meta = this.generateMeta(file, modifiedTime);
80
+ this.$emit(eventToEmit, meta);
81
+
82
+ this._setModifiedTimeForFile(file.id, modifiedTime);
83
+ }
84
+ },
85
+ },
86
+ };