@hasna/connectors 1.3.22 → 1.3.23
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.
- package/bin/index.js +109 -59
- package/bin/mcp.js +236 -182
- package/bin/serve.js +77 -33
- package/connectors/connect-dropbox/src/api/bulk.ts +285 -0
- package/connectors/connect-dropbox/src/api/index.ts +4 -0
- package/connectors/connect-dropbox/src/cli/index.ts +151 -0
- package/connectors/connect-github/src/api/bulk.ts +328 -0
- package/connectors/connect-github/src/api/index.ts +4 -0
- package/connectors/connect-github/src/cli/index.ts +145 -0
- package/connectors/connect-gmail/src/api/history.ts +82 -0
- package/connectors/connect-gmail/src/api/index.ts +12 -0
- package/connectors/connect-gmail/src/api/settings.ts +280 -0
- package/connectors/connect-gmail/src/api/watch.ts +40 -0
- package/connectors/connect-gmail/src/cli/index.ts +237 -0
- package/connectors/connect-googleads/src/api/bulk.ts +354 -0
- package/connectors/connect-googleads/src/api/index.ts +4 -0
- package/connectors/connect-googleads/src/cli/index.ts +192 -0
- package/connectors/connect-googlecalendar/src/api/acl.ts +66 -0
- package/connectors/connect-googlecalendar/src/api/bulk.ts +452 -0
- package/connectors/connect-googlecalendar/src/api/freebusy.ts +35 -0
- package/connectors/connect-googlecalendar/src/api/index.ts +9 -0
- package/connectors/connect-googlecalendar/src/cli/index.ts +522 -0
- package/connectors/connect-googlecalendar/src/types/index.ts +90 -0
- package/connectors/connect-googlecontacts/src/api/bulk.ts +365 -0
- package/connectors/connect-googlecontacts/src/api/groups.ts +164 -0
- package/connectors/connect-googlecontacts/src/api/index.ts +8 -0
- package/connectors/connect-googlecontacts/src/cli/index.ts +340 -0
- package/connectors/connect-googledocs/src/api/bulk.ts +301 -0
- package/connectors/connect-googledocs/src/api/index.ts +4 -0
- package/connectors/connect-googledocs/src/cli/index.ts +187 -0
- package/connectors/connect-googledrive/src/api/bulk.ts +505 -0
- package/connectors/connect-googledrive/src/api/changes.ts +139 -0
- package/connectors/connect-googledrive/src/api/client.ts +34 -0
- package/connectors/connect-googledrive/src/api/index.ts +12 -0
- package/connectors/connect-googledrive/src/api/revisions.ts +132 -0
- package/connectors/connect-googledrive/src/cli/index.ts +624 -0
- package/connectors/connect-googledrive/src/index.ts +2 -0
- package/connectors/connect-googlephotos/src/api/bulk.ts +455 -0
- package/connectors/connect-googlephotos/src/api/index.ts +8 -0
- package/connectors/connect-googlephotos/src/cli/index.ts +185 -0
- package/connectors/connect-googletasks/src/api/bulk.ts +359 -0
- package/connectors/connect-googletasks/src/api/index.ts +1 -0
- package/connectors/connect-googletasks/src/cli/index.ts +178 -0
- package/connectors/connect-linear/src/api/bulk.ts +219 -0
- package/connectors/connect-linear/src/api/index.ts +4 -0
- package/connectors/connect-linear/src/cli/index.ts +116 -0
- package/connectors/connect-shopify/src/api/bulk.ts +288 -0
- package/connectors/connect-shopify/src/api/index.ts +4 -0
- package/connectors/connect-shopify/src/cli/index.ts +108 -0
- package/connectors/connect-slack/src/api/bulk.ts +237 -0
- package/connectors/connect-slack/src/api/index.ts +4 -0
- package/connectors/connect-slack/src/cli/index.ts +157 -0
- package/connectors/connect-stripe/src/api/bulk.ts +488 -0
- package/connectors/connect-stripe/src/api/index.ts +4 -0
- package/connectors/connect-stripe/src/cli/index.ts +206 -0
- package/dist/index.js +75 -33
- package/dist/lib/runner.d.ts +15 -5
- package/package.json +2 -2
- package/connectors/connect-cloudflare/bun.lock +0 -32
- package/connectors/connect-gmail/bin/index.js +0 -7027
- package/connectors/connect-gmail/dist/cli/index.js +0 -7035
- package/connectors/connect-gmail/dist/index.js +0 -2174
- package/dist/server/server.test.d.ts +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { DriveClient } from './client.ts';
|
|
2
|
+
import type { DriveFile } from '../types/index.ts';
|
|
3
|
+
|
|
4
|
+
// ============================================
|
|
5
|
+
// Changes API Types
|
|
6
|
+
// ============================================
|
|
7
|
+
|
|
8
|
+
export interface ListChangesOptions {
|
|
9
|
+
pageToken: string;
|
|
10
|
+
pageSize?: number;
|
|
11
|
+
spaces?: string;
|
|
12
|
+
includeRemoved?: boolean;
|
|
13
|
+
includeItemsFromAllDrives?: boolean;
|
|
14
|
+
restrictToMyDrive?: boolean;
|
|
15
|
+
driveId?: string;
|
|
16
|
+
supportsAllDrives?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ChangeRecord {
|
|
20
|
+
fileId: string;
|
|
21
|
+
type: 'file' | 'drive' | 'driveMember';
|
|
22
|
+
removed?: boolean;
|
|
23
|
+
file?: DriveFile;
|
|
24
|
+
drive?: {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
kind: string;
|
|
28
|
+
};
|
|
29
|
+
driveMember?: {
|
|
30
|
+
kind: string;
|
|
31
|
+
displayName: string;
|
|
32
|
+
photoLink: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ListChangesResponse {
|
|
37
|
+
kind: string;
|
|
38
|
+
nextPageToken: string;
|
|
39
|
+
newStartPageToken: string;
|
|
40
|
+
changes: ChangeRecord[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface WatchChangesOptions {
|
|
44
|
+
topicName: string;
|
|
45
|
+
params?: Record<string, string>;
|
|
46
|
+
watchType?: string;
|
|
47
|
+
watchId?: string;
|
|
48
|
+
token?: string;
|
|
49
|
+
expiration?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface WatchResponse {
|
|
53
|
+
kind: string;
|
|
54
|
+
id: string;
|
|
55
|
+
resourceId: string;
|
|
56
|
+
resourceUri: string;
|
|
57
|
+
expiration: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Changes API module - track changes to Drive files and shared drives
|
|
62
|
+
*/
|
|
63
|
+
export class ChangesApi {
|
|
64
|
+
constructor(private readonly client: DriveClient) {}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the starting page token for change tracking
|
|
68
|
+
*/
|
|
69
|
+
async getStartPageToken(options: {
|
|
70
|
+
supportsAllDrives?: boolean;
|
|
71
|
+
driveId?: string;
|
|
72
|
+
} = {}): Promise<{ nextPageToken: string }> {
|
|
73
|
+
const params: Record<string, string | boolean | undefined> = {};
|
|
74
|
+
if (options.supportsAllDrives !== undefined) params.supportsAllDrives = options.supportsAllDrives;
|
|
75
|
+
if (options.driveId) params.driveId = options.driveId;
|
|
76
|
+
|
|
77
|
+
return this.client.get<{ nextPageToken: string }>('/changes/startPageToken', params);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* List changes for a user
|
|
82
|
+
*/
|
|
83
|
+
async list(options: ListChangesOptions): Promise<ListChangesResponse> {
|
|
84
|
+
const params: Record<string, string | number | boolean | undefined> = {
|
|
85
|
+
pageToken: options.pageToken,
|
|
86
|
+
};
|
|
87
|
+
if (options.pageSize) params.pageSize = options.pageSize;
|
|
88
|
+
if (options.spaces) params.spaces = options.spaces;
|
|
89
|
+
if (options.includeRemoved !== undefined) params.includeRemoved = options.includeRemoved;
|
|
90
|
+
if (options.includeItemsFromAllDrives !== undefined) params.includeItemsFromAllDrives = options.includeItemsFromAllDrives;
|
|
91
|
+
if (options.restrictToMyDrive !== undefined) params.restrictToMyDrive = options.restrictToMyDrive;
|
|
92
|
+
if (options.driveId) params.driveId = options.driveId;
|
|
93
|
+
if (options.supportsAllDrives !== undefined) params.supportsAllDrives = options.supportsAllDrives;
|
|
94
|
+
|
|
95
|
+
return this.client.get<ListChangesResponse>('/changes', params);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Iterate over all changes (handles pagination)
|
|
100
|
+
*/
|
|
101
|
+
async *listAll(options: Omit<ListChangesOptions, 'pageToken'> & { startPageToken: string }): AsyncGenerator<ChangeRecord> {
|
|
102
|
+
let pageToken = options.startPageToken;
|
|
103
|
+
const baseOptions = { ...options };
|
|
104
|
+
// @ts-expect-error pageToken will be set
|
|
105
|
+
delete baseOptions.pageToken;
|
|
106
|
+
// @ts-expect-error startPageToken is not part of ListChangesOptions
|
|
107
|
+
delete baseOptions.startPageToken;
|
|
108
|
+
|
|
109
|
+
do {
|
|
110
|
+
const response = await this.list({ ...baseOptions, pageToken });
|
|
111
|
+
for (const record of response.changes || []) {
|
|
112
|
+
yield record;
|
|
113
|
+
}
|
|
114
|
+
if (response.nextPageToken) {
|
|
115
|
+
pageToken = response.nextPageToken;
|
|
116
|
+
} else {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
} while (true);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Subscribe to push notifications for changes
|
|
124
|
+
*/
|
|
125
|
+
async watch(options: WatchChangesOptions): Promise<WatchResponse> {
|
|
126
|
+
const body: Record<string, unknown> = {
|
|
127
|
+
id: options.watchId,
|
|
128
|
+
type: options.watchType || 'web_hook',
|
|
129
|
+
token: options.token,
|
|
130
|
+
expiration: options.expiration,
|
|
131
|
+
};
|
|
132
|
+
if (options.topicName) {
|
|
133
|
+
body.type = 'web_hook';
|
|
134
|
+
body.params = { topicName: options.topicName, ...(options.params || {}) };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return this.client.post<WatchResponse>('/changes/watch', body as unknown as Record<string, unknown>);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -213,4 +213,38 @@ export class DriveClient {
|
|
|
213
213
|
|
|
214
214
|
return response.arrayBuffer();
|
|
215
215
|
}
|
|
216
|
+
|
|
217
|
+
async downloadRevision(fileId: string, revisionId: string): Promise<ArrayBuffer> {
|
|
218
|
+
const accessToken = await getValidAccessToken();
|
|
219
|
+
const url = DRIVE_API_BASE + '/files/' + fileId + '/revisions/' + revisionId + '?alt=media&supportsAllDrives=true';
|
|
220
|
+
|
|
221
|
+
const response = await fetch(url, {
|
|
222
|
+
headers: {
|
|
223
|
+
'Authorization': 'Bearer ' + accessToken,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
throw new DriveApiError('Download revision failed: ' + response.statusText, response.status);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return response.arrayBuffer();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async exportRevision(fileId: string, revisionId: string, mimeType: string): Promise<ArrayBuffer> {
|
|
235
|
+
const accessToken = await getValidAccessToken();
|
|
236
|
+
const url = DRIVE_API_BASE + '/files/' + fileId + '/revisions/' + revisionId + '/export?mimeType=' + encodeURIComponent(mimeType);
|
|
237
|
+
|
|
238
|
+
const response = await fetch(url, {
|
|
239
|
+
headers: {
|
|
240
|
+
'Authorization': 'Bearer ' + accessToken,
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
throw new DriveApiError('Export revision failed: ' + response.statusText, response.status);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return response.arrayBuffer();
|
|
249
|
+
}
|
|
216
250
|
}
|
|
@@ -4,6 +4,9 @@ import { FoldersApi } from './folders.ts';
|
|
|
4
4
|
import { TrashApi } from './trash.ts';
|
|
5
5
|
import { StorageApi } from './storage.ts';
|
|
6
6
|
import { DrivesApi } from './drives.ts';
|
|
7
|
+
import { BulkApi } from './bulk.ts';
|
|
8
|
+
import { ChangesApi } from './changes.ts';
|
|
9
|
+
import { RevisionsApi } from './revisions.ts';
|
|
7
10
|
|
|
8
11
|
export class Drive {
|
|
9
12
|
private readonly client: DriveClient;
|
|
@@ -14,6 +17,9 @@ export class Drive {
|
|
|
14
17
|
public readonly trash: TrashApi;
|
|
15
18
|
public readonly storage: StorageApi;
|
|
16
19
|
public readonly drives: DrivesApi;
|
|
20
|
+
public readonly bulk: BulkApi;
|
|
21
|
+
public readonly changes: ChangesApi;
|
|
22
|
+
public readonly revisions: RevisionsApi;
|
|
17
23
|
|
|
18
24
|
constructor() {
|
|
19
25
|
this.client = new DriveClient();
|
|
@@ -22,6 +28,9 @@ export class Drive {
|
|
|
22
28
|
this.trash = new TrashApi(this.client);
|
|
23
29
|
this.storage = new StorageApi(this.client);
|
|
24
30
|
this.drives = new DrivesApi(this.client);
|
|
31
|
+
this.bulk = new BulkApi(this.client);
|
|
32
|
+
this.changes = new ChangesApi(this.client);
|
|
33
|
+
this.revisions = new RevisionsApi(this.client);
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
/**
|
|
@@ -45,3 +54,6 @@ export { FoldersApi } from './folders.ts';
|
|
|
45
54
|
export { TrashApi } from './trash.ts';
|
|
46
55
|
export { StorageApi } from './storage.ts';
|
|
47
56
|
export { DrivesApi } from './drives.ts';
|
|
57
|
+
export { BulkApi } from './bulk.ts';
|
|
58
|
+
export { ChangesApi } from './changes.ts';
|
|
59
|
+
export { RevisionsApi } from './revisions.ts';
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { DriveClient } from './client.ts';
|
|
2
|
+
|
|
3
|
+
// ============================================
|
|
4
|
+
// Revisions API Types
|
|
5
|
+
// ============================================
|
|
6
|
+
|
|
7
|
+
export interface FileRevision {
|
|
8
|
+
id: string;
|
|
9
|
+
mimeType: string;
|
|
10
|
+
modifiedTime?: string;
|
|
11
|
+
keepForever?: boolean;
|
|
12
|
+
published?: boolean;
|
|
13
|
+
publishedOutsideDomain?: boolean;
|
|
14
|
+
publishAuto?: boolean;
|
|
15
|
+
publishedLink?: string;
|
|
16
|
+
lastModifyingUser?: {
|
|
17
|
+
displayName: string;
|
|
18
|
+
photoLink: string;
|
|
19
|
+
me: boolean;
|
|
20
|
+
permissionId: string;
|
|
21
|
+
emailAddress: string;
|
|
22
|
+
};
|
|
23
|
+
originalFilename?: string;
|
|
24
|
+
size?: string;
|
|
25
|
+
exportLinks?: Record<string, string>;
|
|
26
|
+
sha1Checksum?: string;
|
|
27
|
+
sha256Checksum?: string;
|
|
28
|
+
md5Checksum?: string;
|
|
29
|
+
contentHints?: {
|
|
30
|
+
thumbnail?: {
|
|
31
|
+
image: string;
|
|
32
|
+
mimeType: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ListRevisionsResponse {
|
|
38
|
+
kind: string;
|
|
39
|
+
fileExportMimeType?: string;
|
|
40
|
+
revisions: FileRevision[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ListRevisionsOptions {
|
|
44
|
+
pageSize?: number;
|
|
45
|
+
pageToken?: string;
|
|
46
|
+
fields?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UpdateRevisionOptions {
|
|
50
|
+
keepForever?: boolean;
|
|
51
|
+
publishAuto?: boolean;
|
|
52
|
+
published?: boolean;
|
|
53
|
+
publishedOutsideDomain?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Revisions API module - manage file revision history
|
|
58
|
+
*/
|
|
59
|
+
export class RevisionsApi {
|
|
60
|
+
constructor(private readonly client: DriveClient) {}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* List revisions of a file
|
|
64
|
+
*/
|
|
65
|
+
async list(fileId: string, options: ListRevisionsOptions = {}): Promise<ListRevisionsResponse> {
|
|
66
|
+
const params: Record<string, string | number | undefined> = {};
|
|
67
|
+
if (options.pageSize) params.pageSize = options.pageSize;
|
|
68
|
+
if (options.pageToken) params.pageToken = options.pageToken;
|
|
69
|
+
if (options.fields) params.fields = options.fields;
|
|
70
|
+
|
|
71
|
+
return this.client.get<ListRevisionsResponse>(`/files/${fileId}/revisions`, params);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Iterate over all revisions of a file (handles pagination)
|
|
76
|
+
*/
|
|
77
|
+
async *listAll(fileId: string, options: Omit<ListRevisionsOptions, 'pageToken'> = {}): AsyncGenerator<FileRevision> {
|
|
78
|
+
let pageToken: string | undefined;
|
|
79
|
+
do {
|
|
80
|
+
const response = await this.list(fileId, { ...options, pageToken });
|
|
81
|
+
for (const revision of response.revisions || []) {
|
|
82
|
+
yield revision;
|
|
83
|
+
}
|
|
84
|
+
pageToken = response.revisions?.length && response.revisions.length > 0
|
|
85
|
+
? undefined
|
|
86
|
+
: undefined;
|
|
87
|
+
// Drive revisions API doesn't always paginate, so we check once
|
|
88
|
+
break;
|
|
89
|
+
} while (pageToken);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get a specific revision
|
|
94
|
+
*/
|
|
95
|
+
async get(fileId: string, revisionId: string): Promise<FileRevision> {
|
|
96
|
+
return this.client.get<FileRevision>(`/files/${fileId}/revisions/${revisionId}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Update revision metadata
|
|
101
|
+
*/
|
|
102
|
+
async update(fileId: string, revisionId: string, options: UpdateRevisionOptions): Promise<FileRevision> {
|
|
103
|
+
const body: Record<string, unknown> = {};
|
|
104
|
+
if (options.keepForever !== undefined) body.keepForever = options.keepForever;
|
|
105
|
+
if (options.publishAuto !== undefined) body.publishAuto = options.publishAuto;
|
|
106
|
+
if (options.published !== undefined) body.published = options.published;
|
|
107
|
+
if (options.publishedOutsideDomain !== undefined) body.publishedOutsideDomain = options.publishedOutsideDomain;
|
|
108
|
+
|
|
109
|
+
return this.client.patch<FileRevision>(`/files/${fileId}/revisions/${revisionId}`, body);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Delete a revision
|
|
114
|
+
*/
|
|
115
|
+
async delete(fileId: string, revisionId: string): Promise<void> {
|
|
116
|
+
await this.client.delete(`/files/${fileId}/revisions/${revisionId}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Download the content of a revision
|
|
121
|
+
*/
|
|
122
|
+
async download(fileId: string, revisionId: string): Promise<ArrayBuffer> {
|
|
123
|
+
return this.client.downloadRevision(fileId, revisionId);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Export a Google Workspace document revision in a specific format
|
|
128
|
+
*/
|
|
129
|
+
async export(fileId: string, revisionId: string, mimeType: string): Promise<ArrayBuffer> {
|
|
130
|
+
return this.client.exportRevision(fileId, revisionId, mimeType);
|
|
131
|
+
}
|
|
132
|
+
}
|