@boole-digital/cli 0.2.1 → 0.2.3
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/index.js +39 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
chmodSync,
|
|
17
17
|
rmSync
|
|
18
18
|
} from "node:fs";
|
|
19
|
-
var API_BASE = (process.env.BOOLE_API_BASE || "https://
|
|
19
|
+
var API_BASE = (process.env.BOOLE_API_BASE || "https://api.cest-finyx.com").replace(/\/+$/, "");
|
|
20
|
+
var WEB_BASE = (process.env.BOOLE_WEB_BASE || process.env.BOOLE_API_BASE || "https://trade.boole.markets").replace(/\/+$/, "");
|
|
20
21
|
var CONFIG_DIR = process.env.BOOLE_HOME || join(homedir(), ".boole");
|
|
21
22
|
var CRED_PATH = join(CONFIG_DIR, "credentials.json");
|
|
22
23
|
var SESSION_PATH = join(CONFIG_DIR, "session.env");
|
|
@@ -145,12 +146,12 @@ function decodePayload(code) {
|
|
|
145
146
|
};
|
|
146
147
|
}
|
|
147
148
|
function successHtml(email, dashboardUrl) {
|
|
148
|
-
const who = email ? `<p>Signed in as <b
|
|
149
|
+
const who = email ? `<p class="who">Signed in as: <b>${email.replace(/[<>&]/g, "")}</b></p>` : "";
|
|
149
150
|
const url = dashboardUrl.replace(/"/g, "");
|
|
150
151
|
return `<!doctype html><meta charset=utf-8><title>Boole</title>
|
|
151
|
-
<style>body{font:16px -apple-system,system-ui,sans-serif;background:#0b0b0b;color:#eaeaea;display:grid;place-items:center;height:100vh;margin:0}div{text-align:center}h1{font-size:22px}p{color:#9a9a9a;margin:
|
|
152
|
-
<div><h1
|
|
153
|
-
<a class="btn" href="${url}">
|
|
152
|
+
<style>body{font:16px -apple-system,system-ui,sans-serif;background:#0b0b0b;color:#eaeaea;display:grid;place-items:center;height:100vh;margin:0}div{text-align:center}h1{font-size:22px;font-weight:600;margin:0 0 14px}p{margin:6px 0;color:#9a9a9a}.who b{color:#eaeaea;font-weight:600}.tag{color:#7a7a7a;margin-top:16px}.btn{display:inline-block;margin-top:22px;padding:10px 22px;border-radius:8px;background:#1c1c22;color:#c8c8d0;text-decoration:none;font-weight:500;border:1px solid #2e2e38}.btn:hover{background:#26262e;color:#eaeaea}</style>
|
|
153
|
+
<div><h1>Authenticated to Boole</h1>${who}<p class="tag">Go build something great</p>
|
|
154
|
+
<a class="btn" href="${url}">Continue to Boole</a></div>`;
|
|
154
155
|
}
|
|
155
156
|
function emailFromCode(code) {
|
|
156
157
|
try {
|
|
@@ -160,7 +161,7 @@ function emailFromCode(code) {
|
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
async function loginPaste() {
|
|
163
|
-
const url = `${
|
|
164
|
+
const url = `${WEB_BASE}/cli-auth?paste=1`;
|
|
164
165
|
info("Opening the Boole login page\u2026");
|
|
165
166
|
log(` ${c.dim("If it does not open, visit:")} ${c.cyan(url)}`);
|
|
166
167
|
openBrowser(url);
|
|
@@ -190,7 +191,7 @@ async function loginLoopback() {
|
|
|
190
191
|
return;
|
|
191
192
|
}
|
|
192
193
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
|
|
193
|
-
res.end(successHtml(emailFromCode(code),
|
|
194
|
+
res.end(successHtml(emailFromCode(code), WEB_BASE));
|
|
194
195
|
queueMicrotask(() => resolveCode(code));
|
|
195
196
|
});
|
|
196
197
|
const port = await new Promise((resolve2) => {
|
|
@@ -199,7 +200,7 @@ async function loginLoopback() {
|
|
|
199
200
|
resolve2(typeof addr === "object" && addr ? addr.port : 0);
|
|
200
201
|
});
|
|
201
202
|
});
|
|
202
|
-
const url = `${
|
|
203
|
+
const url = `${WEB_BASE}/cli-auth?port=${port}`;
|
|
203
204
|
info("Opening the Boole login page in your browser\u2026");
|
|
204
205
|
log(` ${c.dim("If it does not open, visit:")} ${c.cyan(url)}`);
|
|
205
206
|
openBrowser(url);
|
|
@@ -283,14 +284,27 @@ var BooleApi = class {
|
|
|
283
284
|
async request(path, init2 = {}) {
|
|
284
285
|
await this.ensureFresh();
|
|
285
286
|
if (!this.creds) throw new AuthError("Not logged in. Run `boole login`.");
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
287
|
+
const TIMEOUT_MS = Number(process.env.BOOLE_TIMEOUT_MS) || 12e3;
|
|
288
|
+
const doFetch = async () => {
|
|
289
|
+
const ac = new AbortController();
|
|
290
|
+
const t = setTimeout(() => ac.abort(), TIMEOUT_MS);
|
|
291
|
+
try {
|
|
292
|
+
return await fetch(`${API_BASE}${path}`, {
|
|
293
|
+
...init2,
|
|
294
|
+
signal: ac.signal,
|
|
295
|
+
headers: {
|
|
296
|
+
"Content-Type": "application/json",
|
|
297
|
+
...init2.headers || {},
|
|
298
|
+
Authorization: `Bearer ${this.creds.access_token}`
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
} catch (e) {
|
|
302
|
+
if (e?.name === "AbortError") throw new Error(`${path}: timed out after ${TIMEOUT_MS / 1e3}s (network or box waking up)`);
|
|
303
|
+
throw e;
|
|
304
|
+
} finally {
|
|
305
|
+
clearTimeout(t);
|
|
292
306
|
}
|
|
293
|
-
}
|
|
307
|
+
};
|
|
294
308
|
let res = await doFetch();
|
|
295
309
|
if (res.status === 401) {
|
|
296
310
|
this.creds.expires_at = 0;
|
|
@@ -368,7 +382,7 @@ function onboardingNotice() {
|
|
|
368
382
|
warn("No trading computer yet \u2014 and you can\u2019t deploy your first one from the CLI.");
|
|
369
383
|
log(" Finish onboarding in the Boole app first (this is required):");
|
|
370
384
|
log(` 1. Create your account 2. Agree to the terms 3. Set up billing`);
|
|
371
|
-
log(` ${c.cyan(
|
|
385
|
+
log(` ${c.cyan(WEB_BASE)}`);
|
|
372
386
|
log(` Deploy your first trading computer there, then come back and run ${c.cyan("boole connect")}.`);
|
|
373
387
|
log("");
|
|
374
388
|
}
|
|
@@ -389,7 +403,7 @@ function orient() {
|
|
|
389
403
|
log(`${c.bold("Do this next:")} ${c.cyan("boole login")}`);
|
|
390
404
|
} else if (!sess) {
|
|
391
405
|
log(`${c.bold("You are:")} logged in as ${c.bold(creds.user.email || creds.user.id)}, ${c.yellow("no box connected")}.`);
|
|
392
|
-
log(`${c.bold("Do this next:")} ${c.cyan("boole connect")} ${c.dim(`# no trading computer yet? finish onboarding at ${
|
|
406
|
+
log(`${c.bold("Do this next:")} ${c.cyan("boole connect")} ${c.dim(`# no trading computer yet? finish onboarding at ${WEB_BASE}`)}`);
|
|
393
407
|
} else {
|
|
394
408
|
log(`${c.bold("You are:")} connected to ${c.bold(sess.agent || sess.ip)} ${c.green("\u2014 ready")}.`);
|
|
395
409
|
log(c.bold("Do this next:"));
|
|
@@ -445,7 +459,8 @@ function pickAgentId(droplets) {
|
|
|
445
459
|
if (ready.length === 1) return { id: ready[0].id, name: ready[0].name };
|
|
446
460
|
return null;
|
|
447
461
|
}
|
|
448
|
-
async function summary() {
|
|
462
|
+
async function summary(opts = {}) {
|
|
463
|
+
const snapshot = opts.snapshot !== false;
|
|
449
464
|
const creds = loadCredentials();
|
|
450
465
|
if (!creds) {
|
|
451
466
|
warn("Not logged in. Run `boole login`.");
|
|
@@ -483,7 +498,7 @@ async function summary() {
|
|
|
483
498
|
log(c.bold(`Trading computers (${droplets.length})`));
|
|
484
499
|
printAgents(droplets);
|
|
485
500
|
const pick = pickAgentId(droplets);
|
|
486
|
-
if (pick) {
|
|
501
|
+
if (pick && snapshot) {
|
|
487
502
|
log("");
|
|
488
503
|
log(c.bold(`Snapshot \u2014 ${pick.name}`));
|
|
489
504
|
try {
|
|
@@ -493,6 +508,8 @@ async function summary() {
|
|
|
493
508
|
} catch {
|
|
494
509
|
warn("trading computer unreachable (tunnel may be waking up \u2014 retry in a moment)");
|
|
495
510
|
}
|
|
511
|
+
} else if (pick) {
|
|
512
|
+
log(c.dim(` Run ${c.cyan("boole status")} for balances + live snapshot.`));
|
|
496
513
|
}
|
|
497
514
|
operatingBrief();
|
|
498
515
|
}
|
|
@@ -711,7 +728,7 @@ function init(opts = {}) {
|
|
|
711
728
|
}
|
|
712
729
|
|
|
713
730
|
// src/index.ts
|
|
714
|
-
var VERSION = "0.2.
|
|
731
|
+
var VERSION = "0.2.3";
|
|
715
732
|
function parse(argv) {
|
|
716
733
|
const _ = [];
|
|
717
734
|
const flags = {};
|
|
@@ -756,7 +773,7 @@ ${c.bold("Operate the box")}
|
|
|
756
773
|
${c.bold("Other")}
|
|
757
774
|
help, --help \xB7 version, --version
|
|
758
775
|
|
|
759
|
-
Env: ${c.dim("BOOLE_API_BASE")} (
|
|
776
|
+
Env: ${c.dim("BOOLE_API_BASE")} (REST API) \xB7 ${c.dim("BOOLE_WEB_BASE")} (login page) \xB7 ${c.dim("BOOLE_HOME")} \xB7 ${c.dim("BOOLE_TIMEOUT_MS")}
|
|
760
777
|
`;
|
|
761
778
|
async function main() {
|
|
762
779
|
const { _, flags } = parse(process.argv.slice(2));
|
|
@@ -776,7 +793,7 @@ async function main() {
|
|
|
776
793
|
switch (cmd) {
|
|
777
794
|
case "login":
|
|
778
795
|
await login({ paste: !!flags.paste });
|
|
779
|
-
await summary();
|
|
796
|
+
await summary({ snapshot: false });
|
|
780
797
|
break;
|
|
781
798
|
case "logout":
|
|
782
799
|
await logout();
|
package/package.json
CHANGED