@cocreate/file 1.19.6 → 1.21.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/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ # [1.21.0](https://github.com/CoCreate-app/CoCreate-file/compare/v1.20.0...v1.21.0) (2025-11-16)
2
+
3
+
4
+ ### Features
5
+
6
+ * enhance file processing by adding support for include/exclude filters and implementing dynamic data retrieval for various file types ([d8a2185](https://github.com/CoCreate-app/CoCreate-file/commit/d8a2185ce6f9554aa929f285e24526a281bc0b96))
7
+
8
+ # [1.20.0](https://github.com/CoCreate-app/CoCreate-file/compare/v1.19.6...v1.20.0) (2025-10-11)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * add error handling for translation service in file function ([262dc66](https://github.com/CoCreate-app/CoCreate-file/commit/262dc66d57c13a8948ef1afa863413c203f965bc))
14
+ * update import statement and modify exit behavior in server function ([6e72fde](https://github.com/CoCreate-app/CoCreate-file/commit/6e72fdec3867c031e342b3faef598b661f43a620))
15
+
16
+
17
+ ### Features
18
+
19
+ * add options parameter to file function for enhanced translation support ([7fac13d](https://github.com/CoCreate-app/CoCreate-file/commit/7fac13d10b8abd40584d5abc6b89d110f84db288))
20
+ * enhance file handling by supporting base64 encoding for binary sources and improving file reading logic ([192337c](https://github.com/CoCreate-app/CoCreate-file/commit/192337c3a44d412f8a8d2c6bb1172451661eebf5))
21
+ * enhance file processing with support for base64 and binary types, and add variable processing functionality ([eabfddf](https://github.com/CoCreate-app/CoCreate-file/commit/eabfddf2e1c36e7abd330369c1f28f90290cc1b8))
22
+
1
23
  ## [1.19.6](https://github.com/CoCreate-app/CoCreate-file/compare/v1.19.5...v1.19.6) (2025-09-07)
2
24
 
3
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/file",
3
- "version": "1.19.6",
3
+ "version": "1.21.0",
4
4
  "description": "A versatile, configurable headless file uploader supporting local and server operations. Accessible via a JavaScript API and HTML5 attributes, it provides seamless file reading, writing, and uploading with fallbacks to the standard HTML5 file input API. Ideal for developers needing robust file management in headless environments.",
5
5
  "keywords": [
6
6
  "file-uploader",
package/src/client.js CHANGED
@@ -28,7 +28,7 @@ import Elements from "@cocreate/elements";
28
28
  import Actions from "@cocreate/actions";
29
29
  import { render } from "@cocreate/render";
30
30
  import { queryElements } from "@cocreate/utils";
31
- import "@cocreate/element-prototype";
31
+ import { setValue } from "@cocreate/element-prototype";
32
32
 
33
33
  const inputs = new Map();
34
34
  const Files = new Map();
package/src/server.js CHANGED
@@ -4,6 +4,7 @@ const fs = require("fs");
4
4
  const realpathAsync = fs.promises.realpath;
5
5
 
6
6
  const path = require("path");
7
+ const { pathToFileURL } = require("url");
7
8
  const mimeTypes = {
8
9
  ".aac": "audio/aac",
9
10
  ".abw": "application/x-abiword",
@@ -83,7 +84,12 @@ const mimeTypes = {
83
84
  ".7z": "application/x-7z-compressed"
84
85
  };
85
86
 
86
- module.exports = async function file(CoCreateConfig, configPath, match) {
87
+ module.exports = async function file(
88
+ CoCreateConfig,
89
+ configPath,
90
+ match,
91
+ options
92
+ ) {
87
93
  let directories = CoCreateConfig.directories;
88
94
  let sources = CoCreateConfig.sources;
89
95
  let configDirectoryPath = path.dirname(configPath);
@@ -169,46 +175,60 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
169
175
  async function runDirectories() {
170
176
  for (const directory of directories) {
171
177
  const entry = directory.entry;
172
- const exclude = directory.exclude || [];
173
- await runFiles(directory, entry, exclude);
178
+ await runFiles(directory, entry);
174
179
  }
175
180
  return;
176
181
  }
177
182
 
178
- async function runFiles(directory, entry, exclude, Path, directoryName) {
183
+ async function runFiles(directory, entry, Path, directoryName) {
179
184
  const entryPath = path.resolve(configDirectoryPath, entry);
180
185
  let files = fs.readdirSync(entryPath);
181
-
186
+ let exclude = directory.exclude || [];
187
+ let include = directory.include || [];
182
188
  for (let file of files) {
183
- let skip = false;
184
- for (let i = 0; i < exclude.length; i++) {
185
- if (file.includes(exclude[i])) {
186
- skip = true;
187
- break;
188
- }
189
- }
190
- if (skip) continue;
189
+ const filePath = path.resolve(entryPath, file);
191
190
 
192
191
  let isDirectory;
193
192
  let isSymlink = fs
194
- .lstatSync(`${entryPath}/${file}`)
193
+ .lstatSync(filePath)
195
194
  .isSymbolicLink();
196
195
  if (isSymlink) {
197
- let symlinkPath = await realpathAsync(`${entryPath}/${file}`);
196
+ let symlinkPath = await realpathAsync(filePath);
198
197
  isDirectory =
199
198
  fs.existsSync(symlinkPath) &&
200
199
  fs.lstatSync(symlinkPath).isDirectory();
201
200
  } else
202
201
  isDirectory =
203
- fs.existsSync(`${entryPath}/${file}`) &&
204
- fs.lstatSync(`${entryPath}/${file}`).isDirectory();
202
+ fs.existsSync(filePath) &&
203
+ fs.lstatSync(filePath).isDirectory();
204
+
205
+ let skip = false;
206
+ for (let i = 0; i < exclude.length; i++) {
207
+ if (filePath.includes(exclude[i])) {
208
+ skip = true;
209
+ break;
210
+ }
211
+ }
212
+
213
+ for (let i = 0; i < include.length; i++) {
214
+ if (filePath.includes(include[i])) {
215
+ skip = false;
216
+ break;
217
+ } else if (isDirectory) {
218
+ skip = "directory";
219
+ break;
220
+ } else {
221
+ skip = true;
222
+ }
223
+ }
224
+
225
+ if (skip === true) continue;
205
226
 
206
227
  let name = file;
207
228
  let source = "";
208
229
 
209
230
  for (let i = 0; i < match.length; i++) {
210
231
  skip = true;
211
- const filePath = path.resolve(entryPath, file);
212
232
  if (filePath.startsWith(match[i])) {
213
233
  skip = false;
214
234
  break;
@@ -232,7 +252,7 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
232
252
  } else directoryName = "/";
233
253
  }
234
254
 
235
- if (exclude && exclude.includes(directoryName)) continue;
255
+ // if (exclude && exclude.includes(directoryName)) continue;
236
256
 
237
257
  if (!Path) {
238
258
  if (directoryName === "/") Path = directoryName;
@@ -243,76 +263,136 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
243
263
  if (Path === "/") pathname = Path + name;
244
264
  else pathname = Path + "/" + name;
245
265
 
246
- if (isDirectory) mimeType = "text/directory";
247
- else
266
+ if (isDirectory) {
267
+ mimeType = "text/directory";
268
+ } else {
248
269
  source = await getSource(
249
270
  `${entryPath}/${file}`,
250
271
  mimeType,
251
272
  isSymlink
252
273
  );
274
+ }
253
275
 
254
276
  let values = {
255
277
  "{{name}}": name || "",
256
- "{{source}}": source || "",
278
+ "{{source}}": Buffer.isBuffer(source) ? `data:${mimeType};base64,${source.toString('base64')}` : source || "",
257
279
  "{{directory}}": directoryName || "",
258
280
  "{{path}}": Path || "",
259
281
  "{{pathname}}": pathname,
260
- "{{content-type}}": mimeType || ""
282
+ "{{content-type}}": mimeType || "",
261
283
  };
262
284
 
263
- let object = { ...directory.object };
264
- if (!object.name) object.name = "{{name}}";
265
- if (!object.src) object.src = "{{source}}";
266
- if (!object.directory) object.directory = "{{directory}}";
267
- if (!object.path) object.path = "{{path}}";
268
- if (!object.pathname) object.pathname = "{{pathname}}";
269
- if (!object["content-type"])
270
- object["content-type"] = "{{content-type}}";
271
- if (
272
- !object.public &&
273
- object.public != false &&
274
- object.public != "false"
275
- )
276
- object.public = "true";
277
-
278
- let newObject = {
279
- array: directory.array || "files",
280
- object
285
+ let data = {
286
+ array: directory.array || "files"
281
287
  };
282
288
 
283
- if (directory.storage) newObject.storage = directory.storage;
284
- if (directory.database) newObject.database = directory.database;
285
- if (directory.array) newObject.array = directory.array || "files";
286
-
287
- for (const key of Object.keys(directory.object)) {
288
- if (typeof directory.object[key] == "string") {
289
- let variables = directory.object[key].match(
290
- /{{([A-Za-z0-9_.,\[\]\-\/ ]*)}}/g
289
+ let isData = false;
290
+ if ( typeof directory.$data === "string") {
291
+ if (isDirectory) {
292
+ skip = "directory";
293
+ } else {
294
+ isData = true;
295
+ data = await getData(
296
+ `${entryPath}/${file}`,
297
+ mimeType,
298
+ isSymlink
299
+ );
300
+ if (!data) continue
301
+ }
302
+ } else if ( typeof directory.object === "string") {
303
+ if (isDirectory) {
304
+ skip = "directory";
305
+ } else {
306
+ isData = true;
307
+ data.object = await getData(
308
+ `${entryPath}/${file}`,
309
+ mimeType,
310
+ isSymlink
291
311
  );
292
- if (variables) {
293
- for (let variable of variables) {
294
- newObject.object[key] = newObject.object[
295
- key
296
- ].replace(variable, values[variable]);
297
- }
298
- }
312
+ if (!data.object) continue
299
313
  }
300
- }
301
-
302
- if (skip !== "directory") {
303
- if (!newObject.object._id)
304
- newObject.$filter = {
314
+ } else if (typeof directory.object === "object" && directory.object !== null) {
315
+ data.array = directory.array || "files";
316
+ let object = { ...directory.object };
317
+ if (!object.name) object.name = "{{name}}";
318
+ if (!object.src) object.src = "{{source}}";
319
+ if (!object.directory) object.directory = "{{directory}}";
320
+ if (!object.path) object.path = "{{path}}";
321
+ if (!object.pathname) object.pathname = "{{pathname}}";
322
+ if (!object["content-type"])
323
+ object["content-type"] = "{{content-type}}";
324
+ if (
325
+ !object.public &&
326
+ object.public != false &&
327
+ object.public != "false"
328
+ )
329
+ object.public = "true";
330
+
331
+ data.object = object;
332
+
333
+ if (!data.object._id) {
334
+ data.$filter = {
305
335
  query: {
306
336
  pathname
307
337
  }
308
338
  };
339
+ }
309
340
 
310
- response = await runStore(newObject);
311
- console.log(
312
- `Uploaded: ${entryPath}/${file}`,
313
- `To: ${pathname}`
314
- );
341
+ if (
342
+ options.translate &&
343
+ mimeType === "text/html" &&
344
+ Array.isArray(directory.languages) &&
345
+ !object.translations
346
+ ) {
347
+ try {
348
+ // Call your AI translation service
349
+ const translations = await options.translate(
350
+ Buffer.isBuffer(source) ? source.toString('utf-8') : source,
351
+ directory.languages
352
+ );
353
+ data.object.translations = translations;
354
+ } catch (err) {
355
+ console.error("Translation error:", err);
356
+ // Continue without translations
357
+ }
358
+ }
359
+
360
+ if (directory.storage) data.storage = directory.storage;
361
+ if (directory.database) data.database = directory.database;
362
+ if (directory.array) data.array = directory.array || "files";
363
+
364
+ for (const key of Object.keys(directory.object)) {
365
+ if (typeof directory.object[key] == "string") {
366
+ let variables = directory.object[key].match(
367
+ /{{([A-Za-z0-9_.,\[\]\-\/ ]*)}}/g
368
+ );
369
+ if (variables) {
370
+ for (let variable of variables) {
371
+ let replacement = values[variable];
372
+ if (key === 'src' && variable === '{{source}}' && Buffer.isBuffer(source)) {
373
+ replacement = `data:${mimeType};base64,${source.toString('base64')}`;
374
+ }
375
+ data.object[key] = data.object[
376
+ key
377
+ ].replace(variable, replacement);
378
+ }
379
+ }
380
+ }
381
+ }
382
+ }
315
383
 
384
+ if (skip !== "directory") {
385
+ response = await runStore(data);
386
+ if (isData) {
387
+ console.log(
388
+ `Saved: ${entryPath}/${file}`
389
+ );
390
+ } else {
391
+ console.log(
392
+ `Uploaded: ${entryPath}/${file}`,
393
+ `To: ${pathname}`
394
+ );
395
+ }
316
396
  if (response.error) errorLog.push(response.error);
317
397
  }
318
398
 
@@ -321,151 +401,195 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
321
401
  if (entry.endsWith("/")) newEntry = entry + name;
322
402
  else newEntry = entry + "/" + name;
323
403
 
324
- await runFiles(directory, newEntry, exclude, pathname, name);
404
+ await runFiles(directory, newEntry, pathname, name);
325
405
  }
326
406
  }
327
407
  // if (errorLog.length)
328
408
  // console.log(...errorLog)
329
409
  }
330
410
 
331
- async function getSource(path, mimeType, isSymlink) {
332
- let readType = "utf8";
333
- if (mimeType === "image/svg+xml") {
334
- readType = "utf8";
335
- } else if (/^(image|audio|video)\/[-+.\w]+/.test(mimeType)) {
336
- readType = "base64";
411
+ async function getSource(filePath, mimeType, isSymlink) {
412
+ // 1. UPDATED: Includes standard font types and uses simpler matching
413
+ const base64MimeTypes = /^(image|audio|video|font\/(woff2?|ttf|otf|eot)|application\/vnd\.ms-fontobject|application\/x-font-.*|application\/octet-stream)/;
414
+
415
+ // We only care if it needs to be Base64-encoded for a Data URI.
416
+ const needsBase64 = base64MimeTypes.test(mimeType);
417
+
418
+ let resolvedPath = filePath;
419
+ if (isSymlink) {
420
+ // Use promises for realpath
421
+ resolvedPath = await realpathAsync(filePath);
337
422
  }
338
423
 
339
- if (isSymlink) path = await realpathAsync(path);
424
+ // 2. READ: Always read the file as a raw Buffer (omitting encoding)
425
+ // This gives us the raw bytes, which is the safest start for any file.
426
+ let fileBuffer;
427
+ try {
428
+ fileBuffer = await fs.promises.readFile(resolvedPath);
429
+ } catch (error) {
430
+ console.error(`Error reading file: ${resolvedPath}`, error);
431
+ return ""; // Return empty string or handle error as appropriate
432
+ }
340
433
 
341
- let binary = fs.readFileSync(path);
342
- let content = new Buffer.from(binary).toString(readType);
434
+ if (needsBase64) {
435
+ // 3. RETURN BUFFER: Return the raw buffer for binary files.
436
+ return fileBuffer;
437
+ } else {
438
+ // 4. HANDLE TEXT/OTHER:
439
+ // For files not intended for Base64, convert the Buffer to a string using 'utf8'.
440
+ return fileBuffer.toString('utf8');
441
+ }
442
+ }
443
+
444
+ async function getData(filePath, mimeType, isSymlink) {
445
+ let resolvedPath = filePath;
446
+ if (isSymlink) {
447
+ resolvedPath = await realpathAsync(filePath);
448
+ }
449
+
450
+ try {
451
+ const fileMimeType = mimeTypes[path.extname(resolvedPath)] || "text/plain";
452
+ if (fileMimeType === "application/json") {
453
+ // Parse JSON files
454
+ return JSON.parse(fs.readFileSync(resolvedPath, "utf8"));
455
+ } else if (
456
+ fileMimeType === "application/javascript" ||
457
+ fileMimeType === "text/javascript"
458
+ ) {
459
+ // Try CommonJS require first (fast path)
460
+ try {
461
+ // clear require cache to ensure fresh load
462
+ delete require.cache[require.resolve(resolvedPath)];
463
+ return require(resolvedPath);
464
+ } catch (err) {
465
+ // If require fails due to ESM syntax (export / import), fall back to dynamic import
466
+ const isESMSyntaxError =
467
+ err instanceof SyntaxError ||
468
+ /Unexpected token 'export'/.test(err.message) ||
469
+ /Cannot use import statement outside a module/.test(err.message) ||
470
+ /Unexpected token 'import'/.test(err.message);
471
+
472
+ if (isESMSyntaxError) {
473
+ try {
474
+ const module = await import(pathToFileURL(resolvedPath).href);
475
+ // return default export when present otherwise return full module
476
+ return module && module.default ? module.default : module;
477
+ } catch (impErr) {
478
+ console.error(`Failed to dynamic-import module: ${resolvedPath}`, impErr);
479
+ throw impErr;
480
+ }
481
+ }
482
+ // rethrow original require error if it's not an ESM issue
483
+ throw err;
484
+ }
485
+ } else {
486
+ return fs.readFileSync(resolvedPath, "utf8");
487
+ }
488
+ } catch (error) {
489
+ console.error(`Failed to process file: ${resolvedPath}`, error);
490
+ return "";
491
+ }
343
492
 
344
- return content;
345
493
  }
346
494
 
347
495
  /**
348
496
  * Store files by config sources
349
497
  **/
350
498
  async function runSources() {
351
- let updatedSources = [];
499
+ let newConfig = require(configPath);
352
500
 
353
501
  for (let i = 0; i < sources.length; i++) {
354
- const { array, object } = sources[i];
355
-
356
- let source = { ...sources[i] };
357
- let keys = new Map();
358
- let response = {};
359
- let isMatch = false;
360
-
361
- try {
362
- if (array) {
363
- if (!object) object = {};
364
- else
365
- for (const key of Object.keys(object)) {
366
- if (typeof object[key] != "string") continue;
367
-
368
- let variables = object[key].match(
369
- /{{([A-Za-z0-9_.,\[\]\-\/ ]*)}}/g
370
- );
371
- if (variables) {
372
- let originalValue = object[key];
373
- keys.set(key, originalValue);
374
- let value = "";
375
- for (let variable of variables) {
376
- let entry = /{{\s*([\w\W]+)\s*}}/g.exec(
377
- variable
378
- );
379
- entry = entry[1].trim();
380
- if (entry) {
381
- if (!fs.existsSync(entry)) continue;
382
-
383
- if (!isMatch) {
384
- const filePath = path.resolve(
385
- configDirectoryPath,
386
- entry
387
- );
388
- for (
389
- let i = 0;
390
- i < match.length;
391
- i++
392
- ) {
393
- if (
394
- filePath.startsWith(
395
- match[i]
396
- )
397
- ) {
398
- console.log(
399
- "Source saved",
400
- sources[i]
401
- );
402
- isMatch = true;
403
- break;
404
- }
405
- }
406
- }
407
-
408
- let read_type = "utf8";
409
- const fileExtension =
410
- path.extname(entry);
411
- let mime_type =
412
- mimeTypes[fileExtension] ||
413
- "text/html";
414
-
415
- if (
416
- /^(image|audio|video)\/[-+.\w]+/.test(
417
- mime_type
418
- )
419
- ) {
420
- read_type = "base64";
421
- }
422
-
423
- let binary = fs.readFileSync(entry);
424
- let content = new Buffer.from(
425
- binary
426
- ).toString(read_type);
427
- if (content) value += content;
428
- // object[key] = object[key].replace(variable, content);
429
- }
430
- }
431
- object[key] = value;
432
- }
502
+ let data = sources[i];
503
+
504
+ // Handle string values
505
+ if (typeof data === "string") {
506
+ let {value, filePath } = await processVariables(data);
507
+ let response = await runStore(value);
508
+ if (response && response.object && response.object[0]) {
509
+ updateFilePath(filePath, response); // Call the new function to update the file path
510
+ }
511
+ } else if (data.array && data.object) {
512
+ if (typeof data.object === "string") {
513
+ let {value, filePath } = await processVariables(data.object);
514
+ if (value) {
515
+ let response = await runStore(value);
516
+ if (response && response.object && response.object[0]) {
517
+ updateFilePath(filePath, response.object);
433
518
  }
434
-
435
- let data = { array, object };
436
- if (!object._id && object.pathname)
437
- data.$filter = {
438
- query: {
439
- $or: [{ pathname: object.pathname }]
440
- }
441
- };
442
-
443
- if (match.length && isMatch)
444
- response = await runStore(data);
519
+ }
520
+ } else if (typeof data.object === "object" && data.object !== null) {
521
+ for (const key in data) {
522
+ let {value } = await processVariables(data[key]);
523
+ if (data) {
524
+ data.object[key] = value;
525
+ }
526
+ }
527
+ let response = await runStore(data);
528
+ if (response && response.object && response.object[0] && response.object[0]._id) {
529
+ newConfig.sources[i].object._id = response.object[0]._id;
530
+ }
445
531
  }
446
- } catch (err) {
447
- console.log(err);
448
- process.exit();
449
532
  }
450
533
 
451
- if (
452
- response.object &&
453
- response.object[0] &&
454
- response.object[0]._id
455
- ) {
456
- source.object._id = response.object[0]._id;
457
- }
534
+ }
458
535
 
459
- for (const [key, value] of keys) {
460
- source.object[key] = value;
461
- }
536
+ return newConfig;
537
+ }
538
+
539
+ async function processVariables(value) {
540
+ let variableMatch = /{{\s*([\w\W]+)\s*}}/g.exec(value);
541
+ if (!variableMatch) return { value, filePath: null };
542
+
543
+ let entry = variableMatch[1].trim();
544
+ if (!fs.existsSync(entry)) return { value, filePath: null };
462
545
 
463
- updatedSources.push(source);
546
+ const filePath = path.resolve(configDirectoryPath, entry);
547
+
548
+ // Check if the file path matches any of the provided match patterns
549
+ let isMatched = match.some((pattern) => filePath.startsWith(pattern));
550
+ if (!isMatched) return { value, filePath: null };
551
+
552
+ // Read the file as is
553
+ let content;
554
+ try {
555
+ const fileMimeType = mimeTypes[path.extname(entry)] || "text/plain";
556
+
557
+ if (fileMimeType === "application/json") {
558
+ // Parse JSON files
559
+ content = JSON.parse(fs.readFileSync(filePath, "utf8"));
560
+ } else if (fileMimeType === "application/javascript" || fileMimeType === "text/javascript") {
561
+ // For JavaScript files, require the file to execute exports
562
+ content = require(filePath);
563
+ } else {
564
+ // For plain strings, read as UTF-8 without conversion
565
+ content = fs.readFileSync(filePath, "utf8");
566
+ }
567
+ } catch (error) {
568
+ console.error(`Failed to process file: ${filePath}`, error);
569
+ return { value, filePath: null };
464
570
  }
465
571
 
466
- return updatedSources;
572
+ return { value: content, filePath };
573
+ }
574
+
575
+ /**
576
+ * Updates the file at the given file path with the provided data.
577
+ * The data is saved as a JSON string.
578
+ *
579
+ * @param {string} filePath - The path of the file to update.
580
+ * @param {object} data - The data to write to the file.
581
+ */
582
+ function updateFilePath(filePath, data) {
583
+ try {
584
+ const jsonData = JSON.stringify(data, null, 4); // Format JSON with indentation
585
+ fs.writeFileSync(filePath, jsonData, "utf8");
586
+ console.log(`File updated successfully at: ${filePath}`);
587
+ } catch (error) {
588
+ console.error(`Failed to update file at: ${filePath}`, error);
589
+ }
467
590
  }
468
591
 
592
+
469
593
  async function runStore(data) {
470
594
  try {
471
595
  let response;
@@ -493,42 +617,22 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
493
617
  }
494
618
 
495
619
  async function run() {
496
- if (directories) await runDirectories();
620
+ if (directories) {
621
+ await runDirectories();
622
+ }
497
623
 
498
624
  if (sources && sources.length) {
499
- let sources = await runSources();
500
- let newConfig = { ...CoCreateConfig };
501
- if (directories && directories.length)
502
- newConfig.directories = directories;
503
-
504
- newConfig.sources = sources;
505
-
506
- if (newConfig.repositories)
507
- newConfig.repositories.forEach((obj) => {
508
- for (const key in obj) {
509
- if (!["path", "repo", "exclude"].includes(key)) {
510
- delete obj[key];
511
- }
512
- }
513
- });
514
-
515
- delete newConfig.url;
516
- delete newConfig.broadcast;
517
-
625
+ let newConfig = await runSources();
518
626
  fs.writeFileSync(
519
627
  configPath,
520
628
  `module.exports = ${JSON.stringify(newConfig, null, 4)};`
521
629
  );
522
630
  }
523
-
524
- if (!match.length) {
525
- console.log("upload complete!");
526
-
527
- setTimeout(function () {
528
- process.exit();
529
- }, 2000);
530
- }
531
631
  }
532
632
 
533
633
  await run();
634
+ // Only exit if not in watch mode
635
+ if (!process.argv.includes("--watch") && !process.argv.includes("-w")) {
636
+ process.exit();
637
+ }
534
638
  };