@libai168/dsh-tool-google-drive 0.2.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.
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/README.zh.md +129 -0
- package/lib/client.js +467 -0
- package/lib/index.js +339 -0
- package/lib/types/client.d.ts +225 -0
- package/lib/types/index.d.ts +16 -0
- package/package.json +70 -0
- package/scripts/auth-google.mjs +355 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/** Google Drive API client with injected fetch for testability. */
|
|
2
|
+
export class GoogleDriveError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(message, code) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.name = 'GoogleDriveError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function asRecord(value) {
|
|
11
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
12
|
+
}
|
|
13
|
+
function asArray(value) {
|
|
14
|
+
return Array.isArray(value) ? value : [];
|
|
15
|
+
}
|
|
16
|
+
function asString(record, key) {
|
|
17
|
+
const value = record[key];
|
|
18
|
+
return typeof value === 'string' ? value : value != null ? String(value) : '';
|
|
19
|
+
}
|
|
20
|
+
function asNumber(record, key) {
|
|
21
|
+
const value = record[key];
|
|
22
|
+
return typeof value === 'number' ? value : Number(value ?? 0) || 0;
|
|
23
|
+
}
|
|
24
|
+
function asBoolean(record, key) {
|
|
25
|
+
const value = record[key];
|
|
26
|
+
return typeof value === 'boolean' ? value : false;
|
|
27
|
+
}
|
|
28
|
+
function toJson(value) {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.stringify(value ?? {});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return '{}';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function mapOwners(value) {
|
|
37
|
+
return asArray(value).map(item => {
|
|
38
|
+
const record = asRecord(item);
|
|
39
|
+
return {
|
|
40
|
+
displayName: asString(record, 'displayName') || asString(record, 'display_name'),
|
|
41
|
+
emailAddress: asString(record, 'emailAddress') || asString(record, 'email_address'),
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function mapFile(data) {
|
|
46
|
+
const r = asRecord(data);
|
|
47
|
+
return {
|
|
48
|
+
id: asString(r, 'id'),
|
|
49
|
+
name: asString(r, 'name'),
|
|
50
|
+
mimeType: asString(r, 'mimeType'),
|
|
51
|
+
kind: asString(r, 'kind'),
|
|
52
|
+
description: asString(r, 'description'),
|
|
53
|
+
iconLink: asString(r, 'iconLink'),
|
|
54
|
+
webViewLink: asString(r, 'webViewLink'),
|
|
55
|
+
webContentLink: asString(r, 'webContentLink'),
|
|
56
|
+
size: asString(r, 'size'),
|
|
57
|
+
starred: asBoolean(r, 'starred'),
|
|
58
|
+
trashed: asBoolean(r, 'trashed'),
|
|
59
|
+
modifiedTime: asString(r, 'modifiedTime'),
|
|
60
|
+
createdTime: asString(r, 'createdTime'),
|
|
61
|
+
driveId: asString(r, 'driveId'),
|
|
62
|
+
parents: asArray(r.parents).map(v => String(v)),
|
|
63
|
+
owners: mapOwners(r.owners),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function mapPermission(data) {
|
|
67
|
+
const r = asRecord(data);
|
|
68
|
+
return {
|
|
69
|
+
id: asString(r, 'id'),
|
|
70
|
+
type: asString(r, 'type'),
|
|
71
|
+
kind: asString(r, 'kind'),
|
|
72
|
+
role: asString(r, 'role'),
|
|
73
|
+
emailAddress: asString(r, 'emailAddress'),
|
|
74
|
+
displayName: asString(r, 'displayName'),
|
|
75
|
+
allowFileDiscovery: asBoolean(r, 'allowFileDiscovery'),
|
|
76
|
+
expirationTime: asString(r, 'expirationTime'),
|
|
77
|
+
deleted: asBoolean(r, 'deleted'),
|
|
78
|
+
permissionDetails: toJson(r.permissionDetails),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function mapRevision(data) {
|
|
82
|
+
const r = asRecord(data);
|
|
83
|
+
return {
|
|
84
|
+
id: asString(r, 'id'),
|
|
85
|
+
mimeType: asString(r, 'mimeType'),
|
|
86
|
+
modifiedTime: asString(r, 'modifiedTime'),
|
|
87
|
+
keepForever: asBoolean(r, 'keepForever'),
|
|
88
|
+
published: asBoolean(r, 'published'),
|
|
89
|
+
publishAuto: asBoolean(r, 'publishAuto'),
|
|
90
|
+
publishedOutsideDomain: asBoolean(r, 'publishedOutsideDomain'),
|
|
91
|
+
size: asString(r, 'size'),
|
|
92
|
+
originalFilename: asString(r, 'originalFilename'),
|
|
93
|
+
md5Checksum: asString(r, 'md5Checksum'),
|
|
94
|
+
downloadUrl: asString(r, 'downloadUrl'),
|
|
95
|
+
exportLinks: toJson(r.exportLinks),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function mapSharedDrive(data) {
|
|
99
|
+
const r = asRecord(data);
|
|
100
|
+
return {
|
|
101
|
+
id: asString(r, 'id'),
|
|
102
|
+
name: asString(r, 'name'),
|
|
103
|
+
colorRgb: asString(r, 'colorRgb'),
|
|
104
|
+
backgroundImageLink: asString(r, 'backgroundImageLink'),
|
|
105
|
+
createdTime: asString(r, 'createdTime'),
|
|
106
|
+
hidden: asBoolean(r, 'hidden'),
|
|
107
|
+
themeId: asString(r, 'themeId'),
|
|
108
|
+
capabilities: toJson(r.capabilities),
|
|
109
|
+
restrictions: toJson(r.restrictions),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function mapSheetProperties(data) {
|
|
113
|
+
const r = asRecord(data);
|
|
114
|
+
return {
|
|
115
|
+
sheetId: asNumber(r, 'sheetId'),
|
|
116
|
+
title: asString(r, 'title'),
|
|
117
|
+
index: asNumber(r, 'index'),
|
|
118
|
+
sheetType: asString(r, 'sheetType'),
|
|
119
|
+
rowCount: asNumber(asRecord(r.gridProperties), 'rowCount'),
|
|
120
|
+
columnCount: asNumber(asRecord(r.gridProperties), 'columnCount'),
|
|
121
|
+
frozenRowCount: asNumber(asRecord(r.gridProperties), 'frozenRowCount'),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function extractTextFromElement(element) {
|
|
125
|
+
const r = asRecord(element);
|
|
126
|
+
const textRun = asRecord(r.textRun);
|
|
127
|
+
if (Object.keys(textRun).length)
|
|
128
|
+
return asString(textRun, 'content');
|
|
129
|
+
const paragraph = asRecord(r.paragraph);
|
|
130
|
+
if (Object.keys(paragraph).length) {
|
|
131
|
+
return asArray(paragraph.elements).map(extractTextFromElement).join('') + '\n';
|
|
132
|
+
}
|
|
133
|
+
const table = asRecord(r.table);
|
|
134
|
+
if (Object.keys(table).length) {
|
|
135
|
+
return asArray(table.tableRows).map(row => {
|
|
136
|
+
const rowRecord = asRecord(row);
|
|
137
|
+
return asArray(rowRecord.tableCells).map(cell => {
|
|
138
|
+
const cellRecord = asRecord(cell);
|
|
139
|
+
return asArray(cellRecord.content).map(extractTextFromElement).join('').trimEnd();
|
|
140
|
+
}).join('\t');
|
|
141
|
+
}).join('\n') + '\n';
|
|
142
|
+
}
|
|
143
|
+
const tableCell = asRecord(r.tableCell);
|
|
144
|
+
if (Object.keys(tableCell).length) {
|
|
145
|
+
return asArray(tableCell.content).map(extractTextFromElement).join('');
|
|
146
|
+
}
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
function extractDocumentContent(data) {
|
|
150
|
+
const r = asRecord(data);
|
|
151
|
+
const tabs = asArray(r.tabs);
|
|
152
|
+
if (tabs.length) {
|
|
153
|
+
const mapped = tabs.map(tab => {
|
|
154
|
+
const tabRecord = asRecord(tab);
|
|
155
|
+
const tabProps = asRecord(tabRecord.tabProperties);
|
|
156
|
+
const docTab = asRecord(tabRecord.documentTab);
|
|
157
|
+
const body = asRecord(docTab.body);
|
|
158
|
+
const text = asArray(body.content).map(extractTextFromElement).join('').trim();
|
|
159
|
+
return {
|
|
160
|
+
tabId: asString(tabProps, 'tabId'),
|
|
161
|
+
title: asString(tabProps, 'title'),
|
|
162
|
+
index: asNumber(tabProps, 'index'),
|
|
163
|
+
textLength: text.length,
|
|
164
|
+
text,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
text: mapped.map(t => t.text).filter(Boolean).join('\n').trim(),
|
|
169
|
+
tabs: mapped.map(({ text, ...rest }) => rest),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const body = asRecord(r.body);
|
|
173
|
+
const text = asArray(body.content).map(extractTextFromElement).join('').trim();
|
|
174
|
+
return { text, tabs: [] };
|
|
175
|
+
}
|
|
176
|
+
function mapSpreadsheet(data) {
|
|
177
|
+
const r = asRecord(data);
|
|
178
|
+
const props = asRecord(r.properties);
|
|
179
|
+
return {
|
|
180
|
+
spreadsheetId: asString(r, 'spreadsheetId') || asString(r, 'spreadsheet_id'),
|
|
181
|
+
title: asString(props, 'title') || asString(r, 'title'),
|
|
182
|
+
spreadsheetUrl: asString(r, 'spreadsheetUrl'),
|
|
183
|
+
locale: asString(props, 'locale'),
|
|
184
|
+
timeZone: asString(props, 'timeZone'),
|
|
185
|
+
sheetCount: asArray(r.sheets).length,
|
|
186
|
+
sheets: asArray(r.sheets).map(item => mapSheetProperties(asRecord(item).properties ?? item)),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function mapSheetValues(data, spreadsheetId, fallbackRange = '') {
|
|
190
|
+
const r = asRecord(data);
|
|
191
|
+
const values = asArray(r.values).map(row => asArray(row).map(cell => cell == null ? '' : String(cell)));
|
|
192
|
+
return {
|
|
193
|
+
spreadsheetId,
|
|
194
|
+
range: asString(r, 'range') || fallbackRange,
|
|
195
|
+
majorDimension: asString(r, 'majorDimension') || 'ROWS',
|
|
196
|
+
rowCount: values.length,
|
|
197
|
+
columnCount: values.reduce((max, row) => Math.max(max, row.length), 0),
|
|
198
|
+
values,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
export class GoogleDriveClient {
|
|
202
|
+
staticToken;
|
|
203
|
+
clientId;
|
|
204
|
+
clientSecret;
|
|
205
|
+
refreshToken;
|
|
206
|
+
baseUrl;
|
|
207
|
+
tokenUrl;
|
|
208
|
+
timeoutMs;
|
|
209
|
+
fetchImpl;
|
|
210
|
+
tokenCache = null;
|
|
211
|
+
constructor(options = {}) {
|
|
212
|
+
this.staticToken = options.accessToken ?? '';
|
|
213
|
+
this.clientId = options.clientId ?? '';
|
|
214
|
+
this.clientSecret = options.clientSecret ?? '';
|
|
215
|
+
this.refreshToken = options.refreshToken ?? '';
|
|
216
|
+
this.baseUrl = (options.baseUrl ?? 'https://www.googleapis.com/drive/v3').replace(/\/+$/, '');
|
|
217
|
+
this.tokenUrl = options.tokenUrl ?? 'https://oauth2.googleapis.com/token';
|
|
218
|
+
this.timeoutMs = options.timeoutMs ?? 15000;
|
|
219
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
220
|
+
}
|
|
221
|
+
hasCredentials() {
|
|
222
|
+
return Boolean(this.staticToken || (this.clientId && this.clientSecret && this.refreshToken));
|
|
223
|
+
}
|
|
224
|
+
buildUrl(urlOrPath, params) {
|
|
225
|
+
let url = /^https?:\/\//.test(urlOrPath) ? urlOrPath : `${this.baseUrl}${urlOrPath}`;
|
|
226
|
+
if (params) {
|
|
227
|
+
const search = new URLSearchParams();
|
|
228
|
+
for (const [key, value] of Object.entries(params)) {
|
|
229
|
+
if (value === undefined || value === '')
|
|
230
|
+
continue;
|
|
231
|
+
if (Array.isArray(value)) {
|
|
232
|
+
for (const item of value)
|
|
233
|
+
search.append(key, String(item));
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
search.append(key, String(value));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const qs = search.toString();
|
|
240
|
+
if (qs)
|
|
241
|
+
url += `${url.includes('?') ? '&' : '?'}${qs}`;
|
|
242
|
+
}
|
|
243
|
+
return url;
|
|
244
|
+
}
|
|
245
|
+
async getAccessToken(signal) {
|
|
246
|
+
if (this.staticToken)
|
|
247
|
+
return this.staticToken;
|
|
248
|
+
if (!this.clientId || !this.clientSecret || !this.refreshToken) {
|
|
249
|
+
throw new GoogleDriveError('Google Drive credentials not configured.', 401);
|
|
250
|
+
}
|
|
251
|
+
if (this.tokenCache && this.tokenCache.expiresAt > Date.now())
|
|
252
|
+
return this.tokenCache.token;
|
|
253
|
+
const body = new URLSearchParams({
|
|
254
|
+
client_id: this.clientId,
|
|
255
|
+
client_secret: this.clientSecret,
|
|
256
|
+
refresh_token: this.refreshToken,
|
|
257
|
+
grant_type: 'refresh_token',
|
|
258
|
+
});
|
|
259
|
+
const controller = new AbortController();
|
|
260
|
+
const combined = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
261
|
+
const timer = this.timeoutMs > 0 ? setTimeout(() => controller.abort(), this.timeoutMs) : undefined;
|
|
262
|
+
try {
|
|
263
|
+
const response = await this.fetchImpl(this.tokenUrl, {
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
266
|
+
body: body.toString(),
|
|
267
|
+
signal: combined,
|
|
268
|
+
});
|
|
269
|
+
if (!response.ok) {
|
|
270
|
+
const text = await response.text().catch(() => '');
|
|
271
|
+
throw new GoogleDriveError(`Google token endpoint returned HTTP ${response.status}: ${text}`, response.status);
|
|
272
|
+
}
|
|
273
|
+
const json = await response.json();
|
|
274
|
+
const error = typeof json.error === 'string' ? json.error : '';
|
|
275
|
+
if (error)
|
|
276
|
+
throw new GoogleDriveError(`Google token endpoint error: ${error}`, 401);
|
|
277
|
+
const token = asString(json, 'access_token');
|
|
278
|
+
const expiresIn = asNumber(json, 'expires_in');
|
|
279
|
+
if (!token)
|
|
280
|
+
throw new GoogleDriveError('Failed to obtain Google access token.', 401);
|
|
281
|
+
this.tokenCache = { token, expiresAt: Date.now() + Math.max(60, expiresIn - 60) * 1000 };
|
|
282
|
+
return token;
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
if (timer)
|
|
286
|
+
clearTimeout(timer);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async request(method, urlOrPath, options = {}) {
|
|
290
|
+
const { body, params, auth = true, responseType = 'json', signal } = options;
|
|
291
|
+
const url = this.buildUrl(urlOrPath, params);
|
|
292
|
+
const headers = { 'content-type': 'application/json; charset=utf-8' };
|
|
293
|
+
if (auth)
|
|
294
|
+
headers.authorization = `Bearer ${await this.getAccessToken(signal)}`;
|
|
295
|
+
const controller = new AbortController();
|
|
296
|
+
const combined = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
297
|
+
const timer = this.timeoutMs > 0 ? setTimeout(() => controller.abort(), this.timeoutMs) : undefined;
|
|
298
|
+
try {
|
|
299
|
+
const response = await this.fetchImpl(url, {
|
|
300
|
+
method,
|
|
301
|
+
headers,
|
|
302
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
303
|
+
signal: combined,
|
|
304
|
+
});
|
|
305
|
+
if (!response.ok) {
|
|
306
|
+
const text = await response.text().catch(() => '');
|
|
307
|
+
throw new GoogleDriveError(`Google Drive API ${method} ${urlOrPath} returned HTTP ${response.status}: ${text}`, response.status);
|
|
308
|
+
}
|
|
309
|
+
if (responseType === 'text')
|
|
310
|
+
return await response.text();
|
|
311
|
+
if (responseType === 'arrayBuffer')
|
|
312
|
+
return await response.arrayBuffer();
|
|
313
|
+
return await response.json();
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
if (timer)
|
|
317
|
+
clearTimeout(timer);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async authTest(signal) {
|
|
321
|
+
const token = await this.getAccessToken(signal);
|
|
322
|
+
return { ok: true, authMethod: this.staticToken ? 'access_token' : 'refresh_token', tokenPreview: `${token.slice(0, 8)}...` };
|
|
323
|
+
}
|
|
324
|
+
async listFiles(options = {}) {
|
|
325
|
+
const data = asRecord(await this.request('GET', '/files', {
|
|
326
|
+
params: {
|
|
327
|
+
q: options.query,
|
|
328
|
+
pageSize: options.pageSize,
|
|
329
|
+
pageToken: options.pageToken,
|
|
330
|
+
orderBy: options.orderBy,
|
|
331
|
+
spaces: options.spaces,
|
|
332
|
+
corpora: options.corpora,
|
|
333
|
+
driveId: options.driveId,
|
|
334
|
+
includeItemsFromAllDrives: options.includeItemsFromAllDrives,
|
|
335
|
+
supportsAllDrives: options.supportsAllDrives,
|
|
336
|
+
fields: 'nextPageToken, incompleteSearch, files(id,name,mimeType,kind,description,iconLink,webViewLink,webContentLink,size,starred,trashed,modifiedTime,createdTime,driveId,parents,owners(displayName,emailAddress))',
|
|
337
|
+
},
|
|
338
|
+
signal: options.signal,
|
|
339
|
+
}));
|
|
340
|
+
return {
|
|
341
|
+
items: asArray(data.files).map(mapFile),
|
|
342
|
+
nextPageToken: asString(data, 'nextPageToken'),
|
|
343
|
+
incompleteSearch: asBoolean(data, 'incompleteSearch'),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async getFile(fileId, options = {}) {
|
|
347
|
+
const data = await this.request('GET', `/files/${encodeURIComponent(fileId)}`, {
|
|
348
|
+
params: {
|
|
349
|
+
fields: options.fields ?? 'id,name,mimeType,kind,description,iconLink,webViewLink,webContentLink,size,starred,trashed,modifiedTime,createdTime,driveId,parents,owners(displayName,emailAddress))',
|
|
350
|
+
supportsAllDrives: options.supportsAllDrives,
|
|
351
|
+
},
|
|
352
|
+
signal: options.signal,
|
|
353
|
+
});
|
|
354
|
+
return mapFile(data);
|
|
355
|
+
}
|
|
356
|
+
async listPermissions(fileId, options = {}) {
|
|
357
|
+
const data = asRecord(await this.request('GET', '/files/' + encodeURIComponent(fileId) + '/permissions', {
|
|
358
|
+
params: {
|
|
359
|
+
pageSize: options.pageSize,
|
|
360
|
+
pageToken: options.pageToken,
|
|
361
|
+
supportsAllDrives: options.supportsAllDrives,
|
|
362
|
+
useDomainAdminAccess: options.useDomainAdminAccess,
|
|
363
|
+
includePermissionsForView: options.includePermissionsForView,
|
|
364
|
+
fields: options.fields ?? 'nextPageToken,permissions(id,type,kind,role,emailAddress,displayName,allowFileDiscovery,expirationTime,deleted,permissionDetails)',
|
|
365
|
+
},
|
|
366
|
+
signal: options.signal,
|
|
367
|
+
}));
|
|
368
|
+
return { fileId, items: asArray(data.permissions).map(mapPermission), nextPageToken: asString(data, 'nextPageToken') };
|
|
369
|
+
}
|
|
370
|
+
async listRevisions(fileId, options = {}) {
|
|
371
|
+
const data = asRecord(await this.request('GET', '/files/' + encodeURIComponent(fileId) + '/revisions', {
|
|
372
|
+
params: {
|
|
373
|
+
pageSize: options.pageSize,
|
|
374
|
+
pageToken: options.pageToken,
|
|
375
|
+
fields: options.fields ?? 'nextPageToken,revisions(id,mimeType,modifiedTime,keepForever,published,publishAuto,publishedOutsideDomain,size,originalFilename,md5Checksum,downloadUrl,exportLinks)',
|
|
376
|
+
},
|
|
377
|
+
signal: options.signal,
|
|
378
|
+
}));
|
|
379
|
+
return { fileId, items: asArray(data.revisions).map(mapRevision), nextPageToken: asString(data, 'nextPageToken') };
|
|
380
|
+
}
|
|
381
|
+
async exportFile(fileId, options = {}) {
|
|
382
|
+
const exportMimeType = options.exportMimeType ?? 'text/plain';
|
|
383
|
+
const responseEncoding = options.responseEncoding ?? 'text';
|
|
384
|
+
const raw = await this.request('GET', `/files/${encodeURIComponent(fileId)}/export`, {
|
|
385
|
+
params: {
|
|
386
|
+
mimeType: exportMimeType,
|
|
387
|
+
supportsAllDrives: options.supportsAllDrives,
|
|
388
|
+
},
|
|
389
|
+
responseType: responseEncoding === 'base64' ? 'arrayBuffer' : 'text',
|
|
390
|
+
signal: options.signal,
|
|
391
|
+
});
|
|
392
|
+
const content = responseEncoding === 'base64'
|
|
393
|
+
? Buffer.from(raw).toString('base64')
|
|
394
|
+
: String(raw);
|
|
395
|
+
return { fileId, exportMimeType, encoding: responseEncoding, content, contentLength: content.length };
|
|
396
|
+
}
|
|
397
|
+
async listSharedDrives(options = {}) {
|
|
398
|
+
const data = asRecord(await this.request('GET', '/drives', {
|
|
399
|
+
params: {
|
|
400
|
+
pageSize: options.pageSize,
|
|
401
|
+
pageToken: options.pageToken,
|
|
402
|
+
q: options.query,
|
|
403
|
+
useDomainAdminAccess: options.useDomainAdminAccess,
|
|
404
|
+
fields: 'nextPageToken, incompleteSearch, drives(id,name,colorRgb,backgroundImageLink,createdTime,hidden,themeId,capabilities,restrictions)',
|
|
405
|
+
},
|
|
406
|
+
signal: options.signal,
|
|
407
|
+
}));
|
|
408
|
+
const rawItems = asArray(data.drives).length ? asArray(data.drives) : asArray(data.items);
|
|
409
|
+
return {
|
|
410
|
+
items: rawItems.map(mapSharedDrive),
|
|
411
|
+
nextPageToken: asString(data, 'nextPageToken'),
|
|
412
|
+
incompleteSearch: asBoolean(data, 'incompleteSearch'),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
async getSharedDrive(driveId, options = {}) {
|
|
416
|
+
const data = await this.request('GET', `/drives/${encodeURIComponent(driveId)}`, {
|
|
417
|
+
params: {
|
|
418
|
+
useDomainAdminAccess: options.useDomainAdminAccess,
|
|
419
|
+
},
|
|
420
|
+
signal: options.signal,
|
|
421
|
+
});
|
|
422
|
+
return mapSharedDrive(data);
|
|
423
|
+
}
|
|
424
|
+
async getDocument(documentId, options = {}) {
|
|
425
|
+
const data = await this.request('GET', `https://docs.googleapis.com/v1/documents/${encodeURIComponent(documentId)}`, {
|
|
426
|
+
params: {
|
|
427
|
+
includeTabsContent: options.includeTabsContent !== false,
|
|
428
|
+
suggestionsViewMode: options.suggestionsViewMode,
|
|
429
|
+
commentsViewMode: options.commentsViewMode,
|
|
430
|
+
fields: options.fields ?? 'documentId,title,revisionId,tabs(tabProperties(tabId,title,index),documentTab(body(content(paragraph(elements(textRun(content))),table(tableRows(tableCells(content(paragraph(elements(textRun(content)))))))))))',
|
|
431
|
+
},
|
|
432
|
+
signal: options.signal,
|
|
433
|
+
});
|
|
434
|
+
const extracted = extractDocumentContent(data);
|
|
435
|
+
const r = asRecord(data);
|
|
436
|
+
return {
|
|
437
|
+
documentId: asString(r, 'documentId') || documentId,
|
|
438
|
+
title: asString(r, 'title'),
|
|
439
|
+
revisionId: asString(r, 'revisionId'),
|
|
440
|
+
text: extracted.text,
|
|
441
|
+
tabCount: extracted.tabs.length,
|
|
442
|
+
tabs: extracted.tabs,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
async getSpreadsheet(spreadsheetId, options = {}) {
|
|
446
|
+
const data = await this.request('GET', `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(spreadsheetId)}`, {
|
|
447
|
+
params: {
|
|
448
|
+
ranges: options.ranges,
|
|
449
|
+
includeGridData: options.includeGridData,
|
|
450
|
+
excludeTablesInBandedRanges: options.excludeTablesInBandedRanges,
|
|
451
|
+
},
|
|
452
|
+
signal: options.signal,
|
|
453
|
+
});
|
|
454
|
+
return mapSpreadsheet(data);
|
|
455
|
+
}
|
|
456
|
+
async getSheetValues(spreadsheetId, range, options = {}) {
|
|
457
|
+
const data = await this.request('GET', `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(spreadsheetId)}/values/${encodeURIComponent(range)}`, {
|
|
458
|
+
params: {
|
|
459
|
+
valueRenderOption: options.valueRenderOption,
|
|
460
|
+
dateTimeRenderOption: options.dateTimeRenderOption,
|
|
461
|
+
majorDimension: options.majorDimension,
|
|
462
|
+
},
|
|
463
|
+
signal: options.signal,
|
|
464
|
+
});
|
|
465
|
+
return mapSheetValues(data, spreadsheetId, range);
|
|
466
|
+
}
|
|
467
|
+
}
|