unrag 0.2.5 → 0.2.7
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/dist/cli/index.js +611 -174
- package/package.json +12 -6
- package/registry/config/unrag.config.ts +9 -8
- package/registry/connectors/google-drive/_api-types.ts +60 -0
- package/registry/connectors/google-drive/client.ts +99 -38
- package/registry/connectors/google-drive/sync.ts +97 -69
- package/registry/connectors/google-drive/types.ts +76 -37
- package/registry/connectors/notion/client.ts +12 -3
- package/registry/connectors/notion/render.ts +62 -23
- package/registry/connectors/notion/sync.ts +30 -23
- package/registry/core/assets.ts +11 -10
- package/registry/core/config.ts +10 -25
- package/registry/core/context-engine.ts +71 -2
- package/registry/core/deep-merge.ts +45 -0
- package/registry/core/ingest.ts +117 -44
- package/registry/core/types.ts +96 -2
- package/registry/docs/unrag.md +6 -1
- package/registry/embedding/_shared.ts +25 -0
- package/registry/embedding/ai.ts +8 -68
- package/registry/embedding/azure.ts +88 -0
- package/registry/embedding/bedrock.ts +88 -0
- package/registry/embedding/cohere.ts +88 -0
- package/registry/embedding/google.ts +102 -0
- package/registry/embedding/mistral.ts +71 -0
- package/registry/embedding/ollama.ts +90 -0
- package/registry/embedding/openai.ts +88 -0
- package/registry/embedding/openrouter.ts +127 -0
- package/registry/embedding/together.ts +77 -0
- package/registry/embedding/vertex.ts +111 -0
- package/registry/embedding/voyage.ts +169 -0
- package/registry/extractors/audio-transcribe/index.ts +39 -23
- package/registry/extractors/file-docx/index.ts +8 -1
- package/registry/extractors/file-pptx/index.ts +22 -1
- package/registry/extractors/file-xlsx/index.ts +24 -1
- package/registry/extractors/image-caption-llm/index.ts +8 -3
- package/registry/extractors/image-ocr/index.ts +9 -4
- package/registry/extractors/pdf-llm/index.ts +9 -4
- package/registry/extractors/pdf-text-layer/index.ts +23 -2
- package/registry/extractors/video-frames/index.ts +8 -3
- package/registry/extractors/video-transcribe/index.ts +40 -24
- package/registry/manifest.json +346 -0
- package/registry/store/drizzle-postgres-pgvector/store.ts +26 -6
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { IngestResult } from "../../core";
|
|
1
|
+
import type { IngestResult, Metadata } from "../../core";
|
|
2
2
|
import type { AssetInput } from "../../core/types";
|
|
3
|
+
import type { DriveClient, DriveFile } from "./_api-types";
|
|
3
4
|
import { createGoogleDriveClient } from "./client";
|
|
4
5
|
import {
|
|
5
6
|
assetKindFromMediaType,
|
|
@@ -17,6 +18,25 @@ import type {
|
|
|
17
18
|
|
|
18
19
|
const DEFAULT_MAX_BYTES = 15 * 1024 * 1024; // 15MB
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Internal metadata type for Google Drive documents.
|
|
23
|
+
*/
|
|
24
|
+
interface GoogleDriveMetadata extends Metadata {
|
|
25
|
+
connector: "google-drive";
|
|
26
|
+
kind: "file" | "folder" | "shortcut";
|
|
27
|
+
fileId: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
mimeType?: string;
|
|
30
|
+
size?: number;
|
|
31
|
+
googleNativeKind?: string;
|
|
32
|
+
unsupportedGoogleMime?: boolean;
|
|
33
|
+
skippedTooLarge?: boolean;
|
|
34
|
+
exportedTooLarge?: boolean;
|
|
35
|
+
shortcutUnresolved?: boolean;
|
|
36
|
+
exportMimeType?: string;
|
|
37
|
+
exportFallback?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
20
40
|
const joinPrefix = (prefix: string | undefined, rest: string) => {
|
|
21
41
|
const p = (prefix ?? "").trim();
|
|
22
42
|
if (!p) return rest;
|
|
@@ -44,10 +64,10 @@ const asMessage = (err: unknown) => {
|
|
|
44
64
|
}
|
|
45
65
|
};
|
|
46
66
|
|
|
47
|
-
const toUint8Array = (data:
|
|
67
|
+
const toUint8Array = (data: unknown): Uint8Array => {
|
|
48
68
|
if (!data) return new Uint8Array();
|
|
49
69
|
if (data instanceof Uint8Array) return data;
|
|
50
|
-
if (typeof Buffer !== "undefined" && data
|
|
70
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
51
71
|
return new Uint8Array(data);
|
|
52
72
|
}
|
|
53
73
|
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
@@ -61,51 +81,54 @@ const toUint8Array = (data: any): Uint8Array => {
|
|
|
61
81
|
return new Uint8Array();
|
|
62
82
|
};
|
|
63
83
|
|
|
64
|
-
const bytesToText = (bytes: Uint8Array) => {
|
|
84
|
+
const bytesToText = (bytes: Uint8Array): string => {
|
|
65
85
|
return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
66
86
|
};
|
|
67
87
|
|
|
68
|
-
const isNotFound = (err:
|
|
88
|
+
const isNotFound = (err: unknown, treatForbiddenAsNotFound: boolean): boolean => {
|
|
89
|
+
if (typeof err !== "object" || err === null) return false;
|
|
90
|
+
const e = err as Record<string, unknown>;
|
|
91
|
+
const response = e.response as Record<string, unknown> | undefined;
|
|
69
92
|
const status =
|
|
70
|
-
Number(
|
|
71
|
-
Number(err?.response?.status);
|
|
93
|
+
Number(e.code ?? e.status ?? response?.status ?? e.statusCode ?? 0);
|
|
72
94
|
if (status === 404) return true;
|
|
73
95
|
if (treatForbiddenAsNotFound && status === 403) return true;
|
|
74
96
|
return false;
|
|
75
97
|
};
|
|
76
98
|
|
|
77
|
-
async function getFileMetadata(drive:
|
|
99
|
+
async function getFileMetadata(drive: DriveClient, fileId: string): Promise<DriveFile> {
|
|
78
100
|
const res = await drive.files.get({
|
|
79
101
|
fileId,
|
|
80
102
|
supportsAllDrives: true,
|
|
81
103
|
fields:
|
|
82
104
|
"id,name,mimeType,size,md5Checksum,modifiedTime,webViewLink,webContentLink,iconLink,shortcutDetails,driveId",
|
|
83
105
|
});
|
|
84
|
-
return res?.data ?? {};
|
|
106
|
+
return (res?.data ?? {}) as DriveFile;
|
|
85
107
|
}
|
|
86
108
|
|
|
87
|
-
async function downloadFileBytes(drive:
|
|
88
|
-
const res = await drive.files.get(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
async function downloadFileBytes(drive: DriveClient, fileId: string): Promise<Uint8Array> {
|
|
110
|
+
const res = await drive.files.get({
|
|
111
|
+
fileId,
|
|
112
|
+
alt: "media",
|
|
113
|
+
supportsAllDrives: true,
|
|
114
|
+
});
|
|
92
115
|
return toUint8Array(res?.data);
|
|
93
116
|
}
|
|
94
117
|
|
|
95
118
|
async function exportFileBytes(
|
|
96
|
-
drive:
|
|
119
|
+
drive: DriveClient,
|
|
97
120
|
fileId: string,
|
|
98
121
|
mimeType: string
|
|
99
122
|
): Promise<Uint8Array> {
|
|
100
|
-
const res = await drive.files.export(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
);
|
|
123
|
+
const res = await drive.files.export({
|
|
124
|
+
fileId,
|
|
125
|
+
mimeType,
|
|
126
|
+
});
|
|
104
127
|
return toUint8Array(res?.data);
|
|
105
128
|
}
|
|
106
129
|
|
|
107
130
|
export async function loadGoogleDriveFileDocument(args: {
|
|
108
|
-
drive:
|
|
131
|
+
drive: DriveClient;
|
|
109
132
|
fileId: string;
|
|
110
133
|
sourceIdPrefix?: string;
|
|
111
134
|
options?: {
|
|
@@ -128,21 +151,22 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
128
151
|
|
|
129
152
|
// Handle folders: return a document shape but with no content/assets; callers typically skip.
|
|
130
153
|
if (classification.kind === "folder") {
|
|
154
|
+
const folderMetadata: GoogleDriveMetadata = {
|
|
155
|
+
connector: "google-drive",
|
|
156
|
+
kind: "folder",
|
|
157
|
+
fileId,
|
|
158
|
+
name,
|
|
159
|
+
mimeType: DRIVE_MIME.folder,
|
|
160
|
+
...(meta?.webViewLink ? { webViewLink: String(meta.webViewLink) } : {}),
|
|
161
|
+
...(meta?.modifiedTime ? { modifiedTime: String(meta.modifiedTime) } : {}),
|
|
162
|
+
};
|
|
131
163
|
return buildGoogleDriveFileIngestInput({
|
|
132
164
|
fileId,
|
|
133
165
|
sourceIdPrefix: args.sourceIdPrefix,
|
|
134
166
|
content: "",
|
|
135
167
|
assets: [],
|
|
136
|
-
metadata:
|
|
137
|
-
|
|
138
|
-
kind: "folder",
|
|
139
|
-
fileId,
|
|
140
|
-
name,
|
|
141
|
-
mimeType: DRIVE_MIME.folder,
|
|
142
|
-
...(meta?.webViewLink ? { webViewLink: String(meta.webViewLink) } : {}),
|
|
143
|
-
...(meta?.modifiedTime ? { modifiedTime: String(meta.modifiedTime) } : {}),
|
|
144
|
-
},
|
|
145
|
-
}) as any;
|
|
168
|
+
metadata: folderMetadata,
|
|
169
|
+
});
|
|
146
170
|
}
|
|
147
171
|
|
|
148
172
|
// Shortcuts: resolve to target if possible (1-level), otherwise let caller decide.
|
|
@@ -150,20 +174,21 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
150
174
|
const visited = args._visited ?? new Set<string>();
|
|
151
175
|
if (visited.has(fileId)) {
|
|
152
176
|
// cycle
|
|
177
|
+
const cycleMetadata: GoogleDriveMetadata = {
|
|
178
|
+
connector: "google-drive",
|
|
179
|
+
kind: "shortcut",
|
|
180
|
+
fileId,
|
|
181
|
+
name,
|
|
182
|
+
mimeType: DRIVE_MIME.shortcut,
|
|
183
|
+
shortcutUnresolved: true,
|
|
184
|
+
};
|
|
153
185
|
return buildGoogleDriveFileIngestInput({
|
|
154
186
|
fileId,
|
|
155
187
|
sourceIdPrefix: args.sourceIdPrefix,
|
|
156
188
|
content: "",
|
|
157
189
|
assets: [],
|
|
158
|
-
metadata:
|
|
159
|
-
|
|
160
|
-
kind: "shortcut",
|
|
161
|
-
fileId,
|
|
162
|
-
name,
|
|
163
|
-
mimeType: DRIVE_MIME.shortcut,
|
|
164
|
-
shortcutUnresolved: true,
|
|
165
|
-
},
|
|
166
|
-
}) as any;
|
|
190
|
+
metadata: cycleMetadata,
|
|
191
|
+
});
|
|
167
192
|
}
|
|
168
193
|
visited.add(fileId);
|
|
169
194
|
|
|
@@ -172,20 +197,21 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
172
197
|
: "";
|
|
173
198
|
|
|
174
199
|
if (!targetId) {
|
|
200
|
+
const unresolvedMetadata: GoogleDriveMetadata = {
|
|
201
|
+
connector: "google-drive",
|
|
202
|
+
kind: "shortcut",
|
|
203
|
+
fileId,
|
|
204
|
+
name,
|
|
205
|
+
mimeType: DRIVE_MIME.shortcut,
|
|
206
|
+
shortcutUnresolved: true,
|
|
207
|
+
};
|
|
175
208
|
return buildGoogleDriveFileIngestInput({
|
|
176
209
|
fileId,
|
|
177
210
|
sourceIdPrefix: args.sourceIdPrefix,
|
|
178
211
|
content: "",
|
|
179
212
|
assets: [],
|
|
180
|
-
metadata:
|
|
181
|
-
|
|
182
|
-
kind: "shortcut",
|
|
183
|
-
fileId,
|
|
184
|
-
name,
|
|
185
|
-
mimeType: DRIVE_MIME.shortcut,
|
|
186
|
-
shortcutUnresolved: true,
|
|
187
|
-
},
|
|
188
|
-
}) as any;
|
|
213
|
+
metadata: unresolvedMetadata,
|
|
214
|
+
});
|
|
189
215
|
}
|
|
190
216
|
|
|
191
217
|
// Resolve target content/assets but keep sourceId stable to the shortcut file id.
|
|
@@ -209,7 +235,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
209
235
|
};
|
|
210
236
|
}
|
|
211
237
|
|
|
212
|
-
const baseMetadata = {
|
|
238
|
+
const baseMetadata: Record<string, unknown> = {
|
|
213
239
|
connector: "google-drive",
|
|
214
240
|
kind: "file",
|
|
215
241
|
fileId,
|
|
@@ -222,7 +248,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
222
248
|
...(meta?.webContentLink ? { webContentLink: String(meta.webContentLink) } : {}),
|
|
223
249
|
...(meta?.iconLink ? { iconLink: String(meta.iconLink) } : {}),
|
|
224
250
|
...(meta?.driveId ? { driveId: String(meta.driveId) } : {}),
|
|
225
|
-
}
|
|
251
|
+
};
|
|
226
252
|
|
|
227
253
|
// Google-native export path
|
|
228
254
|
if (classification.kind === "google_native") {
|
|
@@ -238,7 +264,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
238
264
|
googleNativeKind: classification.nativeKind,
|
|
239
265
|
unsupportedGoogleMime: true,
|
|
240
266
|
},
|
|
241
|
-
})
|
|
267
|
+
});
|
|
242
268
|
}
|
|
243
269
|
|
|
244
270
|
// For content export, enforce maxBytesPerFile by bytes length.
|
|
@@ -252,7 +278,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
252
278
|
content: "",
|
|
253
279
|
assets: [],
|
|
254
280
|
metadata: { ...baseMetadata, exportedTooLarge: true },
|
|
255
|
-
})
|
|
281
|
+
});
|
|
256
282
|
}
|
|
257
283
|
const content = bytesToText(bytes).trim();
|
|
258
284
|
return buildGoogleDriveFileIngestInput({
|
|
@@ -261,7 +287,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
261
287
|
content,
|
|
262
288
|
assets: [],
|
|
263
289
|
metadata: { ...baseMetadata, googleNativeKind: classification.nativeKind, exportMimeType: plan.mimeType },
|
|
264
|
-
})
|
|
290
|
+
});
|
|
265
291
|
} catch (err) {
|
|
266
292
|
// Slides can fail to export as text; fallback to PPTX unless strict.
|
|
267
293
|
if (classification.nativeKind === "slides" && !strictNativeExport) {
|
|
@@ -274,7 +300,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
274
300
|
content: "",
|
|
275
301
|
assets: [],
|
|
276
302
|
metadata: { ...baseMetadata, exportedTooLarge: true },
|
|
277
|
-
})
|
|
303
|
+
});
|
|
278
304
|
}
|
|
279
305
|
const asset: AssetInput = {
|
|
280
306
|
assetId: fileId,
|
|
@@ -286,7 +312,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
286
312
|
filename: name ? `${name}.pptx` : undefined,
|
|
287
313
|
},
|
|
288
314
|
uri: meta?.webViewLink ? String(meta.webViewLink) : undefined,
|
|
289
|
-
metadata: { connector: "google-drive", fileId, exportMimeType: EXPORT_MIME.pptx }
|
|
315
|
+
metadata: { connector: "google-drive", fileId, exportMimeType: EXPORT_MIME.pptx },
|
|
290
316
|
};
|
|
291
317
|
return buildGoogleDriveFileIngestInput({
|
|
292
318
|
fileId,
|
|
@@ -294,7 +320,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
294
320
|
content: "",
|
|
295
321
|
assets: [asset],
|
|
296
322
|
metadata: { ...baseMetadata, googleNativeKind: "slides", exportFallback: "pptx" },
|
|
297
|
-
})
|
|
323
|
+
});
|
|
298
324
|
} catch {
|
|
299
325
|
// fall through to strict error
|
|
300
326
|
}
|
|
@@ -314,7 +340,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
314
340
|
content: "",
|
|
315
341
|
assets: [],
|
|
316
342
|
metadata: { ...baseMetadata, exportedTooLarge: true },
|
|
317
|
-
})
|
|
343
|
+
});
|
|
318
344
|
}
|
|
319
345
|
|
|
320
346
|
const filename = name && plan.filenameExt ? `${name}.${plan.filenameExt}` : name || undefined;
|
|
@@ -323,7 +349,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
323
349
|
kind: plan.assetKind,
|
|
324
350
|
data: { kind: "bytes", bytes, mediaType: plan.mimeType, ...(filename ? { filename } : {}) },
|
|
325
351
|
uri: meta?.webViewLink ? String(meta.webViewLink) : undefined,
|
|
326
|
-
metadata: { connector: "google-drive", fileId, exportMimeType: plan.mimeType }
|
|
352
|
+
metadata: { connector: "google-drive", fileId, exportMimeType: plan.mimeType },
|
|
327
353
|
};
|
|
328
354
|
|
|
329
355
|
return buildGoogleDriveFileIngestInput({
|
|
@@ -332,7 +358,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
332
358
|
content: "",
|
|
333
359
|
assets: [asset],
|
|
334
360
|
metadata: { ...baseMetadata, googleNativeKind: classification.nativeKind, exportMimeType: plan.mimeType },
|
|
335
|
-
})
|
|
361
|
+
});
|
|
336
362
|
}
|
|
337
363
|
}
|
|
338
364
|
|
|
@@ -344,7 +370,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
344
370
|
content: "",
|
|
345
371
|
assets: [],
|
|
346
372
|
metadata: { ...baseMetadata, skippedTooLarge: true },
|
|
347
|
-
})
|
|
373
|
+
});
|
|
348
374
|
}
|
|
349
375
|
|
|
350
376
|
const bytes = await downloadFileBytes(args.drive, fileId);
|
|
@@ -355,7 +381,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
355
381
|
content: "",
|
|
356
382
|
assets: [],
|
|
357
383
|
metadata: { ...baseMetadata, skippedTooLarge: true },
|
|
358
|
-
})
|
|
384
|
+
});
|
|
359
385
|
}
|
|
360
386
|
|
|
361
387
|
const assetKind = assetKindFromMediaType(mimeType);
|
|
@@ -370,7 +396,7 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
370
396
|
...(filename ? { filename } : {}),
|
|
371
397
|
},
|
|
372
398
|
uri: meta?.webViewLink ? String(meta.webViewLink) : undefined,
|
|
373
|
-
metadata: { connector: "google-drive", fileId, name, mimeType }
|
|
399
|
+
metadata: { connector: "google-drive", fileId, name, mimeType },
|
|
374
400
|
};
|
|
375
401
|
|
|
376
402
|
// For pure binaries, keep content empty; extraction occurs via engine asset processing + extractors.
|
|
@@ -379,8 +405,8 @@ export async function loadGoogleDriveFileDocument(args: {
|
|
|
379
405
|
sourceIdPrefix: args.sourceIdPrefix,
|
|
380
406
|
content: "",
|
|
381
407
|
assets: [asset],
|
|
382
|
-
metadata: baseMetadata
|
|
383
|
-
})
|
|
408
|
+
metadata: baseMetadata,
|
|
409
|
+
});
|
|
384
410
|
}
|
|
385
411
|
|
|
386
412
|
export async function syncGoogleDriveFiles(
|
|
@@ -434,8 +460,10 @@ export async function syncGoogleDriveFiles(
|
|
|
434
460
|
},
|
|
435
461
|
});
|
|
436
462
|
|
|
463
|
+
const meta = doc.metadata as Record<string, unknown>;
|
|
464
|
+
|
|
437
465
|
// Skip folders explicitly (v1).
|
|
438
|
-
if (
|
|
466
|
+
if (meta.kind === "folder") {
|
|
439
467
|
emit({
|
|
440
468
|
type: "file:skipped",
|
|
441
469
|
fileId,
|
|
@@ -446,7 +474,7 @@ export async function syncGoogleDriveFiles(
|
|
|
446
474
|
continue;
|
|
447
475
|
}
|
|
448
476
|
|
|
449
|
-
if (
|
|
477
|
+
if (meta.unsupportedGoogleMime) {
|
|
450
478
|
emit({
|
|
451
479
|
type: "file:skipped",
|
|
452
480
|
fileId,
|
|
@@ -458,7 +486,7 @@ export async function syncGoogleDriveFiles(
|
|
|
458
486
|
continue;
|
|
459
487
|
}
|
|
460
488
|
|
|
461
|
-
if (
|
|
489
|
+
if (meta.skippedTooLarge || meta.exportedTooLarge) {
|
|
462
490
|
emit({
|
|
463
491
|
type: "file:skipped",
|
|
464
492
|
fileId,
|
|
@@ -469,7 +497,7 @@ export async function syncGoogleDriveFiles(
|
|
|
469
497
|
continue;
|
|
470
498
|
}
|
|
471
499
|
|
|
472
|
-
if (
|
|
500
|
+
if (meta.shortcutUnresolved) {
|
|
473
501
|
emit({
|
|
474
502
|
type: "file:skipped",
|
|
475
503
|
fileId,
|
|
@@ -484,7 +512,7 @@ export async function syncGoogleDriveFiles(
|
|
|
484
512
|
sourceId: doc.sourceId,
|
|
485
513
|
content: doc.content,
|
|
486
514
|
assets: doc.assets,
|
|
487
|
-
metadata: doc.metadata
|
|
515
|
+
metadata: doc.metadata,
|
|
488
516
|
});
|
|
489
517
|
|
|
490
518
|
succeeded += 1;
|
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
import type { ContextEngine, AssetInput, IngestInput } from "../../core";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Service account credentials structure.
|
|
5
|
+
*/
|
|
6
|
+
export interface ServiceAccountCredentials {
|
|
7
|
+
client_email: string;
|
|
8
|
+
private_key: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* OAuth auth with an existing client instance.
|
|
14
|
+
*/
|
|
15
|
+
export type GoogleDriveOAuthClientAuth = {
|
|
16
|
+
/** Use an existing OAuth2 client instance (recommended if your app already has one). */
|
|
17
|
+
kind: "oauth";
|
|
18
|
+
oauthClient: unknown;
|
|
19
|
+
clientId?: never;
|
|
20
|
+
clientSecret?: never;
|
|
21
|
+
redirectUri?: never;
|
|
22
|
+
refreshToken?: never;
|
|
23
|
+
accessToken?: never;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* OAuth auth with credentials for building a client.
|
|
28
|
+
*/
|
|
29
|
+
export type GoogleDriveOAuthConfigAuth = {
|
|
30
|
+
/**
|
|
31
|
+
* Convenience form for OAuth2: the connector will construct an OAuth2 client
|
|
32
|
+
* and set credentials including the refresh token.
|
|
33
|
+
*/
|
|
34
|
+
kind: "oauth";
|
|
35
|
+
clientId: string;
|
|
36
|
+
clientSecret: string;
|
|
37
|
+
redirectUri: string;
|
|
38
|
+
refreshToken: string;
|
|
39
|
+
/** Optional access token if you already have one. */
|
|
40
|
+
accessToken?: string;
|
|
41
|
+
oauthClient?: never;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* OAuth auth (either form).
|
|
46
|
+
*/
|
|
47
|
+
export type GoogleDriveOAuthAuth = GoogleDriveOAuthClientAuth | GoogleDriveOAuthConfigAuth;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Service account auth.
|
|
51
|
+
*/
|
|
52
|
+
export type GoogleDriveServiceAccountAuth = {
|
|
53
|
+
/**
|
|
54
|
+
* Service account credentials. This supports both:
|
|
55
|
+
* - direct service-account access (files must be shared to the service account)
|
|
56
|
+
* - Workspace domain-wide delegation (DWD) when `subject` is provided
|
|
57
|
+
*/
|
|
58
|
+
kind: "service_account";
|
|
59
|
+
credentialsJson: string | ServiceAccountCredentials;
|
|
60
|
+
/**
|
|
61
|
+
* DWD impersonation subject email (Workspace only).
|
|
62
|
+
* When provided, the service account will impersonate this user.
|
|
63
|
+
*/
|
|
64
|
+
subject?: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Google Auth escape hatch.
|
|
69
|
+
*/
|
|
70
|
+
export type GoogleDriveGoogleAuthAuth = {
|
|
71
|
+
/** Escape hatch: provide a pre-configured GoogleAuth (or equivalent) instance. */
|
|
72
|
+
kind: "google_auth";
|
|
73
|
+
auth: unknown;
|
|
74
|
+
};
|
|
75
|
+
|
|
3
76
|
/**
|
|
4
77
|
* A plug-and-play auth input for Google Drive.
|
|
5
78
|
*
|
|
@@ -8,43 +81,9 @@ import type { ContextEngine, AssetInput, IngestInput } from "../../core";
|
|
|
8
81
|
* by the CLI (`unrag add google-drive`).
|
|
9
82
|
*/
|
|
10
83
|
export type GoogleDriveAuth =
|
|
11
|
-
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
oauthClient: unknown;
|
|
15
|
-
}
|
|
16
|
-
| {
|
|
17
|
-
/**
|
|
18
|
-
* Convenience form for OAuth2: the connector will construct an OAuth2 client
|
|
19
|
-
* and set credentials including the refresh token.
|
|
20
|
-
*/
|
|
21
|
-
kind: "oauth";
|
|
22
|
-
clientId: string;
|
|
23
|
-
clientSecret: string;
|
|
24
|
-
redirectUri: string;
|
|
25
|
-
refreshToken: string;
|
|
26
|
-
/** Optional access token if you already have one. */
|
|
27
|
-
accessToken?: string;
|
|
28
|
-
}
|
|
29
|
-
| {
|
|
30
|
-
/**
|
|
31
|
-
* Service account credentials. This supports both:
|
|
32
|
-
* - direct service-account access (files must be shared to the service account)
|
|
33
|
-
* - Workspace domain-wide delegation (DWD) when `subject` is provided
|
|
34
|
-
*/
|
|
35
|
-
kind: "service_account";
|
|
36
|
-
credentialsJson: string | Record<string, unknown>;
|
|
37
|
-
/**
|
|
38
|
-
* DWD impersonation subject email (Workspace only).
|
|
39
|
-
* When provided, the service account will impersonate this user.
|
|
40
|
-
*/
|
|
41
|
-
subject?: string;
|
|
42
|
-
}
|
|
43
|
-
| {
|
|
44
|
-
/** Escape hatch: provide a pre-configured GoogleAuth (or equivalent) instance. */
|
|
45
|
-
kind: "google_auth";
|
|
46
|
-
auth: unknown;
|
|
47
|
-
};
|
|
84
|
+
| GoogleDriveOAuthAuth
|
|
85
|
+
| GoogleDriveServiceAccountAuth
|
|
86
|
+
| GoogleDriveGoogleAuthAuth;
|
|
48
87
|
|
|
49
88
|
export type GoogleDriveSyncProgressEvent =
|
|
50
89
|
| { type: "file:start"; fileId: string; sourceId: string }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Client } from "@notionhq/client";
|
|
1
|
+
import { Client, type ClientOptions } from "@notionhq/client";
|
|
2
2
|
|
|
3
3
|
export type NotionClient = Client;
|
|
4
4
|
|
|
@@ -7,16 +7,25 @@ export type CreateNotionClientInput = {
|
|
|
7
7
|
timeoutMs?: number;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Extended client options that include timeoutMs (supported by @notionhq/client).
|
|
12
|
+
*/
|
|
13
|
+
type NotionClientOptions = ClientOptions & {
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
10
17
|
export function createNotionClient(input: CreateNotionClientInput): NotionClient {
|
|
11
18
|
const token = input.token?.trim();
|
|
12
19
|
if (!token) throw new Error("NOTION token is required");
|
|
13
20
|
|
|
14
|
-
|
|
21
|
+
const options: NotionClientOptions = {
|
|
15
22
|
auth: token,
|
|
16
23
|
// @notionhq/client uses undici/fetch under the hood; timeout is supported.
|
|
17
24
|
// If unsupported in a future version, callers can wrap requests.
|
|
18
25
|
timeoutMs: input.timeoutMs ?? 30_000,
|
|
19
|
-
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return new Client(options);
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
|