@blankdotpage/cli 0.1.0 → 0.1.2
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/README.md +0 -1
- package/dist/index.js +93 -27
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import fs2 from "node:fs/promises";
|
|
5
5
|
import os2 from "node:os";
|
|
6
|
-
import { spawn } from "node:child_process";
|
|
7
6
|
import { URL } from "node:url";
|
|
8
7
|
|
|
9
8
|
// src/lib/args.ts
|
|
@@ -41,10 +40,67 @@ function booleanFlag(flags, key) {
|
|
|
41
40
|
return flags[key] === true;
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
// src/lib/browser.ts
|
|
44
|
+
import {
|
|
45
|
+
spawn
|
|
46
|
+
} from "node:child_process";
|
|
47
|
+
function getLaunchCommand(platform, url) {
|
|
48
|
+
if (platform === "darwin") {
|
|
49
|
+
return { command: "open", args: [url] };
|
|
50
|
+
}
|
|
51
|
+
if (platform === "linux") {
|
|
52
|
+
return { command: "xdg-open", args: [url] };
|
|
53
|
+
}
|
|
54
|
+
if (platform === "win32") {
|
|
55
|
+
return { command: "cmd", args: ["/c", "start", "", url] };
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function toError(error) {
|
|
60
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
61
|
+
}
|
|
62
|
+
function openBrowser(url, options = {}) {
|
|
63
|
+
const platform = options.platform ?? process.platform;
|
|
64
|
+
const launch = getLaunchCommand(platform, url);
|
|
65
|
+
if (!launch) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const spawnCommand = options.spawnCommand ?? ((command, args, spawnOptions) => spawn(command, args, spawnOptions));
|
|
69
|
+
const onError = options.onError ?? (() => {
|
|
70
|
+
});
|
|
71
|
+
try {
|
|
72
|
+
const child = spawnCommand(launch.command, launch.args, {
|
|
73
|
+
stdio: "ignore",
|
|
74
|
+
detached: true
|
|
75
|
+
});
|
|
76
|
+
child.once("error", (error) => {
|
|
77
|
+
onError(toError(error));
|
|
78
|
+
});
|
|
79
|
+
child.unref();
|
|
80
|
+
return true;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
onError(toError(error));
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
44
87
|
// src/lib/config.ts
|
|
45
88
|
import os from "node:os";
|
|
46
89
|
import path from "node:path";
|
|
47
90
|
import fs from "node:fs/promises";
|
|
91
|
+
function isObject(value) {
|
|
92
|
+
return typeof value === "object" && value !== null;
|
|
93
|
+
}
|
|
94
|
+
function readOptionalString(input, key) {
|
|
95
|
+
const value = input[key];
|
|
96
|
+
if (value === void 0) {
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
if (typeof value !== "string") {
|
|
100
|
+
throw new Error(`Invalid CLI config value for "${key}"`);
|
|
101
|
+
}
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
48
104
|
function resolveConfigPath() {
|
|
49
105
|
if (process.env.BLANKPAGE_CLI_CONFIG_PATH) {
|
|
50
106
|
return process.env.BLANKPAGE_CLI_CONFIG_PATH;
|
|
@@ -55,15 +111,39 @@ async function loadConfig() {
|
|
|
55
111
|
const configPath = resolveConfigPath();
|
|
56
112
|
try {
|
|
57
113
|
const raw = await fs.readFile(configPath, "utf8");
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
114
|
+
let parsed;
|
|
115
|
+
try {
|
|
116
|
+
parsed = JSON.parse(raw);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Failed to parse CLI config file at ${configPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
if (!isObject(parsed)) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Invalid CLI config file at ${configPath}: expected an object`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
appUrl: readOptionalString(parsed, "appUrl"),
|
|
129
|
+
token: readOptionalString(parsed, "token"),
|
|
130
|
+
tokenExpiresAt: readOptionalString(parsed, "tokenExpiresAt")
|
|
131
|
+
};
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error.code === "ENOENT") {
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
136
|
+
throw error;
|
|
61
137
|
}
|
|
62
138
|
}
|
|
63
139
|
async function saveConfig(config) {
|
|
64
140
|
const configPath = resolveConfigPath();
|
|
65
|
-
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
66
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2),
|
|
141
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 448 });
|
|
142
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), {
|
|
143
|
+
encoding: "utf8",
|
|
144
|
+
mode: 384
|
|
145
|
+
});
|
|
146
|
+
await fs.chmod(configPath, 384);
|
|
67
147
|
}
|
|
68
148
|
|
|
69
149
|
// src/lib/http.ts
|
|
@@ -195,7 +275,7 @@ function generatePageId() {
|
|
|
195
275
|
|
|
196
276
|
// src/index.ts
|
|
197
277
|
function getDefaultAppUrl() {
|
|
198
|
-
return process.env.
|
|
278
|
+
return process.env.BLANKPAGE_APP_URL || "https://blank.page";
|
|
199
279
|
}
|
|
200
280
|
function resolveAppUrl({
|
|
201
281
|
appUrlFlag,
|
|
@@ -212,23 +292,6 @@ function requireToken(token) {
|
|
|
212
292
|
function sleep(ms) {
|
|
213
293
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
214
294
|
}
|
|
215
|
-
function maybeOpenBrowser(url) {
|
|
216
|
-
const platform = process.platform;
|
|
217
|
-
if (platform === "darwin") {
|
|
218
|
-
spawn("open", [url], { stdio: "ignore", detached: true }).unref();
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (platform === "linux") {
|
|
222
|
-
spawn("xdg-open", [url], { stdio: "ignore", detached: true }).unref();
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
if (platform === "win32") {
|
|
226
|
-
spawn("cmd", ["/c", "start", "", url], {
|
|
227
|
-
stdio: "ignore",
|
|
228
|
-
detached: true
|
|
229
|
-
}).unref();
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
295
|
function output(json, payload, text) {
|
|
233
296
|
if (json) {
|
|
234
297
|
printJson(payload);
|
|
@@ -265,13 +328,16 @@ async function commandLogin(ctx) {
|
|
|
265
328
|
{
|
|
266
329
|
event: "login_started",
|
|
267
330
|
authorizeUrl: started.authorizeUrl,
|
|
268
|
-
challengeId: started.challengeId
|
|
269
|
-
challengeSecret: started.challengeSecret
|
|
331
|
+
challengeId: started.challengeId
|
|
270
332
|
},
|
|
271
333
|
`Open this URL to authorize: ${started.authorizeUrl}`
|
|
272
334
|
);
|
|
273
335
|
if (!noBrowser) {
|
|
274
|
-
|
|
336
|
+
openBrowser(started.authorizeUrl, {
|
|
337
|
+
onError: (error) => {
|
|
338
|
+
printError(`Could not open browser automatically: ${error.message}`);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
275
341
|
}
|
|
276
342
|
const deadline = Date.now() + timeoutSeconds * 1e3;
|
|
277
343
|
while (Date.now() < deadline) {
|