@qaecy/cue-cli 0.0.13 → 0.0.15

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.
Files changed (3) hide show
  1. package/main.js +92 -25
  2. package/package.json +1 -1
  3. package/readme.md +14 -1
package/main.js CHANGED
@@ -211,6 +211,7 @@ var BUCKET_CHAT_SESSIONS = "spaces_chats_eu_west6";
211
211
  var BUCKET_RAW = "spaces_raw_eu_west6";
212
212
  var BUCKET_PROCESSED = "spaces_processed_eu_west6";
213
213
  var BUCKET_LOGS = "spaces_logs_eu_west6";
214
+ var BUCKET_PUBLIC = "cue_public_eu_west6";
214
215
  var COLLECTION_CHAT_SESSIONS = "chatSessions";
215
216
  var COLLECTION_ORGANIZATIONS = "organizations";
216
217
  var COLLECTION_PROJECTS = "projects";
@@ -272,6 +273,9 @@ var CueFirebase = class _CueFirebase {
272
273
  get storageChatSessions() {
273
274
  return this._storageChatSessions;
274
275
  }
276
+ get storagePublic() {
277
+ return this._storagePublic;
278
+ }
275
279
  get collectionChatSessions() {
276
280
  return this._collectionChatSessions;
277
281
  }
@@ -342,6 +346,7 @@ var CueFirebase = class _CueFirebase {
342
346
  this._storageRaw = (0, import_storage.getStorage)(app, BUCKET_RAW);
343
347
  this._storageChatSessions = (0, import_storage.getStorage)(app, BUCKET_CHAT_SESSIONS);
344
348
  this._storageLogs = (0, import_storage.getStorage)(app, BUCKET_LOGS);
349
+ this._storagePublic = (0, import_storage.getStorage)(app, BUCKET_PUBLIC);
345
350
  this._collectionChatSessions = (0, import_firestore.collection)(
346
351
  (0, import_firestore.getFirestore)(app),
347
352
  COLLECTION_CHAT_SESSIONS
@@ -377,6 +382,8 @@ var CueFirebase = class _CueFirebase {
377
382
  throw new Error("Storage chat sessions is not initialized");
378
383
  if (this._storageLogs === void 0)
379
384
  throw new Error("Storage logs is not initialized");
385
+ if (this._storagePublic === void 0)
386
+ throw new Error("Storage public is not initialized");
380
387
  if (this._app === void 0)
381
388
  throw new Error("App is not initialized");
382
389
  const functions = (0, import_functions.getFunctions)(this._app, GCP_REGION);
@@ -387,6 +394,7 @@ var CueFirebase = class _CueFirebase {
387
394
  (0, import_storage.connectStorageEmulator)(this._storageRaw, "localhost", 9199);
388
395
  (0, import_storage.connectStorageEmulator)(this._storageChatSessions, "localhost", 9199);
389
396
  (0, import_storage.connectStorageEmulator)(this._storageLogs, "localhost", 9199);
397
+ (0, import_storage.connectStorageEmulator)(this._storagePublic, "localhost", 9199);
390
398
  if (!this._muted)
391
399
  console.info("Firebase emulators attached");
392
400
  }
@@ -402,6 +410,7 @@ var import_storage2 = require("firebase/storage");
402
410
  var qaecyPrefixes = {
403
411
  qcy: "https://dev.qaecy.com/ont#",
404
412
  "qcy-e": "https://dev.qaecy.com/enum#",
413
+ "qcy-f": "https://dev.qaecy.com/functions#",
405
414
  obc: "https://w3id.org/obc#",
406
415
  // OpenBIM Components
407
416
  dicc: "https://w3id.org/digitalconstruction/0.5/Contexts#",
@@ -5736,20 +5745,64 @@ async function uploadFile(file, spaceId, userId, providerId) {
5736
5745
  const storage = firebase.storageRaw;
5737
5746
  const fileRef = (0, import_storage5.ref)(storage, rawFileMetadata.blob_name);
5738
5747
  const fileBuffer = await (0, import_promises6.readFile)(file.fullPath);
5739
- await new Promise((resolve, reject) => {
5740
- const uploadTask = (0, import_storage5.uploadBytesResumable)(fileRef, fileBuffer, {
5741
- customMetadata: rawFileMetadata
5742
- });
5743
- uploadTask.on(
5744
- "state_changed",
5745
- null,
5746
- (error) => reject(error),
5747
- () => resolve()
5748
- );
5749
- if (!uploadTask) {
5750
- reject(new Error("Upload task could not be created"));
5748
+ const maxRetries = 3;
5749
+ let attempt = 0;
5750
+ let lastError = null;
5751
+ while (attempt < maxRetries) {
5752
+ try {
5753
+ await new Promise((resolve, reject) => {
5754
+ const uploadTask = (0, import_storage5.uploadBytesResumable)(fileRef, fileBuffer, {
5755
+ customMetadata: rawFileMetadata
5756
+ });
5757
+ uploadTask.on(
5758
+ "state_changed",
5759
+ null,
5760
+ (error) => {
5761
+ const blobName = rawFileMetadata.blob_name;
5762
+ console.error("[uploadFile] Error uploading file:", {
5763
+ filePath: file.fullPath,
5764
+ relativePath: file.relativePath,
5765
+ md5: file.md5,
5766
+ blobName,
5767
+ blobNameLength: blobName?.length,
5768
+ blobNameIsUnusual: blobName && (blobName.length > 256 || /[^\w\-./]/.test(blobName)),
5769
+ errorCode: error?.code,
5770
+ errorMessage: error?.message,
5771
+ errorPayload: error,
5772
+ fileBufferSize: fileBuffer?.length,
5773
+ rawFileMetadataKeys: Object.keys(rawFileMetadata),
5774
+ rawFileMetadataLength: Object.keys(rawFileMetadata).length,
5775
+ attempt
5776
+ });
5777
+ reject(error);
5778
+ },
5779
+ () => resolve()
5780
+ );
5781
+ if (!uploadTask) {
5782
+ console.error("[uploadFile] Upload task could not be created:", {
5783
+ filePath: file.fullPath,
5784
+ relativePath: file.relativePath,
5785
+ md5: file.md5,
5786
+ blobName: rawFileMetadata.blob_name,
5787
+ attempt
5788
+ });
5789
+ reject(new Error("Upload task could not be created"));
5790
+ }
5791
+ });
5792
+ lastError = null;
5793
+ break;
5794
+ } catch (err) {
5795
+ lastError = err;
5796
+ attempt++;
5797
+ if (attempt < maxRetries) {
5798
+ console.warn(`[uploadFile] Retry attempt ${attempt} for file: ${file.fullPath}`);
5799
+ await new Promise((res) => setTimeout(res, 1e3 * attempt));
5800
+ }
5751
5801
  }
5752
- });
5802
+ }
5803
+ if (lastError) {
5804
+ throw lastError;
5805
+ }
5753
5806
  return rawFileMetadata;
5754
5807
  }
5755
5808
 
@@ -5869,20 +5922,31 @@ async function syncHandler(options) {
5869
5922
  if (verbose && report.localNotOnRemote.length)
5870
5923
  console.info("Syncing missing files \u23F3");
5871
5924
  let rdfWritten = false;
5925
+ let failedUploads = 0;
5872
5926
  for (const file of report.localNotOnRemote) {
5873
- const rawFileMetadata = await uploadFile(file, space, userId, provider);
5874
- await uploadFileRDF(file, rawFileMetadata, verbose);
5875
- syncCount += 1;
5876
- syncSize += file.size || 0;
5877
- const pct = Math.floor(syncCount / report.totalCount * 100);
5878
- if (verbose && report.totalCount > 0 && syncCount % Math.ceil(report.totalCount / 100) === 0) {
5879
- console.info(
5880
- `Progress: ${pct}% (${syncCount}/$${report.totalCount} files, ${fileSizePretty(syncSize)}/${fileSizePretty(
5881
- report.totalSize
5882
- )})`
5883
- );
5927
+ let rawFileMetadata;
5928
+ try {
5929
+ rawFileMetadata = await uploadFile(file, space, userId, provider);
5930
+ await uploadFileRDF(file, rawFileMetadata, verbose);
5931
+ syncCount += 1;
5932
+ syncSize += file.size || 0;
5933
+ const pct = Math.floor(syncCount / report.totalCount * 100);
5934
+ if (verbose && report.totalCount > 0 && syncCount % Math.ceil(report.totalCount / 100) === 0) {
5935
+ console.info(
5936
+ `Progress: ${pct}% (${syncCount}/$${report.totalCount} files, ${fileSizePretty(syncSize)}/${fileSizePretty(
5937
+ report.totalSize
5938
+ )})`
5939
+ );
5940
+ }
5941
+ rdfWritten = true;
5942
+ } catch (err) {
5943
+ failedUploads += 1;
5944
+ console.error(`[syncHandler] Failed to upload file: ${file.fullPath}`);
5945
+ if (verbose) {
5946
+ console.error("[syncHandler] Upload error details:", err);
5947
+ }
5948
+ continue;
5884
5949
  }
5885
- rdfWritten = true;
5886
5950
  }
5887
5951
  const zipDeletePromise = zip ? deleteUnzipped(path) : Promise.resolve();
5888
5952
  if (verbose && report.localNotOnRemotePathOnly.length)
@@ -5932,6 +5996,9 @@ async function syncHandler(options) {
5932
5996
  if (verbose) {
5933
5997
  console.info("");
5934
5998
  console.info(`Sync finished \u{1F680}\u{1F680}\u{1F680}`);
5999
+ if (failedUploads > 0) {
6000
+ console.warn(`Total files failed to upload: ${failedUploads}`);
6001
+ }
5935
6002
  }
5936
6003
  } catch (err) {
5937
6004
  console.error("Error:", err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qaecy/cue-cli",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "Cue CLI for QAECY platform",
5
5
  "main": "main.js",
6
6
  "bin": {
package/readme.md CHANGED
@@ -18,4 +18,17 @@ You need an API key in order to authenticate with the CLI tool.
18
18
  ### Sync a folder
19
19
  To sync the current dir to the space with id `<space-id>` under the provider id `d_drive` (provider id is used to distinguish different document sources and if none is provided the default provider is used). The `v`-flag is for verbose logging so we can follow the progress.
20
20
 
21
- `npx @qaecy/cue-cli sync -s <space-id> -p . --provider d_drive -v`
21
+ `npx @qaecy/cue-cli sync -s <space-id> -p . --provider d_drive -v`
22
+
23
+
24
+ ### Sync command options
25
+
26
+ | Option | Description | Default |
27
+ |-----------------------|------------------------------------------------------------------------------------------------------|--------------|
28
+ | `-s, --space <id>` | Specify the space ID (required) | N/A |
29
+ | `-p, --path <id>` | Specify the folder path to sync (required) | N/A |
30
+ | `-k, --key <api-key>` | Specify the API key (or set `CUE_API_KEY` env variable) | N/A |
31
+ | `--provider <id>` | Specify the provider ID (e.g., sharepoint, drive, dropbox). Leave empty for default provider | `""` |
32
+ | `-v, --verbose` | Enable verbose output | `false` |
33
+ | `-e, --emulators` | Use emulators for sync | `false` |
34
+ | `-z, --zip` | Include zipped content. Will be unzipped to `<zip_path>_unzipped`. Max uncompressed size: 500 MB, max recursion depth: 3. Cleans up unzipped files after sync. | `false` |