@qaecy/cue-cli 0.0.33 → 0.0.34
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/main.js +187 -95
- package/package.json +1 -1
package/main.js
CHANGED
|
@@ -107,7 +107,6 @@ var QLEVER_UPDATE_ENDPOINT_EMULATOR = process.env.CUE_QLEVER_ENDPOINT ? `${proce
|
|
|
107
107
|
var SPARQL_ENDPOINT_EMULATOR = `${EMULATOR_API_GATEWAY_BASE}/triplestore/query`;
|
|
108
108
|
var SPARQL_ENDPOINT = "https://accessors-api-gateway-ueyeemwf2a-oa.a.run.app/triplestore/query";
|
|
109
109
|
var HASH_WORKER_PATH = (0, import_path.join)(__dirname, "hash-worker.js");
|
|
110
|
-
var PROJECT_ID = "qaecy-mvp-406413.appspot.com";
|
|
111
110
|
var FIREBASE_CONFIG = (useEmulator = false) => ({
|
|
112
111
|
apiKey: "AIzaSyCLhz5Wa3ZCERQZVurSt9bqupPeREALFLk",
|
|
113
112
|
appId: "1:151132927589:web:d11c64cc55bdc0f13ab88c",
|
|
@@ -4141,7 +4140,7 @@ var CueAuth = class {
|
|
|
4141
4140
|
// libs/js/cue-sdk/src/lib/api.ts
|
|
4142
4141
|
var ENDPOINT_SEARCH = "/assistant/search";
|
|
4143
4142
|
var ENDPOINT_SPARQL = "/triplestore/query";
|
|
4144
|
-
var ENDPOINT_CONSUMPTION = "/data-views/admin/consumption
|
|
4143
|
+
var ENDPOINT_CONSUMPTION = "/data-views/admin/consumption";
|
|
4145
4144
|
var CueApi = class {
|
|
4146
4145
|
constructor(_auth, _gatewayUrl, projects, sync) {
|
|
4147
4146
|
this._auth = _auth;
|
|
@@ -4201,10 +4200,14 @@ var CueApi = class {
|
|
|
4201
4200
|
}
|
|
4202
4201
|
return response.json();
|
|
4203
4202
|
}
|
|
4204
|
-
async getConsumption(projectId) {
|
|
4203
|
+
async getConsumption(projectId, tier) {
|
|
4205
4204
|
const headers = await this._authHeaders();
|
|
4206
4205
|
const response = await fetch(`${this._gatewayUrl}${ENDPOINT_CONSUMPTION}`, {
|
|
4207
|
-
headers: {
|
|
4206
|
+
headers: {
|
|
4207
|
+
...headers,
|
|
4208
|
+
"x-project-id": projectId,
|
|
4209
|
+
...tier ? { "x-tier": tier } : {}
|
|
4210
|
+
}
|
|
4208
4211
|
});
|
|
4209
4212
|
if (!response.ok) {
|
|
4210
4213
|
throw new Error(`Failed to fetch consumption: ${response.status} ${response.statusText}`);
|
|
@@ -4880,6 +4883,30 @@ var CueBlobStorage = class {
|
|
|
4880
4883
|
const result = await (0, import_storage3.listAll)(listRef);
|
|
4881
4884
|
return result.items.map((item) => item.name);
|
|
4882
4885
|
}
|
|
4886
|
+
/**
|
|
4887
|
+
* Download a file from the public bucket and return its contents as a string.
|
|
4888
|
+
*/
|
|
4889
|
+
async downloadPublic(blobName) {
|
|
4890
|
+
const fileRef = (0, import_storage3.ref)(this.options.storagePublic, blobName);
|
|
4891
|
+
const controller = new AbortController();
|
|
4892
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
4893
|
+
try {
|
|
4894
|
+
const [url, metadata] = await Promise.all([
|
|
4895
|
+
(0, import_storage3.getDownloadURL)(fileRef),
|
|
4896
|
+
(0, import_storage3.getMetadata)(fileRef)
|
|
4897
|
+
]);
|
|
4898
|
+
const cacheBustedUrl = `${url}&t=${encodeURIComponent(metadata.updated)}`;
|
|
4899
|
+
const res = await fetch(cacheBustedUrl, { signal: controller.signal });
|
|
4900
|
+
if (!res.ok)
|
|
4901
|
+
throw new Error(`HTTP ${res.status}`);
|
|
4902
|
+
return res.text();
|
|
4903
|
+
} catch (err) {
|
|
4904
|
+
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
4905
|
+
throw new Error(isTimeout ? `Download timed out: ${blobName}` : err instanceof Error ? err.message : String(err));
|
|
4906
|
+
} finally {
|
|
4907
|
+
clearTimeout(timeout);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4883
4910
|
};
|
|
4884
4911
|
|
|
4885
4912
|
// libs/js/cue-sdk/src/lib/sync.ts
|
|
@@ -5941,6 +5968,29 @@ var CueSyncApi = class {
|
|
|
5941
5968
|
_bindApi(api) {
|
|
5942
5969
|
this._api = api;
|
|
5943
5970
|
}
|
|
5971
|
+
/**
|
|
5972
|
+
* Flushes any pending metadata items from a previous interrupted sync.
|
|
5973
|
+
* Safe to call even when there is nothing new to upload.
|
|
5974
|
+
*/
|
|
5975
|
+
async flushPendingMetadata(spaceId, verbose) {
|
|
5976
|
+
const token = await this._auth.getToken();
|
|
5977
|
+
if (!token)
|
|
5978
|
+
throw new Error("Not authenticated. Call cue.auth.signIn() first.");
|
|
5979
|
+
const existing = await _loadPending(spaceId);
|
|
5980
|
+
if (!existing || existing.items.length === 0)
|
|
5981
|
+
return;
|
|
5982
|
+
console.info(`Trying to upload metadata (${existing.items.length} item(s))...`);
|
|
5983
|
+
if (verbose)
|
|
5984
|
+
console.info(`Flushing ${existing.items.length} pending file location(s) from previous sync \u23F3`);
|
|
5985
|
+
try {
|
|
5986
|
+
this._pendingSpaceId = spaceId;
|
|
5987
|
+
this._pendingItems = [];
|
|
5988
|
+
await this._flushBatch(existing.items, spaceId, token, verbose);
|
|
5989
|
+
console.info("Metadata uploaded \u2705");
|
|
5990
|
+
} catch (err) {
|
|
5991
|
+
throw new Error(`METADATA_SYNC_FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
5992
|
+
}
|
|
5993
|
+
}
|
|
5944
5994
|
/**
|
|
5945
5995
|
* Returns a preview of what would be synced: cost breakdown for new files only,
|
|
5946
5996
|
* units required, and units still available. Use this before calling {@link sync}
|
|
@@ -5952,33 +6002,56 @@ var CueSyncApi = class {
|
|
|
5952
6002
|
if (!token)
|
|
5953
6003
|
throw new Error("Not authenticated. Call cue.auth.signIn() first.");
|
|
5954
6004
|
const graph = await this._getOrCreateGraph(spaceId, token);
|
|
5955
|
-
const
|
|
6005
|
+
const project = await this._projects.getProject(spaceId);
|
|
6006
|
+
const tier = project?.projectSettings?.tier ?? "l";
|
|
6007
|
+
const [remoteFiles, consumption, creditMap, tierNames] = await Promise.all([
|
|
5956
6008
|
this._listRemoteFiles(graph, spaceId, providerId, verbose),
|
|
5957
|
-
this._api?.getConsumption(spaceId) ?? Promise.reject(new Error("CueSyncApi is not bound to a CueApi instance"))
|
|
6009
|
+
this._api?.getConsumption(spaceId, tier) ?? Promise.reject(new Error("CueSyncApi is not bound to a CueApi instance")),
|
|
6010
|
+
this._fetchUnitCreditMap(verbose),
|
|
6011
|
+
this._fetchTierNames()
|
|
5958
6012
|
]);
|
|
5959
6013
|
const report = await compareLocalRemote(localFiles, remoteFiles);
|
|
5960
6014
|
const toUpload = report.localNotOnRemote ?? [];
|
|
5961
6015
|
const costRecords = toUpload.length > 0 ? await this.scanCost(toUpload) : [];
|
|
5962
|
-
|
|
6016
|
+
let unitsToConsume = 0;
|
|
6017
|
+
let creditsToConsume = 0;
|
|
6018
|
+
for (const r of costRecords) {
|
|
6019
|
+
unitsToConsume += r.units;
|
|
6020
|
+
const tierMap = creditMap[tier];
|
|
6021
|
+
const creditPerUnit = tierMap?.[r.ext] ?? 1;
|
|
6022
|
+
if (verbose && tierMap && !(r.ext in tierMap)) {
|
|
6023
|
+
console.info(` Unknown format: .${r.ext} (using default rate of 1 credit/unit)`);
|
|
6024
|
+
}
|
|
6025
|
+
const credits = r.units * creditPerUnit;
|
|
6026
|
+
creditsToConsume += credits;
|
|
6027
|
+
r.credits = Math.round(credits);
|
|
6028
|
+
}
|
|
6029
|
+
const tierName = tierNames[tier] ?? tier;
|
|
5963
6030
|
return {
|
|
5964
6031
|
costRecords,
|
|
6032
|
+
tier,
|
|
6033
|
+
tierName,
|
|
5965
6034
|
unitsToConsume,
|
|
6035
|
+
creditsToConsume: Math.round(creditsToConsume),
|
|
6036
|
+
creditsAvailable: consumption.creditsAvailable,
|
|
5966
6037
|
unitsAvailable: consumption.unitsAvailable,
|
|
5967
6038
|
filesToUpload: toUpload.length,
|
|
5968
6039
|
totalLocalFiles: localFiles.length
|
|
5969
6040
|
};
|
|
5970
6041
|
}
|
|
5971
6042
|
async sync(localFiles, options) {
|
|
5972
|
-
const { spaceId, providerId, userId, verbose } = options;
|
|
6043
|
+
const { spaceId, providerId, userId, verbose, onProgress } = options;
|
|
5973
6044
|
const token = await this._auth.getToken();
|
|
5974
6045
|
if (!token)
|
|
5975
6046
|
throw new Error("Not authenticated. Call cue.auth.signIn() first.");
|
|
5976
6047
|
const graph = await this._getOrCreateGraph(spaceId, token);
|
|
5977
6048
|
if (verbose)
|
|
5978
6049
|
console.info("Listing remote files \u23F3");
|
|
6050
|
+
const project = await this._projects.getProject(spaceId);
|
|
6051
|
+
const tier = project?.projectSettings?.tier ?? "l";
|
|
5979
6052
|
const [remoteFiles, consumption] = await Promise.all([
|
|
5980
6053
|
this._listRemoteFiles(graph, spaceId, providerId, verbose),
|
|
5981
|
-
this._api?.getConsumption(spaceId) ?? Promise.reject(new Error("CueSyncApi is not bound to a CueApi instance"))
|
|
6054
|
+
this._api?.getConsumption(spaceId, tier) ?? Promise.reject(new Error("CueSyncApi is not bound to a CueApi instance"))
|
|
5982
6055
|
]);
|
|
5983
6056
|
const { unitsAvailable } = consumption;
|
|
5984
6057
|
const report = await compareLocalRemote(localFiles, remoteFiles);
|
|
@@ -6033,7 +6106,7 @@ var CueSyncApi = class {
|
|
|
6033
6106
|
rdfWritten = true;
|
|
6034
6107
|
syncCount += 1;
|
|
6035
6108
|
syncSize += file.size || 0;
|
|
6036
|
-
this._logProgress(syncCount, report.totalCount, syncSize, report.totalSize,
|
|
6109
|
+
this._logProgress(syncCount, report.totalCount, syncSize, report.totalSize, onProgress);
|
|
6037
6110
|
} catch (err) {
|
|
6038
6111
|
failedUploads += 1;
|
|
6039
6112
|
console.error(`[CueSyncApi] Failed to upload file: ${file.fullPath}`);
|
|
@@ -6054,17 +6127,19 @@ var CueSyncApi = class {
|
|
|
6054
6127
|
rdfWritten = true;
|
|
6055
6128
|
syncCount += 1;
|
|
6056
6129
|
syncSize += file.size || 0;
|
|
6057
|
-
this._logProgress(syncCount, report.totalCount, syncSize, report.totalSize,
|
|
6130
|
+
this._logProgress(syncCount, report.totalCount, syncSize, report.totalSize, onProgress);
|
|
6058
6131
|
}
|
|
6059
6132
|
await this._drainPending(verbose);
|
|
6060
6133
|
this._stopFlushTimer();
|
|
6134
|
+
const postSyncConsumption = await (this._api?.getConsumption(spaceId, tier) ?? Promise.resolve({ creditsAvailable: 0 }));
|
|
6061
6135
|
return {
|
|
6062
6136
|
syncCount,
|
|
6063
6137
|
syncSize,
|
|
6064
6138
|
failedUploads,
|
|
6065
6139
|
totalCount: report.totalCount,
|
|
6066
6140
|
totalSize: report.totalSize,
|
|
6067
|
-
rdfWritten
|
|
6141
|
+
rdfWritten,
|
|
6142
|
+
creditsAvailable: postSyncConsumption.creditsAvailable
|
|
6068
6143
|
};
|
|
6069
6144
|
}
|
|
6070
6145
|
async _getOrCreateGraph(spaceId, token) {
|
|
@@ -6090,9 +6165,15 @@ var CueSyncApi = class {
|
|
|
6090
6165
|
async _listRemoteFiles(graph, spaceId, providerId, verbose) {
|
|
6091
6166
|
if (verbose)
|
|
6092
6167
|
console.info(`Listing files in raw space: ${spaceId}`);
|
|
6168
|
+
const graphFilesWithTimeout = Promise.race([
|
|
6169
|
+
this._getGraphFiles(graph, providerId),
|
|
6170
|
+
new Promise(
|
|
6171
|
+
(_, reject) => setTimeout(() => reject(new Error("GRAPH_TIMEOUT: Knowledge graph query timed out")), 15e3)
|
|
6172
|
+
)
|
|
6173
|
+
]);
|
|
6093
6174
|
const [blobNames, locationMap] = await Promise.all([
|
|
6094
6175
|
this._blob.listRaw(spaceId),
|
|
6095
|
-
|
|
6176
|
+
graphFilesWithTimeout
|
|
6096
6177
|
]);
|
|
6097
6178
|
if (verbose)
|
|
6098
6179
|
console.info(`Found ${blobNames.length} files in raw store for space: ${spaceId}`);
|
|
@@ -6148,9 +6229,15 @@ WHERE {
|
|
|
6148
6229
|
this._pendingItems = [];
|
|
6149
6230
|
const existing = await _loadPending(spaceId);
|
|
6150
6231
|
if (existing && existing.items.length > 0) {
|
|
6232
|
+
console.info(`Trying to upload metadata from interrupted sync (${existing.items.length} item(s))...`);
|
|
6151
6233
|
if (verbose)
|
|
6152
6234
|
console.info(`Flushing ${existing.items.length} pending file location(s) from previous sync \u23F3`);
|
|
6153
|
-
|
|
6235
|
+
try {
|
|
6236
|
+
await this._flushBatch(existing.items, spaceId, token, verbose);
|
|
6237
|
+
console.info("Metadata uploaded \u2705");
|
|
6238
|
+
} catch (err) {
|
|
6239
|
+
throw new Error(`METADATA_SYNC_FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
6240
|
+
}
|
|
6154
6241
|
}
|
|
6155
6242
|
const timer = setInterval(() => {
|
|
6156
6243
|
this._drainPending(verbose).catch(
|
|
@@ -6195,15 +6282,26 @@ WHERE {
|
|
|
6195
6282
|
}
|
|
6196
6283
|
}
|
|
6197
6284
|
async _postFssBatch(items, spaceId, token) {
|
|
6198
|
-
const
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
"
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6285
|
+
const controller = new AbortController();
|
|
6286
|
+
const timeout = setTimeout(() => controller.abort(), 15e3);
|
|
6287
|
+
let response;
|
|
6288
|
+
try {
|
|
6289
|
+
response = await fetch(`${this._gatewayUrl}${ENDPOINT_FSS_BATCH}`, {
|
|
6290
|
+
method: "POST",
|
|
6291
|
+
headers: {
|
|
6292
|
+
Authorization: `Bearer ${token}`,
|
|
6293
|
+
"Content-Type": "application/json",
|
|
6294
|
+
"x-project-id": spaceId
|
|
6295
|
+
},
|
|
6296
|
+
body: JSON.stringify({ items }),
|
|
6297
|
+
signal: controller.signal
|
|
6298
|
+
});
|
|
6299
|
+
} catch (err) {
|
|
6300
|
+
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
6301
|
+
throw new Error(`File structure batch POST failed: ${isTimeout ? "request timed out" : err instanceof Error ? err.message : String(err)}`);
|
|
6302
|
+
} finally {
|
|
6303
|
+
clearTimeout(timeout);
|
|
6304
|
+
}
|
|
6207
6305
|
if (!response.ok) {
|
|
6208
6306
|
const body = await response.text().catch(() => "");
|
|
6209
6307
|
throw new Error(`File structure batch POST failed: ${response.status} ${response.statusText}${body ? ` \u2014 ${body}` : ""}`);
|
|
@@ -6252,21 +6350,41 @@ WHERE {
|
|
|
6252
6350
|
}
|
|
6253
6351
|
return Array.from(merged.values());
|
|
6254
6352
|
}
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6353
|
+
async _fetchTierNames() {
|
|
6354
|
+
try {
|
|
6355
|
+
const text = await this._blob.downloadPublic("tier-names.json");
|
|
6356
|
+
return JSON.parse(text);
|
|
6357
|
+
} catch {
|
|
6358
|
+
return {};
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
async _fetchUnitCreditMap(verbose) {
|
|
6362
|
+
let text;
|
|
6363
|
+
try {
|
|
6364
|
+
text = await this._blob.downloadPublic("unit-credit.json");
|
|
6365
|
+
} catch (err) {
|
|
6366
|
+
throw new Error(`Couldn't fetch credits table: ${err instanceof Error ? err.message : String(err)}`);
|
|
6367
|
+
}
|
|
6368
|
+
if (verbose)
|
|
6369
|
+
console.info(`Price file: ${text.length} bytes`);
|
|
6370
|
+
try {
|
|
6371
|
+
return JSON.parse(text);
|
|
6372
|
+
} catch {
|
|
6373
|
+
throw new Error(`Credits table is not valid JSON (${text.length} bytes)`);
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
_logProgress(syncCount, totalCount, syncSize, totalSize, onProgress) {
|
|
6377
|
+
if (!onProgress || totalCount === 0)
|
|
6259
6378
|
return;
|
|
6260
6379
|
const pct = Math.floor(syncCount / totalCount * 100);
|
|
6261
|
-
|
|
6262
|
-
`Progress: ${pct}% (${syncCount}/${totalCount} files, ${syncSize}/${totalSize} bytes)`
|
|
6263
|
-
);
|
|
6380
|
+
onProgress({ percent: pct, syncCount, totalCount, syncSize, totalSize });
|
|
6264
6381
|
}
|
|
6265
6382
|
};
|
|
6266
6383
|
|
|
6267
6384
|
// libs/js/cue-sdk/src/lib/cue-node.ts
|
|
6268
6385
|
var BUCKET_RAW2 = "spaces_raw_eu_west6";
|
|
6269
6386
|
var BUCKET_PROCESSED2 = "spaces_processed_eu_west6";
|
|
6387
|
+
var BUCKET_PUBLIC2 = "cue_public_eu_west6";
|
|
6270
6388
|
var CueNode = class extends Cue {
|
|
6271
6389
|
constructor(config) {
|
|
6272
6390
|
super(config);
|
|
@@ -6274,13 +6392,15 @@ var CueNode = class extends Cue {
|
|
|
6274
6392
|
_buildApi(projects) {
|
|
6275
6393
|
const storageRaw = (0, import_storage4.getStorage)(this._app, BUCKET_RAW2);
|
|
6276
6394
|
const storageProcessed = (0, import_storage4.getStorage)(this._app, BUCKET_PROCESSED2);
|
|
6395
|
+
const storagePublic = (0, import_storage4.getStorage)(this._app, BUCKET_PUBLIC2);
|
|
6277
6396
|
if (this._isEmulator) {
|
|
6278
6397
|
const storageHost = this._endpoints.storageEmulatorHost;
|
|
6279
6398
|
const storagePort = this._endpoints.storageEmulatorPort;
|
|
6280
6399
|
(0, import_storage4.connectStorageEmulator)(storageRaw, storageHost, storagePort);
|
|
6281
6400
|
(0, import_storage4.connectStorageEmulator)(storageProcessed, storageHost, storagePort);
|
|
6401
|
+
(0, import_storage4.connectStorageEmulator)(storagePublic, storageHost, storagePort);
|
|
6282
6402
|
}
|
|
6283
|
-
const blob = new CueBlobStorage({ storageRaw, storageProcessed });
|
|
6403
|
+
const blob = new CueBlobStorage({ storageRaw, storageProcessed, storagePublic });
|
|
6284
6404
|
const syncApi = new CueSyncApi(this.auth, projects, blob, this._endpoints.gatewayUrl);
|
|
6285
6405
|
const api = new CueApi(this.auth, this._endpoints.gatewayUrl, projects, syncApi);
|
|
6286
6406
|
syncApi._bindApi(api);
|
|
@@ -6896,46 +7016,6 @@ async function repairTtlHandler(options) {
|
|
|
6896
7016
|
}
|
|
6897
7017
|
}
|
|
6898
7018
|
|
|
6899
|
-
// apps/desktop/cue-cli/src/helpers/emit-idle.ts
|
|
6900
|
-
var import_pubsub = require("@google-cloud/pubsub");
|
|
6901
|
-
async function emitIdle(spaceId, hoursBack, useEmulator) {
|
|
6902
|
-
const from = /* @__PURE__ */ new Date();
|
|
6903
|
-
from.setHours(from.getHours() - hoursBack);
|
|
6904
|
-
const message = {
|
|
6905
|
-
space_id: spaceId,
|
|
6906
|
-
first_write: from.toISOString(),
|
|
6907
|
-
last_write: (/* @__PURE__ */ new Date()).toISOString()
|
|
6908
|
-
};
|
|
6909
|
-
await publishMessage("RDF_WRITING_IDLE", message, useEmulator);
|
|
6910
|
-
}
|
|
6911
|
-
async function publishMessage(topicName, data, useEmulator) {
|
|
6912
|
-
if (useEmulator) {
|
|
6913
|
-
process.env.PUBSUB_EMULATOR_HOST = process.env.PUBSUB_EMULATOR_HOST || "localhost:8085";
|
|
6914
|
-
}
|
|
6915
|
-
const projectId = useEmulator ? "demo-project" : PROJECT_ID;
|
|
6916
|
-
const pubSubClient = new import_pubsub.PubSub({ projectId });
|
|
6917
|
-
const topic = pubSubClient.topic(topicName);
|
|
6918
|
-
const dataBuffer = Buffer.from(JSON.stringify(data));
|
|
6919
|
-
try {
|
|
6920
|
-
if (useEmulator) {
|
|
6921
|
-
const publishPromise = topic.publishMessage({ data: dataBuffer });
|
|
6922
|
-
const timeoutPromise = new Promise(
|
|
6923
|
-
(_, reject) => setTimeout(() => reject(new Error("PubSub publish timeout")), 5e3)
|
|
6924
|
-
);
|
|
6925
|
-
await Promise.race([publishPromise, timeoutPromise]);
|
|
6926
|
-
} else {
|
|
6927
|
-
await topic.publishMessage({ data: dataBuffer });
|
|
6928
|
-
}
|
|
6929
|
-
} catch (error) {
|
|
6930
|
-
console.error(`Error publishing message: ${error.message}`);
|
|
6931
|
-
if (useEmulator) {
|
|
6932
|
-
console.warn("Continuing despite PubSub error in emulator mode...");
|
|
6933
|
-
} else {
|
|
6934
|
-
throw error;
|
|
6935
|
-
}
|
|
6936
|
-
}
|
|
6937
|
-
}
|
|
6938
|
-
|
|
6939
7019
|
// apps/desktop/cue-cli/src/cue-cli-sync.ts
|
|
6940
7020
|
var import_promises7 = require("fs/promises");
|
|
6941
7021
|
var import_fs6 = require("fs");
|
|
@@ -7005,7 +7085,14 @@ async function syncHandler(options) {
|
|
|
7005
7085
|
console.info("Built sync base \u2705\n");
|
|
7006
7086
|
if (verbose)
|
|
7007
7087
|
console.info("Authenticating \u23F3");
|
|
7008
|
-
|
|
7088
|
+
let user;
|
|
7089
|
+
try {
|
|
7090
|
+
user = await cue.auth.signInWithApiKey(key, space);
|
|
7091
|
+
} catch (err) {
|
|
7092
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
7093
|
+
console.error(`Couldn't authenticate. ${cause}`);
|
|
7094
|
+
process.exit(1);
|
|
7095
|
+
}
|
|
7009
7096
|
if (verbose)
|
|
7010
7097
|
console.info("Authenticated \u2705\n");
|
|
7011
7098
|
if (verbose)
|
|
@@ -7016,25 +7103,28 @@ async function syncHandler(options) {
|
|
|
7016
7103
|
userId: user.uid,
|
|
7017
7104
|
verbose
|
|
7018
7105
|
});
|
|
7106
|
+
console.info(`Project is configured at the ${preview.tierName} tier`);
|
|
7019
7107
|
console.info("Cost estimate (new files only):");
|
|
7020
7108
|
if (preview.costRecords.length === 0) {
|
|
7021
7109
|
console.info(" Nothing new to sync.");
|
|
7022
7110
|
} else {
|
|
7023
7111
|
for (const r of preview.costRecords) {
|
|
7024
|
-
|
|
7112
|
+
const creditsStr = r.credits !== void 0 ? ` (${Math.round(r.credits)} credits)` : "";
|
|
7113
|
+
console.info(` .${r.ext}: ${r.count} file(s)${creditsStr}`);
|
|
7025
7114
|
}
|
|
7026
7115
|
}
|
|
7027
7116
|
console.info(` New files: ${preview.filesToUpload}/${preview.totalLocalFiles}`);
|
|
7028
|
-
console.info(`
|
|
7029
|
-
console.info(`
|
|
7117
|
+
console.info(` Credits required: ${Math.round(preview.creditsToConsume)}`);
|
|
7118
|
+
console.info(` Credits available: ${Math.round(preview.creditsAvailable)}
|
|
7030
7119
|
`);
|
|
7120
|
+
await cue.api.sync.flushPendingMetadata(space, verbose);
|
|
7031
7121
|
if (preview.filesToUpload === 0) {
|
|
7032
7122
|
console.info("Everything is already synced.");
|
|
7033
7123
|
process.exit(0);
|
|
7034
7124
|
}
|
|
7035
|
-
if (preview.
|
|
7125
|
+
if (preview.creditsToConsume > preview.creditsAvailable) {
|
|
7036
7126
|
console.error(
|
|
7037
|
-
`Insufficient
|
|
7127
|
+
`Insufficient credits: ${Math.round(preview.creditsToConsume)} required, ${Math.round(preview.creditsAvailable)} available.`
|
|
7038
7128
|
);
|
|
7039
7129
|
process.exit(1);
|
|
7040
7130
|
}
|
|
@@ -7047,24 +7137,14 @@ async function syncHandler(options) {
|
|
|
7047
7137
|
spaceId: space,
|
|
7048
7138
|
providerId: provider,
|
|
7049
7139
|
userId: user.uid,
|
|
7050
|
-
verbose
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
console.info(`Throwing RDF_WRITING_IDLE topic (only in emulators) \u23F3`);
|
|
7140
|
+
verbose,
|
|
7141
|
+
onProgress: ({ percent, syncCount, totalCount }) => {
|
|
7142
|
+
const filled = Math.round(percent / 5);
|
|
7143
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(20 - filled);
|
|
7144
|
+
process.stdout.write(`\r [${bar}] ${percent}% (${syncCount}/${totalCount} files) `);
|
|
7056
7145
|
}
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
if (verbose)
|
|
7060
|
-
console.info(`Threw RDF_WRITING_IDLE topic \u2705`);
|
|
7061
|
-
} catch (error) {
|
|
7062
|
-
if (verbose)
|
|
7063
|
-
console.error(`Error throwing RDF_WRITING_IDLE topic: ${error instanceof Error ? error.message : String(error)}`);
|
|
7064
|
-
if (verbose)
|
|
7065
|
-
console.warn("Continuing despite PubSub error in emulator mode...");
|
|
7066
|
-
}
|
|
7067
|
-
}
|
|
7146
|
+
});
|
|
7147
|
+
process.stdout.write("\n");
|
|
7068
7148
|
const zipDeletePromise = zip && !isFile ? deleteUnzipped(path) : Promise.resolve();
|
|
7069
7149
|
await zipDeletePromise;
|
|
7070
7150
|
if (zip && verbose)
|
|
@@ -7074,6 +7154,7 @@ async function syncHandler(options) {
|
|
|
7074
7154
|
console.info(
|
|
7075
7155
|
`Synced: ${result.syncCount}/${result.totalCount} files (${fileSizePretty(result.syncSize)}/${fileSizePretty(result.totalSize)})`
|
|
7076
7156
|
);
|
|
7157
|
+
console.info(`Credits remaining: ${Math.round(result.creditsAvailable)}`);
|
|
7077
7158
|
console.info(`Sync finished \u{1F680}\u{1F680}\u{1F680}`);
|
|
7078
7159
|
if (result.failedUploads > 0) {
|
|
7079
7160
|
console.warn(`Total files failed to upload: ${result.failedUploads}`);
|
|
@@ -7081,7 +7162,18 @@ async function syncHandler(options) {
|
|
|
7081
7162
|
}
|
|
7082
7163
|
process.exit(0);
|
|
7083
7164
|
} catch (err) {
|
|
7084
|
-
|
|
7165
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7166
|
+
if (msg.includes("GRAPH_TIMEOUT")) {
|
|
7167
|
+
console.error("Could not reach the knowledge graph. Make sure all required services are running.");
|
|
7168
|
+
} else if (msg.includes("METADATA_SYNC_FAILED")) {
|
|
7169
|
+
console.error("Metadata sync failed. Try again.");
|
|
7170
|
+
} else if (msg.includes("LEDGER_WRITE_FAILED") || msg.includes("File structure batch POST failed")) {
|
|
7171
|
+
console.error(
|
|
7172
|
+
"Failed communication with the knowledge graph. The files are up to date but metadata is not. Run the tool again to sync metadata. This is a swift job."
|
|
7173
|
+
);
|
|
7174
|
+
} else {
|
|
7175
|
+
console.error("[syncHandler] Unexpected error:", err);
|
|
7176
|
+
}
|
|
7085
7177
|
process.exit(1);
|
|
7086
7178
|
}
|
|
7087
7179
|
}
|