camstack 1.2.180 → 1.2.181
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/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
FFMPEG_PATH_ENV,
|
|
4
4
|
runDiscover
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-4MQR56VQ.js";
|
|
6
6
|
import "./chunk-LMMQX4CK.js";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
@@ -39,7 +39,7 @@ async function runServe(args) {
|
|
|
39
39
|
...typeof values.data === "string" ? { data: values.data } : {}
|
|
40
40
|
};
|
|
41
41
|
Object.assign(process.env, buildServeEnv(opts));
|
|
42
|
-
await import("./launcher-
|
|
42
|
+
await import("./launcher-TUOJ3PCS.js");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// src/commands/agent.ts
|
|
@@ -84,7 +84,7 @@ async function runAgent(args) {
|
|
|
84
84
|
...typeof values.port === "string" ? { port: values.port } : {}
|
|
85
85
|
};
|
|
86
86
|
Object.assign(process.env, buildAgentEnv(opts));
|
|
87
|
-
await import("./launcher-
|
|
87
|
+
await import("./launcher-TUOJ3PCS.js");
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// src/commands/setup.ts
|
|
@@ -136,7 +136,7 @@ function runSetup(args) {
|
|
|
136
136
|
// src/commands/deploy.ts
|
|
137
137
|
import { execSync } from "child_process";
|
|
138
138
|
import { randomBytes } from "crypto";
|
|
139
|
-
import * as
|
|
139
|
+
import * as fs3 from "fs";
|
|
140
140
|
import * as path2 from "path";
|
|
141
141
|
|
|
142
142
|
// src/http/hub-http.ts
|
|
@@ -187,6 +187,95 @@ function hubRequest(url, opts = {}) {
|
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
// src/commands/credentials.ts
|
|
191
|
+
import * as fs2 from "fs";
|
|
192
|
+
var MissingCredentialsError = class extends Error {
|
|
193
|
+
constructor(server) {
|
|
194
|
+
super(
|
|
195
|
+
[
|
|
196
|
+
`Not logged in to ${server ?? "any hub"}.`,
|
|
197
|
+
" Run `camstack login`: it caches a token in ~/.camstack/<host>.json that every",
|
|
198
|
+
" command reuses automatically. For scripts/CI, pass --token-file <path> with a",
|
|
199
|
+
" token issued on Identity \u2192 Tokens (or a copied ~/.camstack session file)."
|
|
200
|
+
].join("\n")
|
|
201
|
+
);
|
|
202
|
+
this.name = "MissingCredentialsError";
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
var GROUP_OR_OTHER_BITS = 63;
|
|
206
|
+
function readTokenFile(filePath) {
|
|
207
|
+
let raw;
|
|
208
|
+
let mode;
|
|
209
|
+
try {
|
|
210
|
+
raw = fs2.readFileSync(filePath, "utf8");
|
|
211
|
+
mode = fs2.statSync(filePath).mode;
|
|
212
|
+
} catch (err) {
|
|
213
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
214
|
+
throw new Error(`Cannot read token file ${filePath}: ${reason}`, { cause: err });
|
|
215
|
+
}
|
|
216
|
+
const warning = process.platform !== "win32" && (mode & GROUP_OR_OTHER_BITS) !== 0 ? `Token file ${filePath} is readable by other users \u2014 run \`chmod 600 ${filePath}\`.` : void 0;
|
|
217
|
+
const parsed = parseTokenFile(raw.trim(), filePath);
|
|
218
|
+
return warning ? { ...parsed, warning } : parsed;
|
|
219
|
+
}
|
|
220
|
+
function parseTokenFile(content, filePath) {
|
|
221
|
+
if (content.length === 0) throw new Error(`Token file ${filePath} is empty.`);
|
|
222
|
+
if (content.startsWith("{")) return parseSessionJson(content, filePath);
|
|
223
|
+
if (/\s/.test(content)) {
|
|
224
|
+
throw new Error(`Token file ${filePath} must hold exactly one token (found several lines).`);
|
|
225
|
+
}
|
|
226
|
+
return { token: content };
|
|
227
|
+
}
|
|
228
|
+
function parseSessionJson(content, filePath) {
|
|
229
|
+
let json;
|
|
230
|
+
try {
|
|
231
|
+
json = JSON.parse(content);
|
|
232
|
+
} catch {
|
|
233
|
+
throw new Error(`Token file ${filePath} looks like JSON but does not parse.`);
|
|
234
|
+
}
|
|
235
|
+
if (json === null || typeof json !== "object") {
|
|
236
|
+
throw new Error(`Token file ${filePath}: expected a JSON object with a "token" field.`);
|
|
237
|
+
}
|
|
238
|
+
const token = Reflect.get(json, "token");
|
|
239
|
+
const server = Reflect.get(json, "server");
|
|
240
|
+
if (typeof token !== "string" || token.length === 0) {
|
|
241
|
+
throw new Error(`Token file ${filePath}: the JSON has no string "token" field.`);
|
|
242
|
+
}
|
|
243
|
+
return typeof server === "string" && server.length > 0 ? { token, server } : { token };
|
|
244
|
+
}
|
|
245
|
+
function resolveCredentials(inputs) {
|
|
246
|
+
const env = inputs.env ?? process.env;
|
|
247
|
+
const file = inputs.tokenFile ? readTokenFile(inputs.tokenFile) : null;
|
|
248
|
+
const targeted = inputs.server ?? env["CAMSTACK_SERVER"] ?? file?.server;
|
|
249
|
+
const session = inputs.loadSession(targeted);
|
|
250
|
+
const server = targeted ?? session?.server;
|
|
251
|
+
const picked = pickToken(inputs.token, file, env["CAMSTACK_TOKEN"], session);
|
|
252
|
+
if (!picked) throw new MissingCredentialsError(server);
|
|
253
|
+
const warning = file?.warning;
|
|
254
|
+
return warning ? { server, ...picked, warning } : { server, ...picked };
|
|
255
|
+
}
|
|
256
|
+
function pickToken(flag, file, envToken, session) {
|
|
257
|
+
if (flag) return { token: flag, source: "flag" };
|
|
258
|
+
if (file) return { token: file.token, source: "token-file" };
|
|
259
|
+
if (envToken) return { token: envToken, source: "env" };
|
|
260
|
+
if (session) return { token: session.token, source: "session" };
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
var REJECTION_ADVICE = {
|
|
264
|
+
session: "The hub rejected the cached session token (revoked or expired). Run `camstack login` again.",
|
|
265
|
+
"token-file": "The hub rejected the token from the token file (revoked, expired or lacking scope) \u2014 ask the operator who issued it for a new one.",
|
|
266
|
+
env: "The hub rejected $CAMSTACK_TOKEN (revoked, expired or lacking scope).",
|
|
267
|
+
flag: "The hub rejected the --token value (revoked, expired or lacking scope)."
|
|
268
|
+
};
|
|
269
|
+
function authRejectedHint(status, source) {
|
|
270
|
+
if (status !== 401 && status !== 403) return null;
|
|
271
|
+
return REJECTION_ADVICE[source];
|
|
272
|
+
}
|
|
273
|
+
function withAuthHint(message, status, source) {
|
|
274
|
+
const hint = source ? authRejectedHint(status, source) : null;
|
|
275
|
+
return hint ? `${message}
|
|
276
|
+
${hint}` : message;
|
|
277
|
+
}
|
|
278
|
+
|
|
190
279
|
// src/commands/deploy.ts
|
|
191
280
|
function isRecord(value) {
|
|
192
281
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -283,12 +372,12 @@ function toPackFilenames(raw) {
|
|
|
283
372
|
}
|
|
284
373
|
function resolveAddonPath(arg) {
|
|
285
374
|
const absolute = path2.resolve(arg);
|
|
286
|
-
if (
|
|
375
|
+
if (fs3.existsSync(absolute)) return absolute;
|
|
287
376
|
for (const candidate of [
|
|
288
377
|
path2.resolve("packages", `addon-${arg}`),
|
|
289
378
|
path2.resolve("packages", arg)
|
|
290
379
|
]) {
|
|
291
|
-
if (
|
|
380
|
+
if (fs3.existsSync(candidate) && fs3.existsSync(path2.join(candidate, "package.json"))) {
|
|
292
381
|
return candidate;
|
|
293
382
|
}
|
|
294
383
|
}
|
|
@@ -305,7 +394,7 @@ async function resolveAddonPathInteractive(arg) {
|
|
|
305
394
|
return resolved;
|
|
306
395
|
}
|
|
307
396
|
const cwdAbs = path2.resolve(".");
|
|
308
|
-
if (
|
|
397
|
+
if (fs3.existsSync(path2.join(cwdAbs, "package.json"))) {
|
|
309
398
|
const { discoverAddonsInCwd: discoverAddonsInCwd2 } = await import("./discover-addons-3N32LTH7.js");
|
|
310
399
|
const direct = discoverAddonsInCwd2(cwdAbs, 0);
|
|
311
400
|
if (direct.length > 0 && direct[0].path === cwdAbs) {
|
|
@@ -343,9 +432,9 @@ async function resolveAddonPathInteractive(arg) {
|
|
|
343
432
|
}
|
|
344
433
|
function readBuildScript(addonDir, scriptName) {
|
|
345
434
|
const pkgJsonPath = path2.join(addonDir, "package.json");
|
|
346
|
-
if (!
|
|
435
|
+
if (!fs3.existsSync(pkgJsonPath)) return null;
|
|
347
436
|
try {
|
|
348
|
-
const parsed = JSON.parse(
|
|
437
|
+
const parsed = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf8"));
|
|
349
438
|
if (!parsed || typeof parsed !== "object") return null;
|
|
350
439
|
const scripts = parsed.scripts;
|
|
351
440
|
if (!scripts || typeof scripts !== "object") return null;
|
|
@@ -370,7 +459,7 @@ function buildAddon(addonDir, scriptName) {
|
|
|
370
459
|
}
|
|
371
460
|
function packAddon(addonDir) {
|
|
372
461
|
const pkgJsonPath = path2.join(addonDir, "package.json");
|
|
373
|
-
if (!
|
|
462
|
+
if (!fs3.existsSync(pkgJsonPath)) {
|
|
374
463
|
throw new Error(`No package.json found in: ${addonDir}`);
|
|
375
464
|
}
|
|
376
465
|
console.log(`[camstack] Packing addon from ${addonDir}...`);
|
|
@@ -389,7 +478,7 @@ function packAddon(addonDir) {
|
|
|
389
478
|
}
|
|
390
479
|
if (!tgzFilename) throw new Error("npm pack did not produce a .tgz file");
|
|
391
480
|
const tgzPath = path2.join(addonDir, tgzFilename);
|
|
392
|
-
if (!
|
|
481
|
+
if (!fs3.existsSync(tgzPath)) {
|
|
393
482
|
throw new Error(`Expected tgz file not found: ${tgzPath}`);
|
|
394
483
|
}
|
|
395
484
|
console.log(`[camstack] Packed: ${tgzFilename}`);
|
|
@@ -397,7 +486,7 @@ function packAddon(addonDir) {
|
|
|
397
486
|
tgzPath,
|
|
398
487
|
cleanup: () => {
|
|
399
488
|
try {
|
|
400
|
-
if (
|
|
489
|
+
if (fs3.existsSync(tgzPath)) fs3.unlinkSync(tgzPath);
|
|
401
490
|
} catch {
|
|
402
491
|
}
|
|
403
492
|
}
|
|
@@ -427,7 +516,7 @@ async function fetchOnlineAgents(serverUrl, token) {
|
|
|
427
516
|
}
|
|
428
517
|
async function uploadToTarget(args) {
|
|
429
518
|
const { serverUrl, token, tgzPath, nodeId, addonId } = args;
|
|
430
|
-
const fileBuffer =
|
|
519
|
+
const fileBuffer = fs3.readFileSync(tgzPath);
|
|
431
520
|
const boundary = `----camstackcli${randomBytes(16).toString("hex")}`;
|
|
432
521
|
const CRLF = "\r\n";
|
|
433
522
|
const parts = [];
|
|
@@ -464,17 +553,21 @@ async function uploadToTarget(args) {
|
|
|
464
553
|
if (!response.ok) {
|
|
465
554
|
return {
|
|
466
555
|
success: false,
|
|
467
|
-
error:
|
|
556
|
+
error: withAuthHint(
|
|
557
|
+
result.error ?? `Server returned ${response.status} ${response.statusText}`,
|
|
558
|
+
response.status,
|
|
559
|
+
args.authSource
|
|
560
|
+
)
|
|
468
561
|
};
|
|
469
562
|
}
|
|
470
563
|
return result;
|
|
471
564
|
}
|
|
472
565
|
async function deployAddon(addonPath, opts) {
|
|
473
|
-
const resolvedPath = path2.isAbsolute(addonPath) &&
|
|
566
|
+
const resolvedPath = path2.isAbsolute(addonPath) && fs3.existsSync(addonPath) ? addonPath : await resolveAddonPathInteractive(addonPath);
|
|
474
567
|
let tgzPath;
|
|
475
568
|
let cleanup = null;
|
|
476
569
|
if (resolvedPath.endsWith(".tgz") || resolvedPath.endsWith(".tar.gz")) {
|
|
477
|
-
if (!
|
|
570
|
+
if (!fs3.existsSync(resolvedPath)) throw new Error(`File not found: ${resolvedPath}`);
|
|
478
571
|
tgzPath = resolvedPath;
|
|
479
572
|
} else {
|
|
480
573
|
const buildMode = opts.buildMode ?? "auto";
|
|
@@ -531,7 +624,8 @@ async function deployAddon(addonPath, opts) {
|
|
|
531
624
|
serverUrl: opts.serverUrl,
|
|
532
625
|
token: opts.token,
|
|
533
626
|
tgzPath,
|
|
534
|
-
...t.nodeId ? { nodeId: t.nodeId } : {}
|
|
627
|
+
...t.nodeId ? { nodeId: t.nodeId } : {},
|
|
628
|
+
...opts.authSource ? { authSource: opts.authSource } : {}
|
|
535
629
|
}),
|
|
536
630
|
{
|
|
537
631
|
attempts: 5,
|
|
@@ -591,12 +685,12 @@ async function deployAddon(addonPath, opts) {
|
|
|
591
685
|
// src/commands/deploy-server.ts
|
|
592
686
|
import { execSync as execSync2 } from "child_process";
|
|
593
687
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
594
|
-
import * as
|
|
688
|
+
import * as fs5 from "fs";
|
|
595
689
|
import * as os2 from "os";
|
|
596
690
|
import * as path4 from "path";
|
|
597
691
|
|
|
598
692
|
// src/commands/server-closure.ts
|
|
599
|
-
import * as
|
|
693
|
+
import * as fs4 from "fs";
|
|
600
694
|
import * as path3 from "path";
|
|
601
695
|
var CAMSTACK_SCOPE_PREFIX = "@camstack/";
|
|
602
696
|
function computeDevVersion(base, epochSeconds) {
|
|
@@ -605,7 +699,7 @@ function computeDevVersion(base, epochSeconds) {
|
|
|
605
699
|
function readPackageManifest(dir) {
|
|
606
700
|
const pkgJsonPath = path3.join(dir, "package.json");
|
|
607
701
|
try {
|
|
608
|
-
const parsed = JSON.parse(
|
|
702
|
+
const parsed = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
|
|
609
703
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
610
704
|
const raw = parsed;
|
|
611
705
|
if (typeof raw["name"] !== "string") return null;
|
|
@@ -631,7 +725,7 @@ function loadWorkspacePackages(workspaceRoot) {
|
|
|
631
725
|
const base = path3.join(workspaceRoot, pattern.slice(0, -2));
|
|
632
726
|
let entries;
|
|
633
727
|
try {
|
|
634
|
-
entries =
|
|
728
|
+
entries = fs4.readdirSync(base, { withFileTypes: true });
|
|
635
729
|
} catch {
|
|
636
730
|
continue;
|
|
637
731
|
}
|
|
@@ -705,7 +799,7 @@ function discoverServerClosure(workspaceRoot) {
|
|
|
705
799
|
}
|
|
706
800
|
function withDevVersionPackageJson(pkgDir, devVersion, intraSetNames, fn) {
|
|
707
801
|
const pkgJsonPath = path3.join(pkgDir, "package.json");
|
|
708
|
-
const originalBytes =
|
|
802
|
+
const originalBytes = fs4.readFileSync(pkgJsonPath);
|
|
709
803
|
const parsed = JSON.parse(originalBytes.toString("utf-8"));
|
|
710
804
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
711
805
|
throw new Error(`Malformed package.json: ${pkgJsonPath}`);
|
|
@@ -723,12 +817,12 @@ function withDevVersionPackageJson(pkgDir, devVersion, intraSetNames, fn) {
|
|
|
723
817
|
}
|
|
724
818
|
manifest[field] = rewritten;
|
|
725
819
|
}
|
|
726
|
-
|
|
820
|
+
fs4.writeFileSync(pkgJsonPath, `${JSON.stringify(manifest, null, 2)}
|
|
727
821
|
`, "utf-8");
|
|
728
822
|
try {
|
|
729
823
|
return fn();
|
|
730
824
|
} finally {
|
|
731
|
-
|
|
825
|
+
fs4.writeFileSync(pkgJsonPath, originalBytes);
|
|
732
826
|
}
|
|
733
827
|
}
|
|
734
828
|
|
|
@@ -751,7 +845,7 @@ function hasBuildScript(pkgDir) {
|
|
|
751
845
|
}
|
|
752
846
|
function readJson(filePath) {
|
|
753
847
|
try {
|
|
754
|
-
return JSON.parse(
|
|
848
|
+
return JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
755
849
|
} catch {
|
|
756
850
|
return null;
|
|
757
851
|
}
|
|
@@ -799,7 +893,7 @@ function packPackage(pkg, devVersion, intraSetNames, outDir) {
|
|
|
799
893
|
throw new Error(`npm pack produced no tarball for ${pkg.name}`);
|
|
800
894
|
}
|
|
801
895
|
const tgzPath = path4.join(outDir, path4.basename(filename));
|
|
802
|
-
if (!
|
|
896
|
+
if (!fs5.existsSync(tgzPath)) {
|
|
803
897
|
throw new Error(`Expected tarball not found after pack: ${tgzPath}`);
|
|
804
898
|
}
|
|
805
899
|
return { name: pkg.name, tgzPath };
|
|
@@ -817,7 +911,7 @@ async function uploadClosure(args) {
|
|
|
817
911
|
Buffer.from(
|
|
818
912
|
`--${boundary}${CRLF}Content-Disposition: form-data; name="file"; filename="${path4.basename(tarball.tgzPath)}"${CRLF}Content-Type: application/gzip${CRLF}${CRLF}`
|
|
819
913
|
),
|
|
820
|
-
|
|
914
|
+
fs5.readFileSync(tarball.tgzPath),
|
|
821
915
|
Buffer.from(CRLF)
|
|
822
916
|
);
|
|
823
917
|
}
|
|
@@ -836,7 +930,9 @@ async function uploadClosure(args) {
|
|
|
836
930
|
const payload = await response.json().catch(() => ({}));
|
|
837
931
|
if (!response.ok || !isRecord2(payload) || payload["success"] !== true) {
|
|
838
932
|
const detail = isRecord2(payload) && typeof payload["error"] === "string" ? payload["error"] : `${response.status} ${response.statusText}`;
|
|
839
|
-
throw new Error(
|
|
933
|
+
throw new Error(
|
|
934
|
+
withAuthHint(`Server upload rejected: ${detail}`, response.status, args.authSource)
|
|
935
|
+
);
|
|
840
936
|
}
|
|
841
937
|
}
|
|
842
938
|
function toApplyResult(value) {
|
|
@@ -872,7 +968,13 @@ async function applyServerUpdate(args) {
|
|
|
872
968
|
);
|
|
873
969
|
const body = await res.json().catch(() => null);
|
|
874
970
|
if (!res.ok) {
|
|
875
|
-
throw new Error(
|
|
971
|
+
throw new Error(
|
|
972
|
+
withAuthHint(
|
|
973
|
+
`applyServerUpdate returned ${res.status} ${res.statusText}`,
|
|
974
|
+
res.status,
|
|
975
|
+
args.authSource
|
|
976
|
+
)
|
|
977
|
+
);
|
|
876
978
|
}
|
|
877
979
|
const result = toApplyResult(unwrapTrpcJson(body));
|
|
878
980
|
if (result === null) {
|
|
@@ -950,7 +1052,7 @@ async function deployServer(opts) {
|
|
|
950
1052
|
console.log(`[camstack] Building ${closure.buildSet.length} packages (dependency order)...`);
|
|
951
1053
|
for (const pkg of closure.buildSet) buildPackage(pkg);
|
|
952
1054
|
const intraSetNames = new Set(closure.packSet.map((p) => p.name));
|
|
953
|
-
const outDir =
|
|
1055
|
+
const outDir = fs5.mkdtempSync(path4.join(os2.tmpdir(), "camstack-deploy-server-"));
|
|
954
1056
|
try {
|
|
955
1057
|
console.log(`[camstack] Packing ${closure.packSet.length} packages at ${devVersion}...`);
|
|
956
1058
|
const tarballs = [];
|
|
@@ -964,14 +1066,16 @@ async function deployServer(opts) {
|
|
|
964
1066
|
serverUrl: opts.serverUrl,
|
|
965
1067
|
token: opts.token,
|
|
966
1068
|
version: devVersion,
|
|
967
|
-
tarballs
|
|
1069
|
+
tarballs,
|
|
1070
|
+
...opts.authSource ? { authSource: opts.authSource } : {}
|
|
968
1071
|
});
|
|
969
1072
|
console.log("[camstack] \u2713 Upload accepted");
|
|
970
1073
|
console.log(`[camstack] Applying server update to ${devVersion}...`);
|
|
971
1074
|
const apply = await applyServerUpdate({
|
|
972
1075
|
serverUrl: opts.serverUrl,
|
|
973
1076
|
token: opts.token,
|
|
974
|
-
version: devVersion
|
|
1077
|
+
version: devVersion,
|
|
1078
|
+
...opts.authSource ? { authSource: opts.authSource } : {}
|
|
975
1079
|
});
|
|
976
1080
|
if (!apply.accepted) {
|
|
977
1081
|
console.error(`[camstack] \u2717 applyServerUpdate refused: ${apply.message}`);
|
|
@@ -986,12 +1090,12 @@ async function deployServer(opts) {
|
|
|
986
1090
|
await pollUntilPromoted({ serverUrl: opts.serverUrl, token: opts.token, version: devVersion });
|
|
987
1091
|
console.log(`[camstack] \u2713 ${devVersion} promoted \u2014 the hub is running the dev closure`);
|
|
988
1092
|
} finally {
|
|
989
|
-
|
|
1093
|
+
fs5.rmSync(outDir, { recursive: true, force: true });
|
|
990
1094
|
}
|
|
991
1095
|
}
|
|
992
1096
|
|
|
993
1097
|
// src/commands/auth.ts
|
|
994
|
-
import * as
|
|
1098
|
+
import * as fs6 from "fs";
|
|
995
1099
|
import * as path5 from "path";
|
|
996
1100
|
import * as os3 from "os";
|
|
997
1101
|
import * as clack from "@clack/prompts";
|
|
@@ -1003,12 +1107,12 @@ function sessionFileForServer(serverUrl) {
|
|
|
1003
1107
|
function resolveSessionFile(serverUrl) {
|
|
1004
1108
|
if (serverUrl) {
|
|
1005
1109
|
const p = sessionFileForServer(serverUrl);
|
|
1006
|
-
return
|
|
1110
|
+
return fs6.existsSync(p) ? p : null;
|
|
1007
1111
|
}
|
|
1008
|
-
if (!
|
|
1009
|
-
const files =
|
|
1112
|
+
if (!fs6.existsSync(SESSION_DIR)) return null;
|
|
1113
|
+
const files = fs6.readdirSync(SESSION_DIR).filter((f) => f.endsWith(".json")).map((f) => path5.join(SESSION_DIR, f));
|
|
1010
1114
|
if (files.length === 0) return null;
|
|
1011
|
-
return files.map((f) => ({ f, mtime:
|
|
1115
|
+
return files.map((f) => ({ f, mtime: fs6.statSync(f).mtimeMs })).toSorted((a, b) => b.mtime - a.mtime)[0].f;
|
|
1012
1116
|
}
|
|
1013
1117
|
function isSessionFile(value) {
|
|
1014
1118
|
if (value === null || typeof value !== "object") return false;
|
|
@@ -1025,24 +1129,24 @@ function loadSession(serverUrl) {
|
|
|
1025
1129
|
const file = resolveSessionFile(serverUrl);
|
|
1026
1130
|
if (!file) return null;
|
|
1027
1131
|
try {
|
|
1028
|
-
const parsed = JSON.parse(
|
|
1132
|
+
const parsed = JSON.parse(fs6.readFileSync(file, "utf8"));
|
|
1029
1133
|
return isSessionFile(parsed) ? parsed : null;
|
|
1030
1134
|
} catch {
|
|
1031
1135
|
return null;
|
|
1032
1136
|
}
|
|
1033
1137
|
}
|
|
1034
1138
|
function saveSession(session) {
|
|
1035
|
-
if (!
|
|
1036
|
-
|
|
1139
|
+
if (!fs6.existsSync(SESSION_DIR)) {
|
|
1140
|
+
fs6.mkdirSync(SESSION_DIR, { recursive: true, mode: 448 });
|
|
1037
1141
|
}
|
|
1038
1142
|
const file = sessionFileForServer(session.server);
|
|
1039
|
-
|
|
1143
|
+
fs6.writeFileSync(file, JSON.stringify(session, null, 2), { mode: 384 });
|
|
1040
1144
|
return file;
|
|
1041
1145
|
}
|
|
1042
1146
|
function clearSession(serverUrl) {
|
|
1043
1147
|
const file = sessionFileForServer(serverUrl);
|
|
1044
|
-
if (
|
|
1045
|
-
|
|
1148
|
+
if (fs6.existsSync(file)) {
|
|
1149
|
+
fs6.unlinkSync(file);
|
|
1046
1150
|
return true;
|
|
1047
1151
|
}
|
|
1048
1152
|
return false;
|
|
@@ -1132,7 +1236,7 @@ function isUnknown(_value) {
|
|
|
1132
1236
|
return true;
|
|
1133
1237
|
}
|
|
1134
1238
|
async function resolveServerInteractive(presetNamespace) {
|
|
1135
|
-
const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-
|
|
1239
|
+
const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-LW74552N.js");
|
|
1136
1240
|
if (presetNamespace) {
|
|
1137
1241
|
const spinner4 = clack.spinner();
|
|
1138
1242
|
spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
|
|
@@ -1381,7 +1485,7 @@ import { spawn } from "child_process";
|
|
|
1381
1485
|
import * as clack2 from "@clack/prompts";
|
|
1382
1486
|
|
|
1383
1487
|
// src/update-notifier.ts
|
|
1384
|
-
import * as
|
|
1488
|
+
import * as fs7 from "fs";
|
|
1385
1489
|
import * as path6 from "path";
|
|
1386
1490
|
import * as os4 from "os";
|
|
1387
1491
|
var CACHE_DIR = path6.join(os4.homedir(), ".camstack");
|
|
@@ -1391,8 +1495,8 @@ var REGISTRY_BASE = "https://registry.npmjs.org";
|
|
|
1391
1495
|
var FETCH_TIMEOUT_MS = 2500;
|
|
1392
1496
|
function readCache() {
|
|
1393
1497
|
try {
|
|
1394
|
-
if (!
|
|
1395
|
-
const parsed = JSON.parse(
|
|
1498
|
+
if (!fs7.existsSync(CACHE_FILE)) return null;
|
|
1499
|
+
const parsed = JSON.parse(fs7.readFileSync(CACHE_FILE, "utf8"));
|
|
1396
1500
|
if (!parsed || typeof parsed !== "object") return null;
|
|
1397
1501
|
const c = parsed;
|
|
1398
1502
|
if (typeof c.lastCheckAt !== "number") return null;
|
|
@@ -1407,8 +1511,8 @@ function readCache() {
|
|
|
1407
1511
|
}
|
|
1408
1512
|
function writeCache(c) {
|
|
1409
1513
|
try {
|
|
1410
|
-
if (!
|
|
1411
|
-
|
|
1514
|
+
if (!fs7.existsSync(CACHE_DIR)) fs7.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
|
|
1515
|
+
fs7.writeFileSync(CACHE_FILE, JSON.stringify(c, null, 2));
|
|
1412
1516
|
} catch {
|
|
1413
1517
|
}
|
|
1414
1518
|
}
|
|
@@ -1567,7 +1671,7 @@ async function runUpdate(args) {
|
|
|
1567
1671
|
}
|
|
1568
1672
|
|
|
1569
1673
|
// src/commands/dev.ts
|
|
1570
|
-
import * as
|
|
1674
|
+
import * as fs8 from "fs";
|
|
1571
1675
|
import * as path7 from "path";
|
|
1572
1676
|
import { parseArgs as parseArgs5 } from "util";
|
|
1573
1677
|
import * as clack3 from "@clack/prompts";
|
|
@@ -1578,14 +1682,14 @@ function resolveAddonDir(arg) {
|
|
|
1578
1682
|
throw new Error("`dev` requires a source directory, not a tarball (nothing to watch).");
|
|
1579
1683
|
}
|
|
1580
1684
|
const absolute = path7.resolve(arg);
|
|
1581
|
-
if (
|
|
1685
|
+
if (fs8.existsSync(absolute) && fs8.statSync(absolute).isDirectory()) {
|
|
1582
1686
|
return absolute;
|
|
1583
1687
|
}
|
|
1584
1688
|
for (const candidate of [
|
|
1585
1689
|
path7.resolve("packages", `addon-${arg}`),
|
|
1586
1690
|
path7.resolve("packages", arg)
|
|
1587
1691
|
]) {
|
|
1588
|
-
if (
|
|
1692
|
+
if (fs8.existsSync(candidate) && fs8.statSync(candidate).isDirectory()) {
|
|
1589
1693
|
return candidate;
|
|
1590
1694
|
}
|
|
1591
1695
|
}
|
|
@@ -1595,10 +1699,10 @@ function resolveAddonDir(arg) {
|
|
|
1595
1699
|
}
|
|
1596
1700
|
function watchRecursive(target, onEvent) {
|
|
1597
1701
|
try {
|
|
1598
|
-
const w =
|
|
1702
|
+
const w = fs8.watch(target, { recursive: true }, onEvent);
|
|
1599
1703
|
return { close: () => w.close(), recursive: true };
|
|
1600
1704
|
} catch {
|
|
1601
|
-
const w =
|
|
1705
|
+
const w = fs8.watch(target, onEvent);
|
|
1602
1706
|
return { close: () => w.close(), recursive: false };
|
|
1603
1707
|
}
|
|
1604
1708
|
}
|
|
@@ -1622,6 +1726,7 @@ async function runDev(args) {
|
|
|
1622
1726
|
options: {
|
|
1623
1727
|
server: { type: "string", short: "s" },
|
|
1624
1728
|
token: { type: "string", short: "t" },
|
|
1729
|
+
"token-file": { type: "string" },
|
|
1625
1730
|
node: { type: "string", short: "n" },
|
|
1626
1731
|
cluster: { type: "boolean", short: "c" },
|
|
1627
1732
|
"watch-path": { type: "string", short: "w" },
|
|
@@ -1635,27 +1740,32 @@ async function runDev(args) {
|
|
|
1635
1740
|
});
|
|
1636
1741
|
const addonArg = positionals[0] ?? ".";
|
|
1637
1742
|
const addonDir = resolveAddonDir(addonArg);
|
|
1638
|
-
const
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1743
|
+
const creds = resolveCredentials({
|
|
1744
|
+
...typeof values.server === "string" ? { server: values.server } : {},
|
|
1745
|
+
...typeof values.token === "string" ? { token: values.token } : {},
|
|
1746
|
+
...typeof values["token-file"] === "string" ? { tokenFile: values["token-file"] } : {},
|
|
1747
|
+
loadSession
|
|
1748
|
+
});
|
|
1749
|
+
if (creds.warning) console.error(`[camstack dev] Warning: ${creds.warning}`);
|
|
1750
|
+
const serverUrl = creds.server;
|
|
1751
|
+
const token = creds.token;
|
|
1752
|
+
if (!serverUrl) {
|
|
1753
|
+
throw new Error("No hub server known. Pass --server, or run `camstack login` first.");
|
|
1645
1754
|
}
|
|
1646
1755
|
const nodeId = typeof values.node === "string" ? values.node : void 0;
|
|
1647
1756
|
const cluster = values.cluster === true;
|
|
1648
1757
|
const deployOpts = {
|
|
1649
1758
|
serverUrl,
|
|
1650
1759
|
token,
|
|
1760
|
+
authSource: creds.source,
|
|
1651
1761
|
...nodeId ? { nodeId } : {},
|
|
1652
1762
|
...cluster ? { cluster: true } : {},
|
|
1653
1763
|
buildMode: values["no-build"] === true ? "skip" : "auto",
|
|
1654
1764
|
...typeof values["build-script"] === "string" ? { buildScript: values["build-script"] } : {}
|
|
1655
1765
|
};
|
|
1656
1766
|
const watchOverride = typeof values["watch-path"] === "string" ? values["watch-path"] : void 0;
|
|
1657
|
-
const watchTarget = watchOverride ? path7.resolve(addonDir, watchOverride) :
|
|
1658
|
-
if (!
|
|
1767
|
+
const watchTarget = watchOverride ? path7.resolve(addonDir, watchOverride) : fs8.existsSync(path7.join(addonDir, DEFAULT_WATCH_SUBDIR)) ? path7.join(addonDir, DEFAULT_WATCH_SUBDIR) : addonDir;
|
|
1768
|
+
if (!fs8.existsSync(watchTarget)) {
|
|
1659
1769
|
throw new Error(`Watch path does not exist: ${watchTarget}`);
|
|
1660
1770
|
}
|
|
1661
1771
|
const debounceMs = typeof values.debounce === "string" ? parseInt(values.debounce, 10) : DEFAULT_DEBOUNCE_MS;
|
|
@@ -1743,13 +1853,15 @@ function printLine(e, addonId) {
|
|
|
1743
1853
|
`
|
|
1744
1854
|
);
|
|
1745
1855
|
}
|
|
1746
|
-
async function fetchLogs(server, token, addonId, limit) {
|
|
1856
|
+
async function fetchLogs(server, token, addonId, limit, authSource) {
|
|
1747
1857
|
const input = encodeURIComponent(JSON.stringify({ json: { addonId, limit } }));
|
|
1748
1858
|
const url = `${server}/trpc/addons.getLogs?input=${input}`;
|
|
1749
1859
|
const res = await hubRequest(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
1750
1860
|
if (!res.ok) {
|
|
1751
1861
|
const text2 = await res.text().catch(() => "");
|
|
1752
|
-
throw new Error(
|
|
1862
|
+
throw new Error(
|
|
1863
|
+
withAuthHint(`getLogs HTTP ${res.status}: ${text2.slice(0, 200)}`, res.status, authSource)
|
|
1864
|
+
);
|
|
1753
1865
|
}
|
|
1754
1866
|
const body = await res.json();
|
|
1755
1867
|
return body.result?.data?.json ?? [];
|
|
@@ -1760,6 +1872,7 @@ async function runWatch(args) {
|
|
|
1760
1872
|
options: {
|
|
1761
1873
|
server: { type: "string", short: "s" },
|
|
1762
1874
|
token: { type: "string", short: "t" },
|
|
1875
|
+
"token-file": { type: "string" },
|
|
1763
1876
|
node: { type: "string", short: "n" },
|
|
1764
1877
|
cluster: { type: "boolean", short: "c" },
|
|
1765
1878
|
"no-build": { type: "boolean" },
|
|
@@ -1771,17 +1884,24 @@ async function runWatch(args) {
|
|
|
1771
1884
|
allowPositionals: true
|
|
1772
1885
|
});
|
|
1773
1886
|
const addonArg = positionals[0] ?? ".";
|
|
1774
|
-
const
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1887
|
+
const creds = resolveCredentials({
|
|
1888
|
+
...typeof values.server === "string" ? { server: values.server } : {},
|
|
1889
|
+
...typeof values.token === "string" ? { token: values.token } : {},
|
|
1890
|
+
...typeof values["token-file"] === "string" ? { tokenFile: values["token-file"] } : {},
|
|
1891
|
+
loadSession
|
|
1892
|
+
});
|
|
1893
|
+
if (creds.warning) console.error(`[camstack watch] Warning: ${creds.warning}`);
|
|
1894
|
+
const serverUrl = creds.server;
|
|
1895
|
+
const token = creds.token;
|
|
1896
|
+
if (!serverUrl) {
|
|
1897
|
+
throw new Error("No hub server known. Pass --server, or run `camstack login` first.");
|
|
1779
1898
|
}
|
|
1780
1899
|
const nodeId = typeof values.node === "string" ? values.node : void 0;
|
|
1781
1900
|
const cluster = values.cluster === true;
|
|
1782
1901
|
const deployOpts = {
|
|
1783
1902
|
serverUrl,
|
|
1784
1903
|
token,
|
|
1904
|
+
authSource: creds.source,
|
|
1785
1905
|
...nodeId ? { nodeId } : {},
|
|
1786
1906
|
...cluster ? { cluster: true } : {},
|
|
1787
1907
|
buildMode: values["no-build"] === true ? "skip" : "auto",
|
|
@@ -1807,7 +1927,7 @@ async function runWatch(args) {
|
|
|
1807
1927
|
process.on("SIGTERM", shutdown);
|
|
1808
1928
|
while (!stop) {
|
|
1809
1929
|
try {
|
|
1810
|
-
const entries = await fetchLogs(serverUrl, token, addonId, LOG_BATCH_LIMIT);
|
|
1930
|
+
const entries = await fetchLogs(serverUrl, token, addonId, LOG_BATCH_LIMIT, creds.source);
|
|
1811
1931
|
const sorted = [...entries].toSorted((a, b) => {
|
|
1812
1932
|
const ta = typeof a.timestamp === "number" ? a.timestamp : new Date(a.timestamp).getTime();
|
|
1813
1933
|
const tb = typeof b.timestamp === "number" ? b.timestamp : new Date(b.timestamp).getTime();
|
|
@@ -2210,6 +2330,10 @@ function printGlobalHelp(commands) {
|
|
|
2210
2330
|
lines.push(" -h, --help Show this help, or per-command help with `camstack <cmd> --help`");
|
|
2211
2331
|
console.log(lines.join("\n"));
|
|
2212
2332
|
}
|
|
2333
|
+
var TOKEN_RESOLUTION_HELP = [
|
|
2334
|
+
"Token resolution (first hit wins): --token, --token-file, $CAMSTACK_TOKEN,",
|
|
2335
|
+
" then the session cached by `camstack login` for the target server."
|
|
2336
|
+
].join("\n");
|
|
2213
2337
|
function buildCommands() {
|
|
2214
2338
|
return [
|
|
2215
2339
|
{
|
|
@@ -2331,10 +2455,13 @@ function buildCommands() {
|
|
|
2331
2455
|
" --no-verify Skip the post-deploy hub /health gate",
|
|
2332
2456
|
"",
|
|
2333
2457
|
"Target options:",
|
|
2334
|
-
" -s, --server <url> Server URL (default:
|
|
2335
|
-
" -t, --token <token> Auth token override
|
|
2458
|
+
" -s, --server <url> Server URL (default: $CAMSTACK_SERVER, then the cached session)",
|
|
2459
|
+
" -t, --token <token> Auth token override",
|
|
2460
|
+
" --token-file <path> Read the token from a file (bare token or a ~/.camstack session file)",
|
|
2336
2461
|
" -n, --node <id> Push to a specific node. Mutually exclusive with --cluster",
|
|
2337
|
-
" -c, --cluster Push to hub + every online agent (requires admin token)"
|
|
2462
|
+
" -c, --cluster Push to hub + every online agent (requires admin token)",
|
|
2463
|
+
"",
|
|
2464
|
+
TOKEN_RESOLUTION_HELP
|
|
2338
2465
|
].join("\n")
|
|
2339
2466
|
},
|
|
2340
2467
|
{
|
|
@@ -2352,9 +2479,12 @@ function buildCommands() {
|
|
|
2352
2479
|
" and waits for the probation boot to promote.",
|
|
2353
2480
|
"",
|
|
2354
2481
|
"Options:",
|
|
2355
|
-
" -s, --server <url> Server URL (default:
|
|
2356
|
-
" -t, --token <token> Auth token override
|
|
2357
|
-
" --
|
|
2482
|
+
" -s, --server <url> Server URL (default: $CAMSTACK_SERVER, then the cached session)",
|
|
2483
|
+
" -t, --token <token> Auth token override",
|
|
2484
|
+
" --token-file <path> Read the token from a file (bare token or a ~/.camstack session file)",
|
|
2485
|
+
" --no-verify Do not wait for promotion after applyServerUpdate is accepted",
|
|
2486
|
+
"",
|
|
2487
|
+
TOKEN_RESOLUTION_HELP
|
|
2358
2488
|
].join("\n")
|
|
2359
2489
|
},
|
|
2360
2490
|
{
|
|
@@ -2370,6 +2500,7 @@ function buildCommands() {
|
|
|
2370
2500
|
"Options:",
|
|
2371
2501
|
" -s, --server <url> Server URL (default: cached session)",
|
|
2372
2502
|
" -t, --token <token> Auth token override",
|
|
2503
|
+
" --token-file <path> Read the token from a file",
|
|
2373
2504
|
" -n, --node <id> Push to a specific node",
|
|
2374
2505
|
" -c, --cluster Push to hub + every online agent",
|
|
2375
2506
|
" --no-build Skip `npm run build`",
|
|
@@ -2378,7 +2509,9 @@ function buildCommands() {
|
|
|
2378
2509
|
" --no-initial-deploy Skip initial deploy \u2014 only tail existing addon",
|
|
2379
2510
|
"",
|
|
2380
2511
|
"Each round polls the last 100 entries; new entries (by timestamp+content)",
|
|
2381
|
-
"are printed. Ctrl-C to stop."
|
|
2512
|
+
"are printed. Ctrl-C to stop.",
|
|
2513
|
+
"",
|
|
2514
|
+
TOKEN_RESOLUTION_HELP
|
|
2382
2515
|
].join("\n")
|
|
2383
2516
|
},
|
|
2384
2517
|
{
|
|
@@ -2403,11 +2536,14 @@ function buildCommands() {
|
|
|
2403
2536
|
"Target options:",
|
|
2404
2537
|
" -s, --server <url> Server URL (default: cached session)",
|
|
2405
2538
|
" -t, --token <token> Auth token override",
|
|
2539
|
+
" --token-file <path> Read the token from a file",
|
|
2406
2540
|
" -n, --node <id> Push to a specific node",
|
|
2407
2541
|
" -c, --cluster Push to hub + every online agent",
|
|
2408
2542
|
"",
|
|
2409
2543
|
"Stop with Ctrl-C. Each cycle is sequential \u2014 concurrent changes during",
|
|
2410
|
-
"a push are coalesced into the next cycle."
|
|
2544
|
+
"a push are coalesced into the next cycle.",
|
|
2545
|
+
"",
|
|
2546
|
+
TOKEN_RESOLUTION_HELP
|
|
2411
2547
|
].join("\n")
|
|
2412
2548
|
},
|
|
2413
2549
|
{
|
|
@@ -2528,6 +2664,7 @@ async function runDeploy(args) {
|
|
|
2528
2664
|
{
|
|
2529
2665
|
server: { type: "string", short: "s" },
|
|
2530
2666
|
token: { type: "string", short: "t" },
|
|
2667
|
+
"token-file": { type: "string" },
|
|
2531
2668
|
node: { type: "string", short: "n" },
|
|
2532
2669
|
cluster: { type: "boolean", short: "c" },
|
|
2533
2670
|
build: { type: "string", short: "b" },
|
|
@@ -2542,15 +2679,9 @@ async function runDeploy(args) {
|
|
|
2542
2679
|
return;
|
|
2543
2680
|
}
|
|
2544
2681
|
const addonPath = parsed.positionals[0] ?? ".";
|
|
2545
|
-
const
|
|
2546
|
-
const server =
|
|
2547
|
-
const token =
|
|
2548
|
-
if (!token) {
|
|
2549
|
-
console.error(
|
|
2550
|
-
"[camstack] Error: No token. Run `camstack login` first, pass --token, or set CAMSTACK_TOKEN."
|
|
2551
|
-
);
|
|
2552
|
-
process.exit(1);
|
|
2553
|
-
}
|
|
2682
|
+
const creds = resolveCommandCredentials(parsed.values);
|
|
2683
|
+
const server = creds.server ?? DEFAULT_SERVER_URL;
|
|
2684
|
+
const token = creds.token;
|
|
2554
2685
|
const nodeId = stringOpt(parsed.values, "node");
|
|
2555
2686
|
const cluster = boolOpt(parsed.values, "cluster");
|
|
2556
2687
|
if (nodeId && cluster) {
|
|
@@ -2572,6 +2703,7 @@ async function runDeploy(args) {
|
|
|
2572
2703
|
await deployAddon(addonPath, {
|
|
2573
2704
|
serverUrl: server,
|
|
2574
2705
|
token,
|
|
2706
|
+
authSource: creds.source,
|
|
2575
2707
|
...nodeId ? { nodeId } : {},
|
|
2576
2708
|
...cluster ? { cluster: true } : {},
|
|
2577
2709
|
buildMode,
|
|
@@ -2585,6 +2717,7 @@ async function runDeployServer(args) {
|
|
|
2585
2717
|
{
|
|
2586
2718
|
server: { type: "string", short: "s" },
|
|
2587
2719
|
token: { type: "string", short: "t" },
|
|
2720
|
+
"token-file": { type: "string" },
|
|
2588
2721
|
"no-verify": { type: "boolean" }
|
|
2589
2722
|
},
|
|
2590
2723
|
false
|
|
@@ -2593,21 +2726,36 @@ async function runDeployServer(args) {
|
|
|
2593
2726
|
console.log(commandHelp("deploy-server"));
|
|
2594
2727
|
return;
|
|
2595
2728
|
}
|
|
2596
|
-
const
|
|
2597
|
-
const server = stringOpt(parsed.values, "server") ?? process.env.CAMSTACK_SERVER ?? session?.server ?? "https://localhost:4443";
|
|
2598
|
-
const token = stringOpt(parsed.values, "token") ?? process.env.CAMSTACK_TOKEN ?? session?.token;
|
|
2599
|
-
if (!token) {
|
|
2600
|
-
console.error(
|
|
2601
|
-
"[camstack] Error: No token. Run `camstack login` first, pass --token, or set CAMSTACK_TOKEN."
|
|
2602
|
-
);
|
|
2603
|
-
process.exit(1);
|
|
2604
|
-
}
|
|
2729
|
+
const creds = resolveCommandCredentials(parsed.values);
|
|
2605
2730
|
await deployServer({
|
|
2606
|
-
serverUrl: server,
|
|
2607
|
-
token,
|
|
2731
|
+
serverUrl: creds.server ?? DEFAULT_SERVER_URL,
|
|
2732
|
+
token: creds.token,
|
|
2733
|
+
authSource: creds.source,
|
|
2608
2734
|
verify: !boolOpt(parsed.values, "no-verify")
|
|
2609
2735
|
});
|
|
2610
2736
|
}
|
|
2737
|
+
var DEFAULT_SERVER_URL = "https://localhost:4443";
|
|
2738
|
+
function resolveCommandCredentials(values) {
|
|
2739
|
+
const server = stringOpt(values, "server");
|
|
2740
|
+
const token = stringOpt(values, "token");
|
|
2741
|
+
const tokenFile = stringOpt(values, "token-file");
|
|
2742
|
+
try {
|
|
2743
|
+
const creds = resolveCredentials({
|
|
2744
|
+
...server ? { server } : {},
|
|
2745
|
+
...token ? { token } : {},
|
|
2746
|
+
...tokenFile ? { tokenFile } : {},
|
|
2747
|
+
loadSession
|
|
2748
|
+
});
|
|
2749
|
+
if (creds.warning) console.error(`[camstack] Warning: ${creds.warning}`);
|
|
2750
|
+
return creds;
|
|
2751
|
+
} catch (err) {
|
|
2752
|
+
if (err instanceof MissingCredentialsError) {
|
|
2753
|
+
console.error(`[camstack] ${err.message}`);
|
|
2754
|
+
process.exit(1);
|
|
2755
|
+
}
|
|
2756
|
+
throw err;
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2611
2759
|
function commandHelp(name) {
|
|
2612
2760
|
const cmd = buildCommands().find((c) => c.name === name);
|
|
2613
2761
|
return cmd ? cmd.help() : "";
|