@qaecy/cue-cli 0.0.38 → 0.0.40
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 +403 -160
- package/package.json +2 -2
package/main.js
CHANGED
|
@@ -29,6 +29,68 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
mod
|
|
30
30
|
));
|
|
31
31
|
|
|
32
|
+
// libs/js/sync-tools/src/lib/helpers/worker-pool.js
|
|
33
|
+
var worker_pool_exports = {};
|
|
34
|
+
__export(worker_pool_exports, {
|
|
35
|
+
WorkerPool: () => WorkerPool
|
|
36
|
+
});
|
|
37
|
+
var Worker, os, WorkerPool;
|
|
38
|
+
var init_worker_pool = __esm({
|
|
39
|
+
"libs/js/sync-tools/src/lib/helpers/worker-pool.js"() {
|
|
40
|
+
({ Worker } = require("worker_threads"));
|
|
41
|
+
os = require("os");
|
|
42
|
+
WorkerPool = class {
|
|
43
|
+
constructor(workerPath, poolSize = os.cpus().length) {
|
|
44
|
+
this.workerPath = workerPath;
|
|
45
|
+
this.poolSize = poolSize;
|
|
46
|
+
this.workers = [];
|
|
47
|
+
this.idleWorkers = [];
|
|
48
|
+
this.queue = [];
|
|
49
|
+
for (let i = 0; i < poolSize; i++) {
|
|
50
|
+
const worker = new Worker(workerPath);
|
|
51
|
+
worker.on("message", (result) => {
|
|
52
|
+
const callback = worker._currentCallback;
|
|
53
|
+
worker._currentCallback = null;
|
|
54
|
+
this.idleWorkers.push(worker);
|
|
55
|
+
callback(result);
|
|
56
|
+
this._next();
|
|
57
|
+
});
|
|
58
|
+
worker.on("error", (err) => {
|
|
59
|
+
if (worker._currentCallback)
|
|
60
|
+
worker._currentCallback({ error: err.message });
|
|
61
|
+
this.idleWorkers.push(worker);
|
|
62
|
+
this._next();
|
|
63
|
+
});
|
|
64
|
+
this.workers.push(worker);
|
|
65
|
+
this.idleWorkers.push(worker);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
_next() {
|
|
69
|
+
if (this.queue.length > 0 && this.idleWorkers.length > 0) {
|
|
70
|
+
const { filePath, resolve: resolve2, reject } = this.queue.shift();
|
|
71
|
+
const worker = this.idleWorkers.pop();
|
|
72
|
+
worker._currentCallback = (result) => {
|
|
73
|
+
if (result.error)
|
|
74
|
+
reject(new Error(result.error));
|
|
75
|
+
else
|
|
76
|
+
resolve2(result.hash);
|
|
77
|
+
};
|
|
78
|
+
worker.postMessage(filePath);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
hashFile(filePath) {
|
|
82
|
+
return new Promise((resolve2, reject) => {
|
|
83
|
+
this.queue.push({ filePath, resolve: resolve2, reject });
|
|
84
|
+
this._next();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async close() {
|
|
88
|
+
await Promise.all(this.workers.map((worker) => worker.terminate()));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
32
94
|
// libs/js/id-builders/src/lib/id-builders.ts
|
|
33
95
|
function contextBasedGuid(contextString, verbose = false) {
|
|
34
96
|
const namespace = "daca0510-72b5-48ba-9091-b918ca18136b";
|
|
@@ -246,68 +308,6 @@ var init_src = __esm({
|
|
|
246
308
|
}
|
|
247
309
|
});
|
|
248
310
|
|
|
249
|
-
// libs/js/sync-tools/src/lib/helpers/worker-pool.js
|
|
250
|
-
var worker_pool_exports = {};
|
|
251
|
-
__export(worker_pool_exports, {
|
|
252
|
-
WorkerPool: () => WorkerPool
|
|
253
|
-
});
|
|
254
|
-
var Worker, os, WorkerPool;
|
|
255
|
-
var init_worker_pool = __esm({
|
|
256
|
-
"libs/js/sync-tools/src/lib/helpers/worker-pool.js"() {
|
|
257
|
-
({ Worker } = require("worker_threads"));
|
|
258
|
-
os = require("os");
|
|
259
|
-
WorkerPool = class {
|
|
260
|
-
constructor(workerPath, poolSize = os.cpus().length) {
|
|
261
|
-
this.workerPath = workerPath;
|
|
262
|
-
this.poolSize = poolSize;
|
|
263
|
-
this.workers = [];
|
|
264
|
-
this.idleWorkers = [];
|
|
265
|
-
this.queue = [];
|
|
266
|
-
for (let i = 0; i < poolSize; i++) {
|
|
267
|
-
const worker = new Worker(workerPath);
|
|
268
|
-
worker.on("message", (result) => {
|
|
269
|
-
const callback = worker._currentCallback;
|
|
270
|
-
worker._currentCallback = null;
|
|
271
|
-
this.idleWorkers.push(worker);
|
|
272
|
-
callback(result);
|
|
273
|
-
this._next();
|
|
274
|
-
});
|
|
275
|
-
worker.on("error", (err) => {
|
|
276
|
-
if (worker._currentCallback)
|
|
277
|
-
worker._currentCallback({ error: err.message });
|
|
278
|
-
this.idleWorkers.push(worker);
|
|
279
|
-
this._next();
|
|
280
|
-
});
|
|
281
|
-
this.workers.push(worker);
|
|
282
|
-
this.idleWorkers.push(worker);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
_next() {
|
|
286
|
-
if (this.queue.length > 0 && this.idleWorkers.length > 0) {
|
|
287
|
-
const { filePath, resolve: resolve2, reject } = this.queue.shift();
|
|
288
|
-
const worker = this.idleWorkers.pop();
|
|
289
|
-
worker._currentCallback = (result) => {
|
|
290
|
-
if (result.error)
|
|
291
|
-
reject(new Error(result.error));
|
|
292
|
-
else
|
|
293
|
-
resolve2(result.hash);
|
|
294
|
-
};
|
|
295
|
-
worker.postMessage(filePath);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
hashFile(filePath) {
|
|
299
|
-
return new Promise((resolve2, reject) => {
|
|
300
|
-
this.queue.push({ filePath, resolve: resolve2, reject });
|
|
301
|
-
this._next();
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
async close() {
|
|
305
|
-
await Promise.all(this.workers.map((worker) => worker.terminate()));
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
|
|
311
311
|
// libs/js/sync-tools/src/lib/helpers/md5-builder-node.ts
|
|
312
312
|
var md5_builder_node_exports = {};
|
|
313
313
|
__export(md5_builder_node_exports, {
|
|
@@ -545,11 +545,11 @@ var Fuseki = class _Fuseki {
|
|
|
545
545
|
}
|
|
546
546
|
}
|
|
547
547
|
async ping() {
|
|
548
|
-
const
|
|
549
|
-
const res = await this.query(
|
|
548
|
+
const query3 = "ASK { }";
|
|
549
|
+
const res = await this.query(query3);
|
|
550
550
|
return res.boolean;
|
|
551
551
|
}
|
|
552
|
-
async query(
|
|
552
|
+
async query(query3, accept = "application/sparql-results+json") {
|
|
553
553
|
let res;
|
|
554
554
|
try {
|
|
555
555
|
res = await fetch(this.queryEndpoint, {
|
|
@@ -559,7 +559,7 @@ var Fuseki = class _Fuseki {
|
|
|
559
559
|
Accept: accept
|
|
560
560
|
},
|
|
561
561
|
method: "POST",
|
|
562
|
-
body: new URLSearchParams({ query:
|
|
562
|
+
body: new URLSearchParams({ query: query3 })
|
|
563
563
|
});
|
|
564
564
|
} catch (err) {
|
|
565
565
|
throw new Error(
|
|
@@ -572,7 +572,7 @@ var Fuseki = class _Fuseki {
|
|
|
572
572
|
}
|
|
573
573
|
return await res.json();
|
|
574
574
|
}
|
|
575
|
-
async subset(
|
|
575
|
+
async subset(query3, accept = "text/turtle") {
|
|
576
576
|
const res = await fetch(this.queryEndpoint, {
|
|
577
577
|
headers: {
|
|
578
578
|
...this.baseHeaders,
|
|
@@ -581,7 +581,7 @@ var Fuseki = class _Fuseki {
|
|
|
581
581
|
Accept: accept
|
|
582
582
|
},
|
|
583
583
|
method: "POST",
|
|
584
|
-
body: new URLSearchParams({ query:
|
|
584
|
+
body: new URLSearchParams({ query: query3 })
|
|
585
585
|
});
|
|
586
586
|
if (accept === "application/ld+json") {
|
|
587
587
|
return await res.json();
|
|
@@ -679,11 +679,11 @@ var QLever = class _QLever {
|
|
|
679
679
|
this.baseHeaders["x-user-roles"] = "admin";
|
|
680
680
|
}
|
|
681
681
|
async ping() {
|
|
682
|
-
const
|
|
683
|
-
const res = await this.query(
|
|
682
|
+
const query3 = "ASK { }";
|
|
683
|
+
const res = await this.query(query3);
|
|
684
684
|
return res.boolean;
|
|
685
685
|
}
|
|
686
|
-
async query(
|
|
686
|
+
async query(query3, accept = "application/sparql-results+json") {
|
|
687
687
|
let res;
|
|
688
688
|
try {
|
|
689
689
|
res = await fetch(this.queryEndpoint, {
|
|
@@ -693,7 +693,7 @@ var QLever = class _QLever {
|
|
|
693
693
|
Accept: accept
|
|
694
694
|
},
|
|
695
695
|
method: "POST",
|
|
696
|
-
body: new URLSearchParams({ query:
|
|
696
|
+
body: new URLSearchParams({ query: query3 })
|
|
697
697
|
});
|
|
698
698
|
} catch (err) {
|
|
699
699
|
throw new Error(
|
|
@@ -706,7 +706,7 @@ var QLever = class _QLever {
|
|
|
706
706
|
}
|
|
707
707
|
return await res.json();
|
|
708
708
|
}
|
|
709
|
-
async subset(
|
|
709
|
+
async subset(query3, accept = "text/turtle") {
|
|
710
710
|
const res = await fetch(this.queryEndpoint, {
|
|
711
711
|
headers: {
|
|
712
712
|
...this.baseHeaders,
|
|
@@ -714,7 +714,7 @@ var QLever = class _QLever {
|
|
|
714
714
|
Accept: accept
|
|
715
715
|
},
|
|
716
716
|
method: "POST",
|
|
717
|
-
body: new URLSearchParams({ query:
|
|
717
|
+
body: new URLSearchParams({ query: query3 })
|
|
718
718
|
});
|
|
719
719
|
return await res.text();
|
|
720
720
|
}
|
|
@@ -4780,7 +4780,6 @@ async function getGraphFiles(providerId, queryHandler2) {
|
|
|
4780
4780
|
}
|
|
4781
4781
|
|
|
4782
4782
|
// libs/js/sync-tools/src/lib/list-local-files.ts
|
|
4783
|
-
init_src();
|
|
4784
4783
|
async function _path() {
|
|
4785
4784
|
return import("path");
|
|
4786
4785
|
}
|
|
@@ -4796,7 +4795,10 @@ async function listLocalFiles(dir, providerId = "", verbose = false, logInterval
|
|
|
4796
4795
|
if (verbose)
|
|
4797
4796
|
console.info(`Listing files in local dir: ${dir}`);
|
|
4798
4797
|
if (unzipZipped) {
|
|
4799
|
-
const zipFiles = await filesInLocalDirRecursive(
|
|
4798
|
+
const zipFiles = await filesInLocalDirRecursive(
|
|
4799
|
+
dir,
|
|
4800
|
+
(entry) => entry.name.toLowerCase().endsWith(".zip")
|
|
4801
|
+
);
|
|
4800
4802
|
if (zipFiles.length && verbose)
|
|
4801
4803
|
console.info(`Found ${zipFiles.length} zip files to unzip...`);
|
|
4802
4804
|
for (const zipFile of zipFiles) {
|
|
@@ -4825,13 +4827,22 @@ async function listLocalFiles(dir, providerId = "", verbose = false, logInterval
|
|
|
4825
4827
|
const { stat } = await _fs();
|
|
4826
4828
|
const { relative } = await _path();
|
|
4827
4829
|
const stats = await Promise.all(fullPaths.map((f) => stat(f)));
|
|
4830
|
+
const { contextBasedGuid: contextBasedGuid2, generateFileUUID: generateFileUUID2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
4828
4831
|
return fullPaths.map((f, i) => {
|
|
4829
4832
|
const relativePath = relative(dir, f);
|
|
4830
4833
|
const md5 = hashes[i];
|
|
4831
|
-
const contentUUID =
|
|
4832
|
-
const locationUUID =
|
|
4834
|
+
const contentUUID = contextBasedGuid2(md5);
|
|
4835
|
+
const locationUUID = generateFileUUID2(relativePath, providerId);
|
|
4833
4836
|
const { mtimeMs, size } = stats[i];
|
|
4834
|
-
return {
|
|
4837
|
+
return {
|
|
4838
|
+
relativePath,
|
|
4839
|
+
fullPath: f,
|
|
4840
|
+
size,
|
|
4841
|
+
md5,
|
|
4842
|
+
contentUUID,
|
|
4843
|
+
locationUUID,
|
|
4844
|
+
mtimeMs
|
|
4845
|
+
};
|
|
4835
4846
|
});
|
|
4836
4847
|
}
|
|
4837
4848
|
async function filesInLocalDirRecursive(dir, filterFunc = () => true, excludeDirs = true) {
|
|
@@ -4864,7 +4875,9 @@ async function filesInLocalDirRecursive(dir, filterFunc = () => true, excludeDir
|
|
|
4864
4875
|
if (error instanceof Error && "code" in error) {
|
|
4865
4876
|
const nodeError = error;
|
|
4866
4877
|
if (nodeError.code === "EPERM" || nodeError.code === "EACCES") {
|
|
4867
|
-
console.warn(
|
|
4878
|
+
console.warn(
|
|
4879
|
+
`Skipping directory due to permission error: ${currentDir}`
|
|
4880
|
+
);
|
|
4868
4881
|
return;
|
|
4869
4882
|
}
|
|
4870
4883
|
}
|
|
@@ -4882,7 +4895,9 @@ async function unzipFile(zipPath, recursive = true, options) {
|
|
|
4882
4895
|
const currentDepth = options?.currentDepth ?? 0;
|
|
4883
4896
|
const totalUncompressedSize = options?.totalUncompressedSize ?? { value: 0 };
|
|
4884
4897
|
if (currentDepth > maxRecursionDepth) {
|
|
4885
|
-
throw new Error(
|
|
4898
|
+
throw new Error(
|
|
4899
|
+
`Zip extraction aborted: exceeded max recursion depth (${maxRecursionDepth})`
|
|
4900
|
+
);
|
|
4886
4901
|
}
|
|
4887
4902
|
const { mkdir: mkdir2, readFile, writeFile: writeFile2 } = await _fs();
|
|
4888
4903
|
const { join: join4 } = await _path();
|
|
@@ -4901,7 +4916,9 @@ async function unzipFile(zipPath, recursive = true, options) {
|
|
|
4901
4916
|
const promise = file.async("nodebuffer").then(async (content) => {
|
|
4902
4917
|
totalUncompressedSize.value += content.length;
|
|
4903
4918
|
if (totalUncompressedSize.value > maxUncompressedSize) {
|
|
4904
|
-
throw new Error(
|
|
4919
|
+
throw new Error(
|
|
4920
|
+
`Zip extraction aborted: exceeded max uncompressed size (${maxUncompressedSize} bytes)`
|
|
4921
|
+
);
|
|
4905
4922
|
}
|
|
4906
4923
|
await writeFile2(targetPath, content);
|
|
4907
4924
|
if (recursive && targetPath.toLowerCase().endsWith(".zip")) {
|
|
@@ -4924,7 +4941,11 @@ async function ensureDir(path) {
|
|
|
4924
4941
|
}
|
|
4925
4942
|
async function deleteUnzipped(dir) {
|
|
4926
4943
|
const { rm } = await _fs();
|
|
4927
|
-
const paths = await filesInLocalDirRecursive(
|
|
4944
|
+
const paths = await filesInLocalDirRecursive(
|
|
4945
|
+
dir,
|
|
4946
|
+
(entry) => entry.name.toLowerCase().endsWith(UNZIPPED_SUFFIX),
|
|
4947
|
+
false
|
|
4948
|
+
);
|
|
4928
4949
|
for (const p of paths) {
|
|
4929
4950
|
await rm(p, { recursive: true, force: true });
|
|
4930
4951
|
}
|
|
@@ -4932,7 +4953,7 @@ async function deleteUnzipped(dir) {
|
|
|
4932
4953
|
|
|
4933
4954
|
// apps/desktop/cue-cli/src/helpers/query-handler.ts
|
|
4934
4955
|
var import_auth2 = require("firebase/auth");
|
|
4935
|
-
async function queryHandler(
|
|
4956
|
+
async function queryHandler(query3, spaceId, useEmulator) {
|
|
4936
4957
|
const endpoint = useEmulator ? SPARQL_ENDPOINT_EMULATOR : SPARQL_ENDPOINT;
|
|
4937
4958
|
const token = await (0, import_auth2.getAuth)().currentUser?.getIdToken();
|
|
4938
4959
|
const res = await fetch(endpoint, {
|
|
@@ -4943,7 +4964,7 @@ async function queryHandler(query4, spaceId, useEmulator) {
|
|
|
4943
4964
|
"Content-Type": "application/sparql-query",
|
|
4944
4965
|
Accept: "application/sparql-results+json"
|
|
4945
4966
|
},
|
|
4946
|
-
body:
|
|
4967
|
+
body: query3
|
|
4947
4968
|
});
|
|
4948
4969
|
if (!res.ok) {
|
|
4949
4970
|
console.error(
|
|
@@ -5027,8 +5048,8 @@ function cueComputed(deps, compute) {
|
|
|
5027
5048
|
}
|
|
5028
5049
|
};
|
|
5029
5050
|
}
|
|
5030
|
-
async function staleWhileRevalidate(
|
|
5031
|
-
const cacheKey = contextBasedGuid(
|
|
5051
|
+
async function staleWhileRevalidate(query3, fetchFresh, onData, cache) {
|
|
5052
|
+
const cacheKey = contextBasedGuid(query3);
|
|
5032
5053
|
let staleId;
|
|
5033
5054
|
if (cache) {
|
|
5034
5055
|
const stale = await cache.get(cacheKey);
|
|
@@ -5059,8 +5080,6 @@ var DEFAULT_SDK_CONFIG = {
|
|
|
5059
5080
|
var FIREBASE_PROJECT_ID = "qaecy-mvp-406413";
|
|
5060
5081
|
var FIREBASE_SENDER_ID = "734737865998";
|
|
5061
5082
|
var GCP_REGION2 = "europe-west6";
|
|
5062
|
-
var COLLECTION_API_KEYS2 = "apiKeys";
|
|
5063
|
-
var COLLECTION_ORGANIZATIONS2 = "organizations";
|
|
5064
5083
|
var COLLECTION_PROJECTS2 = "projects";
|
|
5065
5084
|
var BUCKET_CHAT_SESSIONS2 = "spaces_chats_eu_west6";
|
|
5066
5085
|
var BUCKET_RAW2 = "spaces_raw_eu_west6";
|
|
@@ -5069,6 +5088,9 @@ var BUCKET_LOGS2 = "spaces_logs_eu_west6";
|
|
|
5069
5088
|
var BUCKET_PUBLIC2 = "cue_public_eu_west6";
|
|
5070
5089
|
var BUCKET_PERSISTENCE2 = "db_persistence_eu_west6";
|
|
5071
5090
|
var ENDPOINT_CONSUMPTION = "/data-views/admin/consumption";
|
|
5091
|
+
var ENDPOINT_PROFILE_ORGANIZATIONS = "/data-views/admin/profile/organizations";
|
|
5092
|
+
var ENDPOINT_PROFILE_API_KEYS = "/data-views/admin/profile/api-keys";
|
|
5093
|
+
var ENDPOINT_ORG_MEMBERS = (orgId) => `/data-views/admin/organizations/${orgId}/members`;
|
|
5072
5094
|
var ENDPOINT_CREATE_PROJECT = "/commands/admin/project";
|
|
5073
5095
|
var ENDPOINT_SEARCH = "/assistant/search";
|
|
5074
5096
|
var ENDPOINT_FUSEKI_QUERY = "/triplestore/query";
|
|
@@ -5180,14 +5202,14 @@ var CueAuth = class {
|
|
|
5180
5202
|
const tokenResult = await (0, import_auth3.getIdTokenResult)(user);
|
|
5181
5203
|
return tokenResult.claims["role"] === SUPERADMIN_ROLE;
|
|
5182
5204
|
}
|
|
5183
|
-
/** Sign in with a Cue API key */
|
|
5205
|
+
/** Sign in with a Cue API key. `projectId` is optional — omit it when no project context is available (e.g. admin flows). */
|
|
5184
5206
|
async signInWithApiKey(cueApiKey, projectId) {
|
|
5207
|
+
const headers = { "cue-api-key": cueApiKey };
|
|
5208
|
+
if (projectId)
|
|
5209
|
+
headers["x-project-id"] = projectId;
|
|
5185
5210
|
const response = await fetch(this._endpoints.tokenUrl, {
|
|
5186
5211
|
method: "GET",
|
|
5187
|
-
headers
|
|
5188
|
-
"x-project-id": projectId,
|
|
5189
|
-
"cue-api-key": cueApiKey
|
|
5190
|
-
}
|
|
5212
|
+
headers
|
|
5191
5213
|
});
|
|
5192
5214
|
if (!response.ok)
|
|
5193
5215
|
throw new Error(`Failed to fetch custom token: ${response.statusText}`);
|
|
@@ -5293,12 +5315,12 @@ var CueApi = class {
|
|
|
5293
5315
|
* Execute a SPARQL query against the project's triplestore.
|
|
5294
5316
|
* The user must be authenticated before calling this.
|
|
5295
5317
|
*/
|
|
5296
|
-
async sparql(
|
|
5318
|
+
async sparql(query3, projectId, graphType) {
|
|
5297
5319
|
console.log(graphType);
|
|
5298
5320
|
const endpoint = graphType === "qlever" ? ENDPOINT_QLEVER_QUERY : ENDPOINT_FUSEKI_QUERY;
|
|
5299
5321
|
console.log(`Executing SPARQL query against ${endpoint} for project ${projectId} with graph type ${graphType ?? "fuseki"}`);
|
|
5300
5322
|
const urlencoded = new URLSearchParams();
|
|
5301
|
-
urlencoded.append("query",
|
|
5323
|
+
urlencoded.append("query", query3);
|
|
5302
5324
|
const response = await this._auth.authenticatedFetch(
|
|
5303
5325
|
`${this._gatewayUrl}${endpoint}`,
|
|
5304
5326
|
{
|
|
@@ -5434,27 +5456,32 @@ var CueProjects = class {
|
|
|
5434
5456
|
|
|
5435
5457
|
// libs/js/cue-sdk/src/lib/profile.ts
|
|
5436
5458
|
var import_auth4 = require("firebase/auth");
|
|
5437
|
-
var import_firestore4 = require("firebase/firestore");
|
|
5438
5459
|
var import_functions3 = require("firebase/functions");
|
|
5439
5460
|
var CueProfile = class {
|
|
5440
|
-
constructor(_auth, app, useEmulator,
|
|
5461
|
+
constructor(_auth, app, useEmulator, _gatewayUrl) {
|
|
5441
5462
|
this._auth = _auth;
|
|
5442
|
-
this.
|
|
5463
|
+
this._gatewayUrl = _gatewayUrl;
|
|
5443
5464
|
this._functions = (0, import_functions3.getFunctions)(app, GCP_REGION2);
|
|
5444
5465
|
if (useEmulator) {
|
|
5445
|
-
(0, import_firestore4.connectFirestoreEmulator)(this._db, emulatorHost, emulatorPort);
|
|
5446
5466
|
(0, import_functions3.connectFunctionsEmulator)(this._functions, "localhost", 5001);
|
|
5447
5467
|
}
|
|
5448
5468
|
}
|
|
5449
|
-
_db;
|
|
5450
5469
|
_functions;
|
|
5451
|
-
|
|
5470
|
+
_url(endpoint) {
|
|
5471
|
+
return `${this._gatewayUrl}${endpoint}`;
|
|
5472
|
+
}
|
|
5473
|
+
async _fetch(path, init) {
|
|
5474
|
+
const response = await this._auth.authenticatedFetch(this._url(path), init);
|
|
5475
|
+
if (!response.ok) {
|
|
5476
|
+
throw new Error(`Profile API error ${response.status}: ${response.statusText}`);
|
|
5477
|
+
}
|
|
5478
|
+
const text = await response.text();
|
|
5479
|
+
return text ? JSON.parse(text) : null;
|
|
5480
|
+
}
|
|
5452
5481
|
/** Whether the current user has an active API key. */
|
|
5453
5482
|
async hasAPIKey() {
|
|
5454
|
-
const
|
|
5455
|
-
|
|
5456
|
-
return false;
|
|
5457
|
-
return this._checkIfUserHasAPIKey(uid);
|
|
5483
|
+
const info = await this._fetch(ENDPOINT_PROFILE_API_KEYS);
|
|
5484
|
+
return info !== null;
|
|
5458
5485
|
}
|
|
5459
5486
|
/** Returns the sign-in methods registered for the current user's email. */
|
|
5460
5487
|
async getSignInMethods() {
|
|
@@ -5522,47 +5549,36 @@ var CueProfile = class {
|
|
|
5522
5549
|
}
|
|
5523
5550
|
/** Creates a new API key for the current user. */
|
|
5524
5551
|
async createAPIKey(expiration) {
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
const data = { key: `cue-${randomKey}`, uid, expiration };
|
|
5531
|
-
const col = (0, import_firestore4.collection)(this._db, COLLECTION_API_KEYS2);
|
|
5532
|
-
this._apiKeyDocRef = await (0, import_firestore4.addDoc)(col, data);
|
|
5533
|
-
return data;
|
|
5552
|
+
return this._fetch(ENDPOINT_PROFILE_API_KEYS, {
|
|
5553
|
+
method: "POST",
|
|
5554
|
+
headers: { "Content-Type": "application/json" },
|
|
5555
|
+
body: JSON.stringify({ expiration })
|
|
5556
|
+
});
|
|
5534
5557
|
}
|
|
5535
5558
|
/** Revokes the current user's API key. */
|
|
5536
5559
|
async revokeAPIKey() {
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5560
|
+
const response = await this._auth.authenticatedFetch(
|
|
5561
|
+
this._url(ENDPOINT_PROFILE_API_KEYS),
|
|
5562
|
+
{ method: "DELETE" }
|
|
5563
|
+
);
|
|
5564
|
+
if (!response.ok) {
|
|
5565
|
+
throw new Error(`Revoke API key error ${response.status}: ${response.statusText}`);
|
|
5566
|
+
}
|
|
5541
5567
|
}
|
|
5542
5568
|
/** Fetches the current user's existing API key. */
|
|
5543
5569
|
async requestAPIKey() {
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
return
|
|
5548
|
-
}
|
|
5549
|
-
|
|
5550
|
-
const col = (0, import_firestore4.collection)(this._db, COLLECTION_API_KEYS2);
|
|
5551
|
-
const q = (0, import_firestore4.query)(col, (0, import_firestore4.where)("uid", "==", uid), (0, import_firestore4.limit)(1));
|
|
5552
|
-
const snapshot = await (0, import_firestore4.getDocs)(q);
|
|
5553
|
-
if (!snapshot.empty)
|
|
5554
|
-
this._apiKeyDocRef = snapshot.docs[0].ref;
|
|
5555
|
-
return !snapshot.empty;
|
|
5556
|
-
}
|
|
5557
|
-
/** Returns all organizations the current user is a member of. */
|
|
5570
|
+
const result = await this._fetch(ENDPOINT_PROFILE_API_KEYS);
|
|
5571
|
+
if (!result)
|
|
5572
|
+
throw new Error("No API key found");
|
|
5573
|
+
return result;
|
|
5574
|
+
}
|
|
5575
|
+
/** Returns organizations the current user is a member of. */
|
|
5558
5576
|
async listOrganizations() {
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
const snap = await (0, import_firestore4.getDocs)(q);
|
|
5565
|
-
return snap.docs.map((d) => d.data());
|
|
5577
|
+
return this._fetch(ENDPOINT_PROFILE_ORGANIZATIONS);
|
|
5578
|
+
}
|
|
5579
|
+
/** Returns all members of the given organisation. Caller must be an org admin or superadmin. */
|
|
5580
|
+
async getOrgMembers(orgId) {
|
|
5581
|
+
return this._fetch(ENDPOINT_ORG_MEMBERS(orgId));
|
|
5566
5582
|
}
|
|
5567
5583
|
_requireUser() {
|
|
5568
5584
|
const user = this._auth.currentUser;
|
|
@@ -5866,8 +5882,8 @@ WHERE {
|
|
|
5866
5882
|
}
|
|
5867
5883
|
GROUP BY ?iri ?parent`;
|
|
5868
5884
|
}
|
|
5869
|
-
async _runCategoriesQuery(
|
|
5870
|
-
const data = await this._api.sparql(
|
|
5885
|
+
async _runCategoriesQuery(query3) {
|
|
5886
|
+
const data = await this._api.sparql(query3, this._projectId, this._graphType);
|
|
5871
5887
|
return data.results.bindings.filter((b) => b["iri"] !== void 0).map((b) => {
|
|
5872
5888
|
const iri = b["iri"].value;
|
|
5873
5889
|
return {
|
|
@@ -5894,8 +5910,8 @@ WHERE {
|
|
|
5894
5910
|
}
|
|
5895
5911
|
GROUP BY ?iri ?parent`;
|
|
5896
5912
|
}
|
|
5897
|
-
async _runRelationshipsQuery(
|
|
5898
|
-
const data = await this._api.sparql(
|
|
5913
|
+
async _runRelationshipsQuery(query3) {
|
|
5914
|
+
const data = await this._api.sparql(query3, this._projectId, this._graphType);
|
|
5899
5915
|
return data.results.bindings.filter((b) => b["iri"] !== void 0).map((b) => {
|
|
5900
5916
|
const iri = b["iri"].value;
|
|
5901
5917
|
return {
|
|
@@ -7707,13 +7723,16 @@ function uploadedFileMetadata(originalName, projectId, userId, md5, providerId,
|
|
|
7707
7723
|
}
|
|
7708
7724
|
|
|
7709
7725
|
// libs/js/cue-sdk/src/lib/sync.ts
|
|
7726
|
+
async function _fs2() {
|
|
7727
|
+
return import("fs/promises");
|
|
7728
|
+
}
|
|
7710
7729
|
async function _readNodeFile(fullPath) {
|
|
7711
7730
|
if (typeof window !== "undefined") {
|
|
7712
7731
|
throw new Error(
|
|
7713
7732
|
`Cannot read file from path "${fullPath}" in a browser environment. Provide file.data (Uint8Array) instead.`
|
|
7714
7733
|
);
|
|
7715
7734
|
}
|
|
7716
|
-
const { readFile } = await
|
|
7735
|
+
const { readFile } = await _fs2();
|
|
7717
7736
|
return readFile(fullPath);
|
|
7718
7737
|
}
|
|
7719
7738
|
var _scanFn = null;
|
|
@@ -7739,7 +7758,7 @@ async function _initWasm() {
|
|
|
7739
7758
|
await mod.default({ module_or_path: wasmBinary });
|
|
7740
7759
|
_scanFn = mod.scan;
|
|
7741
7760
|
} else {
|
|
7742
|
-
const { readFile } = await
|
|
7761
|
+
const { readFile } = await _fs2();
|
|
7743
7762
|
const { join: join4 } = await import("path");
|
|
7744
7763
|
const { pathToFileURL } = await import("url");
|
|
7745
7764
|
const wasmDir = join4(__dirname, "assets", "wasm");
|
|
@@ -7767,7 +7786,7 @@ async function _loadPending(spaceId) {
|
|
|
7767
7786
|
return raw ? JSON.parse(raw) : null;
|
|
7768
7787
|
}
|
|
7769
7788
|
try {
|
|
7770
|
-
const raw = await (await
|
|
7789
|
+
const raw = await (await _fs2()).readFile(await _pendingFilePath(spaceId), "utf-8");
|
|
7771
7790
|
return JSON.parse(raw);
|
|
7772
7791
|
} catch {
|
|
7773
7792
|
return null;
|
|
@@ -7779,7 +7798,7 @@ async function _savePending(batch) {
|
|
|
7779
7798
|
window.localStorage.setItem(`${PENDING_LS_PREFIX}${batch.spaceId}`, data);
|
|
7780
7799
|
return;
|
|
7781
7800
|
}
|
|
7782
|
-
await (await
|
|
7801
|
+
await (await _fs2()).writeFile(await _pendingFilePath(batch.spaceId), data, "utf-8");
|
|
7783
7802
|
}
|
|
7784
7803
|
async function _clearPending(spaceId) {
|
|
7785
7804
|
if (typeof window !== "undefined") {
|
|
@@ -7787,7 +7806,7 @@ async function _clearPending(spaceId) {
|
|
|
7787
7806
|
return;
|
|
7788
7807
|
}
|
|
7789
7808
|
try {
|
|
7790
|
-
await (await
|
|
7809
|
+
await (await _fs2()).unlink(await _pendingFilePath(spaceId));
|
|
7791
7810
|
} catch {
|
|
7792
7811
|
}
|
|
7793
7812
|
}
|
|
@@ -8115,9 +8134,13 @@ WHERE {
|
|
|
8115
8134
|
}
|
|
8116
8135
|
}
|
|
8117
8136
|
const timer = setInterval(() => {
|
|
8118
|
-
this._drainPending(verbose).catch(
|
|
8119
|
-
|
|
8120
|
-
|
|
8137
|
+
this._drainPending(verbose).catch((err) => {
|
|
8138
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8139
|
+
console.warn(
|
|
8140
|
+
`\u26A0\uFE0F Metadata flush failed (will retry on next tick): ${msg}
|
|
8141
|
+
Pending items are saved locally and will be re-sent automatically.`
|
|
8142
|
+
);
|
|
8143
|
+
});
|
|
8121
8144
|
}, 6e4);
|
|
8122
8145
|
if (typeof timer === "object" && typeof timer.unref === "function") {
|
|
8123
8146
|
timer.unref();
|
|
@@ -8405,8 +8428,7 @@ var Cue = class _Cue {
|
|
|
8405
8428
|
this.auth,
|
|
8406
8429
|
this._app,
|
|
8407
8430
|
this._isEmulator,
|
|
8408
|
-
this._endpoints.
|
|
8409
|
-
this._endpoints.firestoreEmulatorPort
|
|
8431
|
+
this._endpoints.gatewayUrl
|
|
8410
8432
|
);
|
|
8411
8433
|
this.privileges = new CuePrivileges(this.auth.isSuperAdmin);
|
|
8412
8434
|
const storagePersistence = (0, import_storage5.getStorage)(this._app, BUCKET_PERSISTENCE2);
|
|
@@ -8453,7 +8475,7 @@ var Cue = class _Cue {
|
|
|
8453
8475
|
const syncApi = new CueSyncApi(auth, projects, blob, endpoints.gatewayUrl);
|
|
8454
8476
|
const api = new CueApi(auth, endpoints.gatewayUrl, projects, syncApi);
|
|
8455
8477
|
syncApi._bindApi(api);
|
|
8456
|
-
const profile = new CueProfile(auth, app, false, endpoints.
|
|
8478
|
+
const profile = new CueProfile(auth, app, false, endpoints.gatewayUrl);
|
|
8457
8479
|
const instance = Object.create(_Cue.prototype);
|
|
8458
8480
|
const privileges = new CuePrivileges(auth.isSuperAdmin);
|
|
8459
8481
|
const cache = new CueCache(storagePersistence);
|
|
@@ -8582,7 +8604,7 @@ async function compareHandler(options) {
|
|
|
8582
8604
|
await authenticate(emulators, space, options.key, verbose);
|
|
8583
8605
|
if (verbose)
|
|
8584
8606
|
console.info("Building compare base \u23F3");
|
|
8585
|
-
const qh = async (
|
|
8607
|
+
const qh = async (query3) => queryHandler(query3, space, emulators);
|
|
8586
8608
|
const [localFiles, remoteFiles] = await Promise.all([
|
|
8587
8609
|
listLocalFiles(
|
|
8588
8610
|
path,
|
|
@@ -8913,7 +8935,7 @@ async function _doGzip(filePath) {
|
|
|
8913
8935
|
});
|
|
8914
8936
|
await (0, import_promises3.unlink)(filePath);
|
|
8915
8937
|
}
|
|
8916
|
-
async function _doQuery(
|
|
8938
|
+
async function _doQuery(query3, spaceId, url) {
|
|
8917
8939
|
const token = await (0, import_auth9.getAuth)().currentUser?.getIdToken();
|
|
8918
8940
|
try {
|
|
8919
8941
|
const res = await fetch(url, {
|
|
@@ -8924,7 +8946,7 @@ async function _doQuery(query4, spaceId, url) {
|
|
|
8924
8946
|
"Content-Type": "application/sparql-query",
|
|
8925
8947
|
Accept: "application/n-quads"
|
|
8926
8948
|
},
|
|
8927
|
-
body:
|
|
8949
|
+
body: query3
|
|
8928
8950
|
});
|
|
8929
8951
|
if (!res.ok) {
|
|
8930
8952
|
console.error(`Error: ${res.status} ${res.statusText}`);
|
|
@@ -9032,7 +9054,7 @@ async function uploadToLocalGraph(id, filePath, mimeType = "application/n-quads"
|
|
|
9032
9054
|
|
|
9033
9055
|
// apps/desktop/cue-cli/src/cue-cli-dump.ts
|
|
9034
9056
|
async function dumpHandler(options) {
|
|
9035
|
-
const { space, verbose, emulators, jelly, query:
|
|
9057
|
+
const { space, verbose, emulators, jelly, query: query3, load } = options;
|
|
9036
9058
|
try {
|
|
9037
9059
|
const { isSuperAdmin } = await authenticate(emulators, space, options.key, verbose);
|
|
9038
9060
|
if (!isSuperAdmin) {
|
|
@@ -9053,7 +9075,7 @@ async function dumpHandler(options) {
|
|
|
9053
9075
|
} else {
|
|
9054
9076
|
if (verbose)
|
|
9055
9077
|
console.time("Downloaded and zipped graph \u2705");
|
|
9056
|
-
if (
|
|
9078
|
+
if (query3) {
|
|
9057
9079
|
if (verbose)
|
|
9058
9080
|
console.info("Setting: Construct query");
|
|
9059
9081
|
filePath = await dumpRdfGraphToFileConstruct(space, emulators, verbose);
|
|
@@ -9511,6 +9533,226 @@ Triples only in file 2 (${result.triplesOnlyInFile2.size}):`);
|
|
|
9511
9533
|
process.exitCode = 1;
|
|
9512
9534
|
}
|
|
9513
9535
|
|
|
9536
|
+
// apps/desktop/cue-cli/src/cue-cli-create-project.ts
|
|
9537
|
+
var readline2 = __toESM(require("readline"));
|
|
9538
|
+
function ask(rl, question) {
|
|
9539
|
+
return new Promise((resolve2) => rl.question(question, (answer) => resolve2(answer.trim())));
|
|
9540
|
+
}
|
|
9541
|
+
async function pickOne(rl, label, items, display) {
|
|
9542
|
+
console.log(`
|
|
9543
|
+
${label}`);
|
|
9544
|
+
items.forEach((item, i) => console.log(` ${i + 1}. ${display(item)}`));
|
|
9545
|
+
while (true) {
|
|
9546
|
+
const answer = await ask(rl, `Enter number (1-${items.length}): `);
|
|
9547
|
+
const idx = parseInt(answer, 10) - 1;
|
|
9548
|
+
if (idx >= 0 && idx < items.length)
|
|
9549
|
+
return items[idx];
|
|
9550
|
+
console.log(" Invalid selection, try again.");
|
|
9551
|
+
}
|
|
9552
|
+
}
|
|
9553
|
+
async function pickMultipleOrAll(rl, label, items, display) {
|
|
9554
|
+
if (items.length === 0)
|
|
9555
|
+
return [];
|
|
9556
|
+
console.log(`
|
|
9557
|
+
${label}`);
|
|
9558
|
+
items.forEach((item, i) => console.log(` ${i + 1}. ${display(item)}`));
|
|
9559
|
+
console.log(` 0. All`);
|
|
9560
|
+
const answer = await ask(rl, `Enter comma-separated numbers or 0 for all: `);
|
|
9561
|
+
if (answer === "0")
|
|
9562
|
+
return items;
|
|
9563
|
+
const indices = answer.split(",").map((s) => parseInt(s.trim(), 10) - 1).filter((i) => i >= 0 && i < items.length);
|
|
9564
|
+
return [...new Set(indices)].map((i) => items[i]);
|
|
9565
|
+
}
|
|
9566
|
+
async function createProjectHandler(options) {
|
|
9567
|
+
const { emulators, verbose } = options;
|
|
9568
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
9569
|
+
try {
|
|
9570
|
+
const key = options.key ?? process.env.CUE_API_KEY;
|
|
9571
|
+
if (!key) {
|
|
9572
|
+
console.error("API key is required. Provide it via --key or CUE_API_KEY env variable.");
|
|
9573
|
+
process.exit(1);
|
|
9574
|
+
}
|
|
9575
|
+
const cue = new CueNode({
|
|
9576
|
+
apiKey: FIREBASE_CONFIG().apiKey,
|
|
9577
|
+
appId: FIREBASE_CONFIG().appId,
|
|
9578
|
+
measurementId: FIREBASE_CONFIG().measurementId,
|
|
9579
|
+
environment: emulators ? "emulator" : "production",
|
|
9580
|
+
...emulators ? { endpoints: getEmulatorEndpoints() } : {}
|
|
9581
|
+
});
|
|
9582
|
+
if (verbose)
|
|
9583
|
+
console.info("Authenticating \u23F3");
|
|
9584
|
+
const user = await cue.auth.signInWithApiKey(key);
|
|
9585
|
+
const idTokenResult = await user.getIdTokenResult();
|
|
9586
|
+
const isSuperAdmin = idTokenResult.claims["role"] === "superadmin";
|
|
9587
|
+
if (verbose)
|
|
9588
|
+
console.info(`Authenticated as ${user.uid} (superadmin: ${isSuperAdmin}) \u2705`);
|
|
9589
|
+
const gatewayUrl = emulators ? getEmulatorEndpoints().gatewayUrl : "https://accessors-api-gateway-ueyeemwf2a-oa.a.run.app";
|
|
9590
|
+
let orgId;
|
|
9591
|
+
let orgName;
|
|
9592
|
+
let orgMembers = [];
|
|
9593
|
+
let callerIsOrgAdmin = false;
|
|
9594
|
+
if (isSuperAdmin) {
|
|
9595
|
+
const orgsRes = await cue.auth.authenticatedFetch(`${gatewayUrl}/data-views/admin/organizations`);
|
|
9596
|
+
if (!orgsRes.ok) {
|
|
9597
|
+
console.error(`Failed to list organisations: ${orgsRes.status} ${orgsRes.statusText}`);
|
|
9598
|
+
process.exit(1);
|
|
9599
|
+
}
|
|
9600
|
+
const allOrgs = await orgsRes.json();
|
|
9601
|
+
if (allOrgs.length === 0) {
|
|
9602
|
+
console.error("No organisations found on the platform.");
|
|
9603
|
+
process.exit(1);
|
|
9604
|
+
}
|
|
9605
|
+
const picked = await pickOne(rl, "Select organisation:", allOrgs, (o) => `${o.name} (${o.id})`);
|
|
9606
|
+
orgId = picked.id;
|
|
9607
|
+
orgName = picked.name;
|
|
9608
|
+
callerIsOrgAdmin = picked.admins?.includes(user.uid) ?? false;
|
|
9609
|
+
const membersRes = await cue.auth.authenticatedFetch(`${gatewayUrl}/data-views/admin/organizations/${orgId}/members`);
|
|
9610
|
+
if (membersRes.ok)
|
|
9611
|
+
orgMembers = await membersRes.json();
|
|
9612
|
+
} else {
|
|
9613
|
+
const myOrgs = await cue.profile.listOrganizations();
|
|
9614
|
+
const adminOrgs = myOrgs.filter((o) => o.isAdmin);
|
|
9615
|
+
if (adminOrgs.length === 0) {
|
|
9616
|
+
console.error("You are not an admin of any organisation. Cannot create a project.");
|
|
9617
|
+
process.exit(1);
|
|
9618
|
+
}
|
|
9619
|
+
const picked = await pickOne(rl, "Select organisation:", adminOrgs, (o) => `${o.name} (${o.id})`);
|
|
9620
|
+
orgId = picked.id;
|
|
9621
|
+
orgName = picked.name;
|
|
9622
|
+
callerIsOrgAdmin = true;
|
|
9623
|
+
orgMembers = await cue.profile.getOrgMembers(orgId);
|
|
9624
|
+
}
|
|
9625
|
+
console.log(`
|
|
9626
|
+
Organisation: ${orgName} (${orgId})`);
|
|
9627
|
+
const projectName = await ask(rl, "\nProject name: ");
|
|
9628
|
+
if (!projectName) {
|
|
9629
|
+
console.error("Project name is required.");
|
|
9630
|
+
process.exit(1);
|
|
9631
|
+
}
|
|
9632
|
+
const graphType = await pickOne(
|
|
9633
|
+
rl,
|
|
9634
|
+
"Select graph backend (default: QLever):",
|
|
9635
|
+
[
|
|
9636
|
+
{ value: "qlever", label: "QLever (recommended)" },
|
|
9637
|
+
{ value: "fuseki", label: "Fuseki" }
|
|
9638
|
+
],
|
|
9639
|
+
(item) => item.label
|
|
9640
|
+
).then((item) => item.value);
|
|
9641
|
+
const tier = await pickOne(
|
|
9642
|
+
rl,
|
|
9643
|
+
"Select processing tier (default: L \u2014 Large):",
|
|
9644
|
+
[
|
|
9645
|
+
{ value: "l", label: "L \u2014 Large (default)" },
|
|
9646
|
+
{ value: "m", label: "M \u2014 Medium" },
|
|
9647
|
+
{ value: "s", label: "S \u2014 Small" }
|
|
9648
|
+
],
|
|
9649
|
+
(item) => item.label
|
|
9650
|
+
).then((item) => item.value);
|
|
9651
|
+
let selectedAdmins = [];
|
|
9652
|
+
let selectedSyncers = [];
|
|
9653
|
+
let selectedMembers = [];
|
|
9654
|
+
if (isSuperAdmin) {
|
|
9655
|
+
const orgAdmins = orgMembers.filter((m) => m.isAdmin);
|
|
9656
|
+
if (orgAdmins.length === 0) {
|
|
9657
|
+
console.error("This organisation has no admins. Cannot create a project without at least one admin.");
|
|
9658
|
+
process.exit(1);
|
|
9659
|
+
}
|
|
9660
|
+
while (selectedAdmins.length === 0) {
|
|
9661
|
+
selectedAdmins = await pickMultipleOrAll(
|
|
9662
|
+
rl,
|
|
9663
|
+
"Select project admin(s) \u2014 at least one required:",
|
|
9664
|
+
orgAdmins,
|
|
9665
|
+
(m) => `${m.name} <${m.email}>`
|
|
9666
|
+
);
|
|
9667
|
+
if (selectedAdmins.length === 0)
|
|
9668
|
+
console.log(" At least one admin must be selected.");
|
|
9669
|
+
}
|
|
9670
|
+
}
|
|
9671
|
+
const nonAdminMembers = orgMembers.filter((m) => !selectedAdmins.some((a5) => a5.uid === m.uid));
|
|
9672
|
+
if (nonAdminMembers.length > 0) {
|
|
9673
|
+
selectedMembers = await pickMultipleOrAll(
|
|
9674
|
+
rl,
|
|
9675
|
+
"Select project members:",
|
|
9676
|
+
nonAdminMembers,
|
|
9677
|
+
(m) => `${m.name} <${m.email}>${m.isAdmin ? " (org admin)" : ""}`
|
|
9678
|
+
);
|
|
9679
|
+
}
|
|
9680
|
+
if (selectedMembers.length > 0) {
|
|
9681
|
+
const answer = await ask(rl, `
|
|
9682
|
+
Set all selected members as syncers as well? (Y/n): `);
|
|
9683
|
+
if (answer.toLowerCase() !== "n") {
|
|
9684
|
+
selectedSyncers = selectedMembers;
|
|
9685
|
+
} else {
|
|
9686
|
+
selectedSyncers = await pickMultipleOrAll(
|
|
9687
|
+
rl,
|
|
9688
|
+
"Select project syncers:",
|
|
9689
|
+
selectedMembers,
|
|
9690
|
+
(m) => `${m.name} <${m.email}>`
|
|
9691
|
+
);
|
|
9692
|
+
}
|
|
9693
|
+
}
|
|
9694
|
+
console.log("\n\u2500\u2500 Summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
9695
|
+
console.log(` Organisation : ${orgName}`);
|
|
9696
|
+
console.log(` Name : ${projectName}`);
|
|
9697
|
+
console.log(` Graph : ${graphType}`);
|
|
9698
|
+
console.log(` Tier : ${tier.toUpperCase()}`);
|
|
9699
|
+
if (isSuperAdmin) {
|
|
9700
|
+
console.log(` Admins : ${selectedAdmins.map((m) => m.email).join(", ")}`);
|
|
9701
|
+
} else {
|
|
9702
|
+
console.log(` Admins : (you)`);
|
|
9703
|
+
}
|
|
9704
|
+
console.log(` Members : ${selectedMembers.length === 0 ? "(none)" : selectedMembers.map((m) => m.email).join(", ")}`);
|
|
9705
|
+
console.log(` Syncers : ${selectedSyncers.length === 0 ? "(none)" : selectedSyncers.map((m) => m.email).join(", ")}`);
|
|
9706
|
+
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
9707
|
+
const confirm = await ask(rl, "\nCreate project? (Y/n): ");
|
|
9708
|
+
if (confirm.toLowerCase() === "n") {
|
|
9709
|
+
console.log("Aborted.");
|
|
9710
|
+
process.exit(0);
|
|
9711
|
+
}
|
|
9712
|
+
if (verbose)
|
|
9713
|
+
console.info("Creating project \u23F3");
|
|
9714
|
+
const body = {
|
|
9715
|
+
organizationID: orgId,
|
|
9716
|
+
name: projectName,
|
|
9717
|
+
graphType,
|
|
9718
|
+
tier,
|
|
9719
|
+
...selectedAdmins.length > 0 ? { admins: selectedAdmins.map((m) => m.uid) } : {},
|
|
9720
|
+
...selectedMembers.length > 0 ? { members: selectedMembers.map((m) => m.uid) } : {},
|
|
9721
|
+
...selectedSyncers.length > 0 ? { syncers: selectedSyncers.map((m) => m.uid) } : {}
|
|
9722
|
+
};
|
|
9723
|
+
let created;
|
|
9724
|
+
if (isSuperAdmin) {
|
|
9725
|
+
const res = await cue.auth.authenticatedFetch(`${gatewayUrl}/commands/admin/project`, {
|
|
9726
|
+
method: "POST",
|
|
9727
|
+
headers: { "Content-Type": "application/json" },
|
|
9728
|
+
body: JSON.stringify(body)
|
|
9729
|
+
});
|
|
9730
|
+
if (!res.ok) {
|
|
9731
|
+
const detail = await res.text().catch(() => "");
|
|
9732
|
+
console.error(`Failed to create project: ${res.status} ${res.statusText}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
9733
|
+
process.exit(1);
|
|
9734
|
+
}
|
|
9735
|
+
created = await res.json();
|
|
9736
|
+
} else {
|
|
9737
|
+
created = await cue.projects.createProject({
|
|
9738
|
+
organizationID: orgId,
|
|
9739
|
+
name: projectName,
|
|
9740
|
+
graphType,
|
|
9741
|
+
tier,
|
|
9742
|
+
...selectedAdmins.length > 0 ? { admins: selectedAdmins.map((m) => m.uid) } : {},
|
|
9743
|
+
...selectedMembers.length > 0 ? { members: selectedMembers.map((m) => m.uid) } : {},
|
|
9744
|
+
...selectedSyncers.length > 0 ? { syncers: selectedSyncers.map((m) => m.uid) } : {}
|
|
9745
|
+
});
|
|
9746
|
+
}
|
|
9747
|
+
console.log(`
|
|
9748
|
+
Project created \u2705`);
|
|
9749
|
+
console.log(` ID : ${created["id"]}`);
|
|
9750
|
+
console.log(` Name : ${created["name"]}`);
|
|
9751
|
+
} finally {
|
|
9752
|
+
rl.close();
|
|
9753
|
+
}
|
|
9754
|
+
}
|
|
9755
|
+
|
|
9514
9756
|
// apps/desktop/cue-cli/src/main.ts
|
|
9515
9757
|
var packageJson;
|
|
9516
9758
|
try {
|
|
@@ -9532,4 +9774,5 @@ program.command("dump-processed").description("Dump processed files to local fol
|
|
|
9532
9774
|
program.command("repair-ttl").description("Repair TTL files in the specified space").requiredOption("-s, --space <id>", "Specify the space ID (required)").requiredOption("-p, --processor <id>", "Id of the processor to repair TTL files (required) [eg. writers-blob, processors-cad-files]").requiredOption("-f, --from <subString>", "Substring (Regex) to replace in the TTL file (required)").requiredOption("-t, --to <substituteString>", "Substring to replace in the TTL file (required)").option("-k, --key <api-key>", "Specify the API key (or set CUE_API_KEY env variable)").option("-v, --verbose", "Enable verbose output", false).option("-e, --emulators", "Uses emulators for sync", false).action(repairTtlHandler);
|
|
9533
9775
|
program.command("util-rdf-compare").description("Compare two Turtle (.ttl) files and report semantic differences").requiredOption("--file1 <path>", "Path to the first TTL file").requiredOption("--file2 <path>", "Path to the second TTL file").option("-v, --verbose", "Enable verbose output", false).action(utilRdfCompareHandler);
|
|
9534
9776
|
program.command("util-remove-rdf-star").description("Remove RDF-star (quoted) triples from an NQuads file. Supports .nq and .nq.gz input/output.").requiredOption("-i, --input <path>", "Input file path (.nq or .nq.gz)").requiredOption("-o, --output <path>", "Output file path (.nq or .nq.gz)").option("-v, --verbose", "Enable verbose output", false).action(utilRemoveRdfStarHandler);
|
|
9777
|
+
program.command("create-project").description("Interactively create a new project under an organisation").option("-k, --key <api-key>", "Specify the API key (or set CUE_API_KEY env variable)").option("-e, --emulators", "Uses emulators", false).option("-v, --verbose", "Enable verbose output", false).action(createProjectHandler);
|
|
9535
9778
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qaecy/cue-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.40",
|
|
4
4
|
"description": "Cue CLI for QAECY platform",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@google-cloud/pubsub": "4.4.1",
|
|
18
18
|
"axios": "1.14.0",
|
|
19
|
-
"commander": "
|
|
19
|
+
"commander": "14.0.2",
|
|
20
20
|
"firebase": "12.4.0",
|
|
21
21
|
"firebase-admin": "13.0.2",
|
|
22
22
|
"jsonld": "8.3.3",
|