@sinoia/hubdoc-tools 1.3.5 → 1.3.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/package.json +3 -4
- package/plugins/alfresco/index.ts +0 -518
- package/plugins/alfresco/plugin.json +0 -12
- package/plugins/aws-s3/index.ts +0 -471
- package/plugins/aws-s3/plugin.json +0 -12
- package/plugins/azure-blob/index.ts +0 -420
- package/plugins/azure-blob/plugin.json +0 -12
- package/plugins/box/index.ts +0 -495
- package/plugins/box/plugin.json +0 -12
- package/plugins/core/README.md +0 -122
- package/plugins/core/TESTING.md +0 -155
- package/plugins/core/index.ts +0 -510
- package/plugins/core/plugin.json +0 -26
- package/plugins/dropbox/index.ts +0 -451
- package/plugins/dropbox/plugin.json +0 -12
- package/plugins/filesystem/index.ts +0 -360
- package/plugins/filesystem/plugin.json +0 -12
- package/plugins/googledrive/index.ts +0 -463
- package/plugins/googledrive/plugin.json +0 -12
- package/plugins/nuxeo/index.ts +0 -512
- package/plugins/nuxeo/plugin.json +0 -12
- package/plugins/onedrive/TESTING.md +0 -197
- package/plugins/onedrive/index.ts +0 -447
- package/plugins/onedrive/plugin.json +0 -12
- package/plugins/opentext/index.ts +0 -542
- package/plugins/opentext/plugin.json +0 -12
- package/plugins/sharepoint/index.ts +0 -509
- package/plugins/sharepoint/plugin.json +0 -12
package/plugins/nuxeo/index.ts
DELETED
|
@@ -1,512 +0,0 @@
|
|
|
1
|
-
import axios, { AxiosInstance } from 'axios';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import {
|
|
5
|
-
DocumentSourcePlugin,
|
|
6
|
-
DocumentSource,
|
|
7
|
-
PluginConfig,
|
|
8
|
-
ScanResult,
|
|
9
|
-
PluginImportOptions,
|
|
10
|
-
PluginExportOptions,
|
|
11
|
-
ImportResult,
|
|
12
|
-
ExportResult
|
|
13
|
-
} from '../../src/types/plugins';
|
|
14
|
-
|
|
15
|
-
interface NuxeoConfig extends PluginConfig {
|
|
16
|
-
baseUrl: string;
|
|
17
|
-
username: string;
|
|
18
|
-
password: string;
|
|
19
|
-
repository?: string; // Default repository name, usually 'default'
|
|
20
|
-
rootPath?: string; // Starting path, defaults to '/default-domain/workspaces'
|
|
21
|
-
limit?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface NuxeoDocument {
|
|
25
|
-
uid: string;
|
|
26
|
-
name: string;
|
|
27
|
-
title: string;
|
|
28
|
-
type: string;
|
|
29
|
-
path: string;
|
|
30
|
-
state: string;
|
|
31
|
-
isFolder: boolean;
|
|
32
|
-
lastModified: string;
|
|
33
|
-
created: string;
|
|
34
|
-
properties: {
|
|
35
|
-
'dc:title': string;
|
|
36
|
-
'dc:description'?: string;
|
|
37
|
-
'dc:creator': string;
|
|
38
|
-
'dc:lastContributor': string;
|
|
39
|
-
'dc:created': string;
|
|
40
|
-
'dc:modified': string;
|
|
41
|
-
'file:content'?: {
|
|
42
|
-
name: string;
|
|
43
|
-
'mime-type': string;
|
|
44
|
-
length: number;
|
|
45
|
-
digest?: string;
|
|
46
|
-
};
|
|
47
|
-
[key: string]: any;
|
|
48
|
-
};
|
|
49
|
-
facets?: string[];
|
|
50
|
-
changeToken?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export default class NuxeoPlugin implements DocumentSourcePlugin {
|
|
54
|
-
readonly name = 'nuxeo';
|
|
55
|
-
readonly version = '1.0.0';
|
|
56
|
-
readonly description = 'Nuxeo ECM document source';
|
|
57
|
-
readonly supportedOperations = ['import', 'export', 'both'] as const;
|
|
58
|
-
|
|
59
|
-
private config?: NuxeoConfig;
|
|
60
|
-
private apiClient?: AxiosInstance;
|
|
61
|
-
|
|
62
|
-
async testConnection(config: PluginConfig): Promise<boolean> {
|
|
63
|
-
try {
|
|
64
|
-
const client = this.createApiClient(config as NuxeoConfig);
|
|
65
|
-
const response = await client.get('/user/Administrator');
|
|
66
|
-
return response.status === 200;
|
|
67
|
-
} catch (error: any) {
|
|
68
|
-
console.error(`Nuxeo connection test failed: ${error.message}`);
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async scan(config: PluginConfig, options?: PluginImportOptions): Promise<ScanResult> {
|
|
74
|
-
this.config = config as NuxeoConfig;
|
|
75
|
-
this.apiClient = this.createApiClient(this.config);
|
|
76
|
-
|
|
77
|
-
const sources: DocumentSource[] = [];
|
|
78
|
-
const errors: string[] = [];
|
|
79
|
-
let totalSize = 0;
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const limit = (this.config as any).limit || (options as any)?.limit;
|
|
83
|
-
console.log(`🔍 Scanning Nuxeo repository${limit ? ` (limit: ${limit})` : ''}...`);
|
|
84
|
-
|
|
85
|
-
const rootPath = this.config.rootPath || '/default-domain/workspaces';
|
|
86
|
-
const documents = await this.scanPath(rootPath);
|
|
87
|
-
|
|
88
|
-
let processedCount = 0;
|
|
89
|
-
for (const doc of documents) {
|
|
90
|
-
if (!doc.isFolder && doc.properties['file:content']) {
|
|
91
|
-
const fileContent = doc.properties['file:content'];
|
|
92
|
-
|
|
93
|
-
const source: DocumentSource = {
|
|
94
|
-
id: doc.uid,
|
|
95
|
-
name: fileContent.name || doc.name,
|
|
96
|
-
path: this.getDocumentPath(doc),
|
|
97
|
-
size: fileContent.length || 0,
|
|
98
|
-
mimeType: fileContent['mime-type'] || 'application/octet-stream',
|
|
99
|
-
lastModified: new Date(doc.properties['dc:modified']),
|
|
100
|
-
metadata: {
|
|
101
|
-
nuxeoUid: doc.uid,
|
|
102
|
-
nuxeoPath: doc.path,
|
|
103
|
-
docType: doc.type,
|
|
104
|
-
title: doc.properties['dc:title'],
|
|
105
|
-
description: doc.properties['dc:description'],
|
|
106
|
-
creator: doc.properties['dc:creator'],
|
|
107
|
-
lastContributor: doc.properties['dc:lastContributor'],
|
|
108
|
-
createdAt: doc.properties['dc:created'],
|
|
109
|
-
state: doc.state,
|
|
110
|
-
facets: doc.facets,
|
|
111
|
-
changeToken: doc.changeToken,
|
|
112
|
-
digest: fileContent.digest
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// Apply filters
|
|
117
|
-
if (this.shouldIncludeSource(source, options)) {
|
|
118
|
-
sources.push(source);
|
|
119
|
-
totalSize += source.size;
|
|
120
|
-
processedCount++;
|
|
121
|
-
|
|
122
|
-
// Check limit
|
|
123
|
-
if (limit && processedCount >= limit) {
|
|
124
|
-
console.log(`📏 Reached limit of ${limit} files`);
|
|
125
|
-
break;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
sources,
|
|
133
|
-
totalCount: sources.length,
|
|
134
|
-
totalSize,
|
|
135
|
-
errors
|
|
136
|
-
};
|
|
137
|
-
} catch (error: any) {
|
|
138
|
-
return {
|
|
139
|
-
sources: [],
|
|
140
|
-
totalCount: 0,
|
|
141
|
-
totalSize: 0,
|
|
142
|
-
errors: [`Nuxeo scan failed: ${error.message}`]
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private async scanPath(docPath: string): Promise<NuxeoDocument[]> {
|
|
148
|
-
if (!this.apiClient) throw new Error('API client not initialized');
|
|
149
|
-
|
|
150
|
-
const allDocuments: NuxeoDocument[] = [];
|
|
151
|
-
let currentPageIndex = 0;
|
|
152
|
-
const pageSize = 100;
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
while (true) {
|
|
156
|
-
// Use NXQL query to get all documents under the specified path
|
|
157
|
-
const query = `SELECT * FROM Document WHERE ecm:path STARTSWITH '${docPath}' AND ecm:isVersion = 0 AND ecm:isTrashed = 0`;
|
|
158
|
-
|
|
159
|
-
const response = await this.apiClient.get('/search/lang/NXQL/execute', {
|
|
160
|
-
params: {
|
|
161
|
-
query: query,
|
|
162
|
-
currentPageIndex: currentPageIndex,
|
|
163
|
-
pageSize: pageSize,
|
|
164
|
-
sortBy: 'dc:title',
|
|
165
|
-
sortOrder: 'ASC'
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
const documents: NuxeoDocument[] = response.data.entries || [];
|
|
170
|
-
|
|
171
|
-
if (documents.length === 0) {
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Process both files and folders
|
|
176
|
-
for (const doc of documents) {
|
|
177
|
-
allDocuments.push(doc);
|
|
178
|
-
|
|
179
|
-
// If it's a folder and has children, we could recursively scan
|
|
180
|
-
// but the STARTSWITH query should already include all descendants
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Check if there are more pages
|
|
184
|
-
if (documents.length < pageSize) {
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
currentPageIndex++;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return allDocuments;
|
|
191
|
-
} catch (error: any) {
|
|
192
|
-
if (error.response?.status === 404) {
|
|
193
|
-
console.warn(`Warning: Path not found: ${docPath}`);
|
|
194
|
-
return [];
|
|
195
|
-
}
|
|
196
|
-
throw error;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async import(
|
|
201
|
-
config: PluginConfig,
|
|
202
|
-
sources: DocumentSource[],
|
|
203
|
-
targetDir: string,
|
|
204
|
-
options?: PluginImportOptions
|
|
205
|
-
): Promise<ImportResult[]> {
|
|
206
|
-
this.config = config as NuxeoConfig;
|
|
207
|
-
this.apiClient = this.createApiClient(this.config);
|
|
208
|
-
|
|
209
|
-
const results: ImportResult[] = [];
|
|
210
|
-
const batchSize = options?.batchSize || 5;
|
|
211
|
-
|
|
212
|
-
// Process in batches to respect API limits
|
|
213
|
-
for (let i = 0; i < sources.length; i += batchSize) {
|
|
214
|
-
const batch = sources.slice(i, i + batchSize);
|
|
215
|
-
|
|
216
|
-
for (const source of batch) {
|
|
217
|
-
const result = await this.importSingle(source, targetDir);
|
|
218
|
-
results.push(result);
|
|
219
|
-
|
|
220
|
-
// Small delay to respect rate limits
|
|
221
|
-
await this.sleep(200);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return results;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private async importSingle(source: DocumentSource, targetDir: string): Promise<ImportResult> {
|
|
229
|
-
try {
|
|
230
|
-
if (!this.apiClient) throw new Error('API client not initialized');
|
|
231
|
-
|
|
232
|
-
const targetPath = path.join(targetDir, source.path);
|
|
233
|
-
const targetDirectory = path.dirname(targetPath);
|
|
234
|
-
|
|
235
|
-
await fs.ensureDir(targetDirectory);
|
|
236
|
-
|
|
237
|
-
// Download file content from Nuxeo using the blob download endpoint
|
|
238
|
-
const response = await this.apiClient.get(`/id/${source.id}/@blob/file:content`, {
|
|
239
|
-
responseType: 'stream'
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
const writer = fs.createWriteStream(targetPath);
|
|
243
|
-
response.data.pipe(writer);
|
|
244
|
-
|
|
245
|
-
return new Promise((resolve) => {
|
|
246
|
-
writer.on('finish', () => {
|
|
247
|
-
resolve({
|
|
248
|
-
success: true,
|
|
249
|
-
source,
|
|
250
|
-
localPath: targetPath,
|
|
251
|
-
bytesTransferred: source.size
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
writer.on('error', (error) => {
|
|
256
|
-
resolve({
|
|
257
|
-
success: false,
|
|
258
|
-
source,
|
|
259
|
-
error: error.message
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
} catch (error: any) {
|
|
264
|
-
return {
|
|
265
|
-
success: false,
|
|
266
|
-
source,
|
|
267
|
-
error: error.message
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async export?(
|
|
273
|
-
config: PluginConfig,
|
|
274
|
-
localSources: DocumentSource[],
|
|
275
|
-
options?: PluginExportOptions
|
|
276
|
-
): Promise<ExportResult[]> {
|
|
277
|
-
this.config = config as NuxeoConfig;
|
|
278
|
-
this.apiClient = this.createApiClient(this.config);
|
|
279
|
-
|
|
280
|
-
const results: ExportResult[] = [];
|
|
281
|
-
const rootPath = this.config.rootPath || '/default-domain/workspaces';
|
|
282
|
-
|
|
283
|
-
for (const source of localSources) {
|
|
284
|
-
try {
|
|
285
|
-
// Determine target path in Nuxeo
|
|
286
|
-
let targetPath = rootPath;
|
|
287
|
-
|
|
288
|
-
if (options?.preserveStructure && source.path.includes('/')) {
|
|
289
|
-
const folderPath = path.dirname(source.path);
|
|
290
|
-
const targetFolderId = await this.createFolderStructure(folderPath, rootPath);
|
|
291
|
-
targetPath = targetFolderId;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Read local file
|
|
295
|
-
const fileContent = await fs.readFile(source.id);
|
|
296
|
-
// Normalize filename to NFC to handle accented characters consistently across platforms
|
|
297
|
-
const fileName = (options?.preserveStructure ? path.basename(source.path) : source.name).normalize('NFC');
|
|
298
|
-
|
|
299
|
-
// Create document in Nuxeo using multipart form data
|
|
300
|
-
const FormData = require('form-data');
|
|
301
|
-
const form = new FormData();
|
|
302
|
-
|
|
303
|
-
// Document metadata
|
|
304
|
-
const docData = {
|
|
305
|
-
'entity-type': 'document',
|
|
306
|
-
type: 'File',
|
|
307
|
-
name: fileName,
|
|
308
|
-
properties: {
|
|
309
|
-
'dc:title': fileName,
|
|
310
|
-
'dc:description': `Uploaded via hubdoc-tools`
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
form.append('entity-type', 'document');
|
|
315
|
-
form.append('type', 'File');
|
|
316
|
-
form.append('name', fileName);
|
|
317
|
-
form.append('properties', JSON.stringify({
|
|
318
|
-
'dc:title': fileName,
|
|
319
|
-
'dc:description': 'Uploaded via hubdoc-tools'
|
|
320
|
-
}));
|
|
321
|
-
|
|
322
|
-
// Attach file
|
|
323
|
-
form.append('file', fileContent, {
|
|
324
|
-
filename: fileName,
|
|
325
|
-
contentType: source.mimeType || 'application/octet-stream'
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
const uploadResponse = await this.apiClient!.post(`/path${targetPath}`, form, {
|
|
329
|
-
headers: {
|
|
330
|
-
...form.getHeaders()
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
const resultTargetPath = options?.preserveStructure ? source.path : source.name;
|
|
335
|
-
|
|
336
|
-
results.push({
|
|
337
|
-
success: true,
|
|
338
|
-
targetPath: resultTargetPath,
|
|
339
|
-
source,
|
|
340
|
-
bytesTransferred: source.size
|
|
341
|
-
});
|
|
342
|
-
} catch (error: any) {
|
|
343
|
-
results.push({
|
|
344
|
-
success: false,
|
|
345
|
-
targetPath: options?.targetPath || '',
|
|
346
|
-
source,
|
|
347
|
-
error: error.message
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return results;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
private async createFolderStructure(folderPath: string, parentPath: string): Promise<string> {
|
|
356
|
-
if (!this.apiClient) throw new Error('API client not initialized');
|
|
357
|
-
|
|
358
|
-
const parts = folderPath.split('/').filter(part => part.length > 0);
|
|
359
|
-
let currentPath = parentPath;
|
|
360
|
-
|
|
361
|
-
for (const folderName of parts) {
|
|
362
|
-
const expectedPath = `${currentPath}/${folderName}`;
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
// Check if folder already exists
|
|
366
|
-
const response = await this.apiClient.get(`/path${expectedPath}`);
|
|
367
|
-
|
|
368
|
-
if (response.data && response.data.type === 'Folder') {
|
|
369
|
-
currentPath = expectedPath;
|
|
370
|
-
continue;
|
|
371
|
-
}
|
|
372
|
-
} catch (error: any) {
|
|
373
|
-
// Folder doesn't exist, create it
|
|
374
|
-
if (error.response?.status === 404) {
|
|
375
|
-
try {
|
|
376
|
-
const createResponse = await this.apiClient.post(`/path${currentPath}`, {
|
|
377
|
-
'entity-type': 'document',
|
|
378
|
-
type: 'Folder',
|
|
379
|
-
name: folderName,
|
|
380
|
-
properties: {
|
|
381
|
-
'dc:title': folderName
|
|
382
|
-
}
|
|
383
|
-
}, {
|
|
384
|
-
headers: {
|
|
385
|
-
'Content-Type': 'application/json'
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
currentPath = expectedPath;
|
|
390
|
-
} catch (createError: any) {
|
|
391
|
-
throw new Error(`Failed to create folder ${folderName}: ${createError.message}`);
|
|
392
|
-
}
|
|
393
|
-
} else {
|
|
394
|
-
throw error;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return currentPath;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
getConfigSchema(): Record<string, any> {
|
|
403
|
-
return {
|
|
404
|
-
type: 'object',
|
|
405
|
-
properties: {
|
|
406
|
-
baseUrl: {
|
|
407
|
-
type: 'string',
|
|
408
|
-
description: 'Nuxeo base URL (e.g., http://localhost:8080/nuxeo)',
|
|
409
|
-
required: true
|
|
410
|
-
},
|
|
411
|
-
username: {
|
|
412
|
-
type: 'string',
|
|
413
|
-
description: 'Nuxeo username',
|
|
414
|
-
required: true
|
|
415
|
-
},
|
|
416
|
-
password: {
|
|
417
|
-
type: 'string',
|
|
418
|
-
description: 'Nuxeo password',
|
|
419
|
-
required: true
|
|
420
|
-
},
|
|
421
|
-
repository: {
|
|
422
|
-
type: 'string',
|
|
423
|
-
description: 'Nuxeo repository name (default: default)',
|
|
424
|
-
default: 'default'
|
|
425
|
-
},
|
|
426
|
-
rootPath: {
|
|
427
|
-
type: 'string',
|
|
428
|
-
description: 'Starting path in Nuxeo (default: /default-domain/workspaces)',
|
|
429
|
-
default: '/default-domain/workspaces'
|
|
430
|
-
},
|
|
431
|
-
limit: {
|
|
432
|
-
type: 'number',
|
|
433
|
-
description: 'Maximum number of documents to scan (useful for testing)',
|
|
434
|
-
required: false
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
required: ['baseUrl', 'username', 'password']
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
async initialize(config: PluginConfig): Promise<void> {
|
|
442
|
-
this.config = config as NuxeoConfig;
|
|
443
|
-
|
|
444
|
-
if (!this.config.baseUrl || !this.config.username || !this.config.password) {
|
|
445
|
-
throw new Error('Nuxeo base URL, username, and password are required');
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
this.apiClient = this.createApiClient(this.config);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
async destroy(): Promise<void> {
|
|
452
|
-
this.config = undefined;
|
|
453
|
-
this.apiClient = undefined;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
private createApiClient(config: NuxeoConfig): AxiosInstance {
|
|
457
|
-
const repository = config.repository || 'default';
|
|
458
|
-
const baseURL = `${config.baseUrl.replace(/\/$/, '')}/api/v1/repo/${repository}`;
|
|
459
|
-
|
|
460
|
-
return axios.create({
|
|
461
|
-
baseURL,
|
|
462
|
-
auth: {
|
|
463
|
-
username: config.username,
|
|
464
|
-
password: config.password
|
|
465
|
-
},
|
|
466
|
-
headers: {
|
|
467
|
-
'Content-Type': 'application/json',
|
|
468
|
-
'Accept': 'application/json'
|
|
469
|
-
},
|
|
470
|
-
timeout: 30000
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
private getDocumentPath(doc: NuxeoDocument): string {
|
|
475
|
-
// Remove the repository-specific prefix from the path
|
|
476
|
-
let cleanPath = doc.path.replace(/^\/default-domain\/workspaces\//, '');
|
|
477
|
-
|
|
478
|
-
// If the document has a file content, use the file name
|
|
479
|
-
if (doc.properties['file:content']?.name) {
|
|
480
|
-
const pathParts = cleanPath.split('/');
|
|
481
|
-
pathParts[pathParts.length - 1] = doc.properties['file:content'].name;
|
|
482
|
-
cleanPath = pathParts.join('/');
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
return cleanPath || doc.name;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
private shouldIncludeSource(source: DocumentSource, options?: PluginImportOptions): boolean {
|
|
489
|
-
// Apply size filter
|
|
490
|
-
if (options?.filters?.maxSize && source.size > options.filters.maxSize) {
|
|
491
|
-
return false;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Apply date range filter
|
|
495
|
-
if (options?.filters?.dateRange) {
|
|
496
|
-
const { from, to } = options.filters.dateRange;
|
|
497
|
-
if (from && source.lastModified < from) return false;
|
|
498
|
-
if (to && source.lastModified > to) return false;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// Apply MIME type filter
|
|
502
|
-
if (options?.filters?.mimeTypes && !options.filters.mimeTypes.includes(source.mimeType)) {
|
|
503
|
-
return false;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return true;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
private sleep(ms: number): Promise<void> {
|
|
510
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
511
|
-
}
|
|
512
|
-
}
|