@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
@@ -1,226 +0,0 @@
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 the user's Google Drive
8
- // 2) A timer that runs on regular intervals, renewing the notification channel as needed
9
-
10
- const { uuid } = require("uuidv4");
11
- const includes = require("lodash.includes");
12
- const googleDrive = require("../../google_drive.app.js");
13
-
14
- module.exports = {
15
- key: "google_drive-changes-to-specific-files",
16
- name: "Changes to Specific Files",
17
- description:
18
- "Watches for changes to specific files, emitting an event any time a change is made to one of those files",
19
- version: "0.0.6",
20
- // Dedupe events based on the "x-goog-message-number" header for the target channel:
21
- // https://developers.google.com/drive/api/v3/push#making-watch-requests
22
- dedupe: "unique",
23
- props: {
24
- googleDrive,
25
- db: "$.service.db",
26
- http: "$.interface.http",
27
- drive: { propDefinition: [googleDrive, "watchedDrive"] },
28
- files: {
29
- type: "string[]",
30
- label: "Files",
31
- description: "The files you want to watch for changes.",
32
- optional: true,
33
- async options({ page, prevContext }) {
34
- const { nextPageToken } = prevContext;
35
- if (!this.drive) return [];
36
- if (this.drive === "myDrive") {
37
- return await this.googleDrive.listFiles({ pageToken: nextPageToken });
38
- }
39
-
40
- return await this.googleDrive.listFiles({
41
- pageToken: nextPageToken,
42
- corpora: "drive",
43
- driveId: this.drive,
44
- includeItemsFromAllDrives: true,
45
- supportsAllDrives: true,
46
- });
47
- },
48
- },
49
- updateTypes: { propDefinition: [googleDrive, "updateTypes"] },
50
- watchForPropertiesChanges: {
51
- propDefinition: [googleDrive, "watchForPropertiesChanges"],
52
- },
53
- timer: {
54
- label: "Push notification renewal schedule",
55
- description:
56
- "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**.",
57
- type: "$.interface.timer",
58
- default: {
59
- intervalSeconds: 60 * 60 * 24,
60
- },
61
- },
62
- },
63
- hooks: {
64
- async activate() {
65
- // Called when a componenent is created or updated. Handles all the logic
66
- // for starting and stopping watch notifications tied to the desired files.
67
-
68
- // You can pass the same channel ID in watch requests for multiple files, so
69
- // our channel ID is fixed for this component to simplify the state we have to
70
- // keep track of.
71
- const channelID = this.db.get("channelID") || uuid();
72
-
73
- // Subscriptions are keyed on Google's resourceID, "an opaque value that
74
- // identifies the watched resource". This value is included in request
75
- // headers, allowing us to look up the watched resource.
76
- let subscriptions = this.db.get("subscriptions") || {};
77
-
78
- for (const fileID of this.files) {
79
- const { expiration, resourceId } = await this.googleDrive.watchFile(
80
- channelID,
81
- this.http.endpoint,
82
- fileID
83
- );
84
- // The fileID must be kept with the subscription metadata so we can
85
- // renew the watch request for this specific file when it expires.
86
- subscriptions[resourceId] = { expiration, fileID };
87
- }
88
-
89
- // Save metadata on the subscription so we can stop / renew later
90
- this.db.set("subscriptions", subscriptions);
91
- this.db.set("channelID", channelID);
92
- },
93
- async deactivate() {
94
- const channelID = this.db.get("channelID");
95
- if (!channelID) {
96
- console.log(
97
- "Channel not found, cannot stop notifications for non-existent channel"
98
- );
99
- return;
100
- }
101
-
102
- const subscriptions = this.db.get("subscriptions") || {};
103
- for (const resourceId of Object.keys(subscriptions)) {
104
- await this.googleDrive.stopNotifications(channelID, resourceId);
105
- }
106
-
107
- // Reset DB state
108
- this.db.set("subscriptions", {});
109
- this.db.set("channelID", null);
110
- },
111
- },
112
- async run(event) {
113
- // This function is polymorphic: it can be triggered as a cron job, to make sure we renew
114
- // watch requests for specific files, or via HTTP request (the change payloads from Google)
115
-
116
- let subscriptions = this.db.get("subscriptions") || {};
117
- const channelID = this.db.get("channelID");
118
-
119
- // Component was invoked by timer
120
- if (event.interval_seconds) {
121
- for (const [currentResourceId, metadata] of Object.entries(
122
- subscriptions
123
- )) {
124
- const { fileID } = metadata;
125
- // If the subscription for this resource will expire before the next run,
126
- // stop the existing subscription and renew
127
- if (metadata.expiration < +new Date() + event.interval_seconds * 1000) {
128
- console.log(
129
- `Notifications for resource ${currentResourceId} are expiring at ${metadata.expiration}. Renewing`
130
- );
131
- await this.googleDrive.stopNotifications(
132
- channelID,
133
- currentResourceId
134
- );
135
- const { expiration, resourceId } = await this.googleDrive.watchFile(
136
- channelID,
137
- this.http.endpoint,
138
- fileID
139
- );
140
- subscriptions[resourceId] = { expiration, fileID };
141
- }
142
- }
143
-
144
- this.db.set("subscriptions", subscriptions);
145
- return;
146
- }
147
-
148
- const { headers } = event;
149
-
150
- if (headers["x-goog-resource-state"] === "sync") {
151
- console.log("Sync notification, exiting early");
152
- return;
153
- }
154
-
155
- if (
156
- !headers["x-goog-resource-state"] ||
157
- !headers["x-goog-resource-id"] ||
158
- !headers["x-goog-resource-uri"] ||
159
- !headers["x-goog-message-number"]
160
- ) {
161
- console.log("Request missing necessary headers: ", headers);
162
- return;
163
- }
164
-
165
- const incomingChannelID = headers["x-goog-channel-id"];
166
- if (incomingChannelID !== channelID) {
167
- console.log(
168
- `Channel ID of ${incomingChannelID} not equal to deployed component channel of ${channelID}`
169
- );
170
- }
171
-
172
- if (!(headers["x-goog-resource-id"] in subscriptions)) {
173
- console.log(
174
- `Resource ID of ${resourceId} not currently being tracked. Exiting`
175
- );
176
- return;
177
- }
178
-
179
- if (!includes(this.updateTypes, headers["x-goog-resource-state"])) {
180
- console.log(
181
- `Update type ${headers["x-goog-resource-state"]} not in list of updates to watch: `,
182
- this.updateTypes
183
- );
184
- return;
185
- }
186
-
187
- // We observed false positives where a single change to a document would trigger two changes:
188
- // one to "properties" and another to "content,properties". But changes to properties
189
- // alone are legitimate, most users just won't want this source to emit in those cases.
190
- // If x-goog-changed is _only_ set to "properties", only move on if the user set the prop
191
- if (
192
- !this.watchForPropertiesChanges &&
193
- headers["x-goog-changed"] === "properties"
194
- ) {
195
- console.log(
196
- "Change to properties only, which this component is set to ignore. Exiting"
197
- );
198
- return;
199
- }
200
-
201
- const file = await this.googleDrive.getFileMetadata(
202
- headers["x-goog-resource-uri"]
203
- );
204
-
205
- if (!file || !Object.keys(file).length) {
206
- console.log("No file metadata returned, nothing to emit");
207
- return;
208
- }
209
-
210
- const eventToEmit = {
211
- file,
212
- change: {
213
- state: headers["x-goog-resource-state"],
214
- resourceURI: headers["x-goog-resource-uri"],
215
- changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
216
- },
217
- };
218
-
219
- this.$emit(eventToEmit, {
220
- summary: `${headers["x-goog-resource-state"].toUpperCase()} - ${
221
- file.name || "Untitled"
222
- }`,
223
- id: headers["x-goog-message-number"],
224
- });
225
- },
226
- };
@@ -1,213 +0,0 @@
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
- const { uuid } = require("uuidv4");
12
- const includes = require("lodash.includes");
13
- const googleDrive = require("../../google_drive.app.js");
14
-
15
- module.exports = {
16
- key: "google_drive-new-or-modified-files",
17
- name: "New or Modified Files",
18
- description:
19
- "Emits a new event any time any file in your linked Google Drive is added, modified, or deleted",
20
- version: "0.0.6",
21
- // Dedupe events based on the "x-goog-message-number" header for the target channel:
22
- // https://developers.google.com/drive/api/v3/push#making-watch-requests
23
- dedupe: "unique",
24
- props: {
25
- googleDrive,
26
- db: "$.service.db",
27
- http: "$.interface.http",
28
- drive: { propDefinition: [googleDrive, "watchedDrive"] },
29
- updateTypes: { propDefinition: [googleDrive, "updateTypes"] },
30
- watchForPropertiesChanges: {
31
- propDefinition: [googleDrive, "watchForPropertiesChanges"],
32
- },
33
- timer: {
34
- label: "Push notification renewal schedule",
35
- description:
36
- "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**.",
37
- type: "$.interface.timer",
38
- default: {
39
- intervalSeconds: 60 * 60 * 24,
40
- },
41
- },
42
- },
43
- hooks: {
44
- async activate() {
45
- // Called when a component is created or updated. Handles all the logic
46
- // for starting and stopping watch notifications tied to the desired files.
47
-
48
- const channelID = this.db.get("channelID") || uuid();
49
-
50
- const startPageToken = await this.googleDrive.getPageToken();
51
- const { expiration, resourceId } = await this.googleDrive.watchDrive(
52
- channelID,
53
- this.http.endpoint,
54
- startPageToken,
55
- this.drive === "myDrive" ? null : this.drive
56
- );
57
- // We use and increment the pageToken as new changes arrive, in run()
58
- this.db.set("pageToken", startPageToken);
59
-
60
- // Save metadata on the subscription so we can stop / renew later
61
- // Subscriptions are tied to Google's resourceID, "an opaque value that
62
- // identifies the watched resource". This value is included in request headers
63
- this.db.set("subscription", { resourceId, expiration });
64
- this.db.set("channelID", channelID);
65
- },
66
- async deactivate() {
67
- const channelID = this.db.get("channelID");
68
- const { resourceId } = this.db.get("subscription");
69
-
70
- // Reset DB state before anything else
71
- this.db.set("subscription", null);
72
- this.db.set("channelID", null);
73
- this.db.set("pageToken", null);
74
-
75
- if (!channelID) {
76
- console.log(
77
- "Channel not found, cannot stop notifications for non-existent channel"
78
- );
79
- return;
80
- }
81
-
82
- if (!resourceId) {
83
- console.log(
84
- "No resource ID found, cannot stop notifications for non-existent resource"
85
- );
86
- return;
87
- }
88
-
89
- await this.googleDrive.stopNotifications(channelID, resourceId);
90
- },
91
- },
92
- async run(event) {
93
- // This function is polymorphic: it can be triggered as a cron job, to make sure we renew
94
- // watch requests for specific files, or via HTTP request (the change payloads from Google)
95
-
96
- let subscription = this.db.get("subscription");
97
- const channelID = this.db.get("channelID");
98
- const pageToken = this.db.get("pageToken");
99
-
100
- // Component was invoked by timer
101
- if (event.interval_seconds) {
102
- if (!subscription || !subscription.resourceId) {
103
- return;
104
- }
105
- console.log(
106
- `Checking for resubscription on resource ${subscription.resourceId}`
107
- );
108
- // If the subscription for this resource will expire before the next run,
109
- // stop the existing subscription and renew. Expiration is in ms.
110
- if (
111
- subscription.expiration <
112
- +new Date() + event.interval_seconds * 1000
113
- ) {
114
- console.log(
115
- `Notifications for resource ${subscription.resourceId} are expiring at ${subscription.expiration}. Renewing`
116
- );
117
- await this.googleDrive.stopNotifications(
118
- channelID,
119
- subscription.resourceId
120
- );
121
- const { expiration, resourceId } = await this.googleDrive.watchDrive(
122
- channelID,
123
- this.http.endpoint,
124
- pageToken,
125
- this.drive === "myDrive" ? null : this.drive
126
- );
127
- this.db.set("subscription", { expiration, resourceId });
128
- }
129
- return;
130
- }
131
-
132
- const { headers } = event;
133
-
134
- if (headers["x-goog-resource-state"] === "sync") {
135
- console.log("Sync notification, exiting early");
136
- return;
137
- }
138
-
139
- if (
140
- !headers["x-goog-resource-state"] ||
141
- !headers["x-goog-resource-id"] ||
142
- !headers["x-goog-resource-uri"] ||
143
- !headers["x-goog-message-number"]
144
- ) {
145
- console.log("Request missing necessary headers: ", headers);
146
- return;
147
- }
148
-
149
- const incomingChannelID = headers["x-goog-channel-id"];
150
- if (incomingChannelID !== channelID) {
151
- console.log(
152
- `Channel ID of ${incomingChannelID} not equal to deployed component channel of ${channelID}`
153
- );
154
- return;
155
- }
156
-
157
- if (headers["x-goog-resource-id"] !== subscription.resourceId) {
158
- console.log(
159
- `Resource ID of ${resourceId} not currently being tracked. Exiting`
160
- );
161
- return;
162
- }
163
-
164
- if (!includes(this.updateTypes, headers["x-goog-resource-state"])) {
165
- console.log(
166
- `Update type ${headers["x-goog-resource-state"]} not in list of updates to watch: `,
167
- this.updateTypes
168
- );
169
- return;
170
- }
171
-
172
- // We observed false positives where a single change to a document would trigger two changes:
173
- // one to "properties" and another to "content,properties". But changes to properties
174
- // alone are legitimate, most users just won't want this source to emit in those cases.
175
- // If x-goog-changed is _only_ set to "properties", only move on if the user set the prop
176
- if (
177
- !this.watchForPropertiesChanges &&
178
- headers["x-goog-changed"] === "properties"
179
- ) {
180
- console.log(
181
- "Change to properties only, which this component is set to ignore. Exiting"
182
- );
183
- return;
184
- }
185
-
186
- const {
187
- changedFiles,
188
- newStartPageToken,
189
- } = await this.googleDrive.getChanges(
190
- pageToken,
191
- this.drive === "myDrive" ? null : this.drive
192
- );
193
-
194
- this.db.set("pageToken", newStartPageToken);
195
-
196
- for (const file of changedFiles) {
197
- console.log(file);
198
- const eventToEmit = {
199
- file,
200
- change: {
201
- state: headers["x-goog-resource-state"],
202
- resourceURI: headers["x-goog-resource-uri"],
203
- changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
204
- },
205
- };
206
-
207
- this.$emit(eventToEmit, {
208
- summary: file.name,
209
- id: headers["x-goog-message-number"],
210
- });
211
- }
212
- },
213
- };