arcadible 0.1.34 → 0.1.36
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/bin/arc-login.js +16 -7
- package/bin/arc-whoami.js +2 -2
- package/package.json +1 -1
- package/src/account.js +1 -2
- package/src/schema/game.js +17 -8
- package/src/schema/workflow.js +11 -1
- package/src/util/argv.js +16 -7
- package/src/util/output.js +8 -3
- package/src/util/rc.js +33 -8
package/bin/arc-login.js
CHANGED
|
@@ -16,6 +16,7 @@ const cfgproduct = require("../src/config/product");
|
|
|
16
16
|
const error = require("../src/util/error");
|
|
17
17
|
const log = require("../src/util/log");
|
|
18
18
|
const login = require("../src/cli/login");
|
|
19
|
+
const output = require("../src/util/output");
|
|
19
20
|
const phrase = require("../src/phrase");
|
|
20
21
|
const rc = require("../src/util/rc");
|
|
21
22
|
const shell = require("../src/util/shell");
|
|
@@ -23,6 +24,7 @@ const spinner = require("../src/util/spinner");
|
|
|
23
24
|
|
|
24
25
|
// [use]
|
|
25
26
|
|
|
27
|
+
const abort = output.abort;
|
|
26
28
|
const ArcError = error.ArcError;
|
|
27
29
|
const findRc = rc.findRc;
|
|
28
30
|
const launch = shell.launch;
|
|
@@ -70,10 +72,13 @@ const onLoginEnter = function (fn) {
|
|
|
70
72
|
|
|
71
73
|
// [function]
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
// `shown` is set once the link is printed, so a failure after it starts
|
|
76
|
+
// after a blank line.
|
|
77
|
+
const handler = function ({ browser, qrcode: qr, shown, sw }) {
|
|
74
78
|
return {
|
|
75
79
|
onLoginCreated({ code: dac, secret, url }) {
|
|
76
80
|
sw.stop(true);
|
|
81
|
+
shown.link = true;
|
|
77
82
|
const link = `${url}/${secret}`;
|
|
78
83
|
log.p("Logging in...");
|
|
79
84
|
qrcode.generate(link, { small: true }, (code) => {
|
|
@@ -82,7 +87,8 @@ const handler = function ({ browser, qrcode: qr, sw }) {
|
|
|
82
87
|
}
|
|
83
88
|
log.nlp(url);
|
|
84
89
|
log.h(dac.toUpperCase());
|
|
85
|
-
|
|
90
|
+
// a key press can only be read from a terminal.
|
|
91
|
+
if (browser && process.stdin.isTTY) {
|
|
86
92
|
log.nlp("Press Enter to open the URL.");
|
|
87
93
|
onLoginEnter(() => {
|
|
88
94
|
launch(link);
|
|
@@ -96,10 +102,16 @@ const handler = function ({ browser, qrcode: qr, sw }) {
|
|
|
96
102
|
// [function]
|
|
97
103
|
|
|
98
104
|
const start = function (argv) {
|
|
105
|
+
const shown = { link: false };
|
|
99
106
|
const sw = new SpinnerWheel("Logging in... %s");
|
|
100
107
|
sw.start();
|
|
101
108
|
return login({
|
|
102
|
-
handler: handler({
|
|
109
|
+
handler: handler({
|
|
110
|
+
browser: argv.browser,
|
|
111
|
+
qrcode: argv.qrcode,
|
|
112
|
+
shown,
|
|
113
|
+
sw,
|
|
114
|
+
}),
|
|
103
115
|
})
|
|
104
116
|
.then((current) => {
|
|
105
117
|
const user = current?.user;
|
|
@@ -111,11 +123,8 @@ const start = function (argv) {
|
|
|
111
123
|
log.result("Logged in.", [user.display_name], { nl: true });
|
|
112
124
|
})
|
|
113
125
|
.catch((ex) => {
|
|
114
|
-
sw.stop(true);
|
|
115
126
|
process.stdin.pause();
|
|
116
|
-
|
|
117
|
-
log.pd(ex.message);
|
|
118
|
-
process.exit(1);
|
|
127
|
+
abort("Login aborted.", ex, { nl: shown.link, sw });
|
|
119
128
|
});
|
|
120
129
|
};
|
|
121
130
|
|
package/bin/arc-whoami.js
CHANGED
|
@@ -8,8 +8,8 @@ const yargs = require("yargs/yargs");
|
|
|
8
8
|
|
|
9
9
|
// [import]
|
|
10
10
|
|
|
11
|
-
const account = require("../src/account");
|
|
12
11
|
const args = require("../src/util/argv");
|
|
12
|
+
const cfgcode = require("../src/config/code");
|
|
13
13
|
const cfgpackage = require("../src/config/package");
|
|
14
14
|
const cfgproduct = require("../src/config/product");
|
|
15
15
|
const log = require("../src/util/log");
|
|
@@ -76,7 +76,7 @@ const start = function (argv) {
|
|
|
76
76
|
.catch((ex) => {
|
|
77
77
|
const message = ex.message;
|
|
78
78
|
// a session that can't be refreshed is no session: say so, and why.
|
|
79
|
-
if (ex.code ===
|
|
79
|
+
if (ex.code === cfgcode.SESSION_EXPIRED) {
|
|
80
80
|
if (json) {
|
|
81
81
|
print({ user: null });
|
|
82
82
|
} else {
|
package/package.json
CHANGED
package/src/account.js
CHANGED
|
@@ -40,7 +40,6 @@ const FILE_MODE = 0o600;
|
|
|
40
40
|
|
|
41
41
|
// the statuses that mean the refresh token itself was refused.
|
|
42
42
|
const REJECTED = [400, 401, 403];
|
|
43
|
-
const SESSION_EXPIRED = cfgcode.SESSION_EXPIRED;
|
|
44
43
|
|
|
45
44
|
// [declare]
|
|
46
45
|
|
|
@@ -154,4 +153,4 @@ const remove = function () {
|
|
|
154
153
|
|
|
155
154
|
// [export]
|
|
156
155
|
|
|
157
|
-
module.exports = {
|
|
156
|
+
module.exports = { get, remove, save };
|
package/src/schema/game.js
CHANGED
|
@@ -130,6 +130,19 @@ const atLeast = function (field, min, unit) {
|
|
|
130
130
|
|
|
131
131
|
// [function]
|
|
132
132
|
|
|
133
|
+
// a required string's error: "Must be defined." and `lines` when it's missing,
|
|
134
|
+
// and zod's own type message (null) when it's there but isn't a string.
|
|
135
|
+
const required = function (field, lines) {
|
|
136
|
+
const missing = message(field, ["Must be defined.", ...lines]).message;
|
|
137
|
+
return {
|
|
138
|
+
error(issue) {
|
|
139
|
+
return typeof issue.input === "undefined" ? missing : null;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// [function]
|
|
145
|
+
|
|
133
146
|
// a list of distinct values. Without a max, its length is up to the values.
|
|
134
147
|
const zSet = function (field, schema, { max = Infinity, min }) {
|
|
135
148
|
return z
|
|
@@ -422,6 +435,7 @@ const zHandle = function () {
|
|
|
422
435
|
return z.optional(
|
|
423
436
|
z
|
|
424
437
|
.string()
|
|
438
|
+
.min(1, { ...atLeast(field, 1), abort: true })
|
|
425
439
|
.regex(
|
|
426
440
|
/^[a-z0-9](?:(?![-]{2})[a-z0-9-]){1,22}[a-z0-9]$/u,
|
|
427
441
|
message(field, ["Contains invalid characters."]),
|
|
@@ -435,10 +449,7 @@ const zId = function () {
|
|
|
435
449
|
const field = "id";
|
|
436
450
|
return z
|
|
437
451
|
.string(
|
|
438
|
-
|
|
439
|
-
"Must be defined.",
|
|
440
|
-
`Run ${phrase.cmdInit()} to generate a new game ID.`,
|
|
441
|
-
]),
|
|
452
|
+
required(field, [`Run ${phrase.cmdInit()} to generate a new game ID.`]),
|
|
442
453
|
)
|
|
443
454
|
.uuid(message(field, ["Must be a valid UUID."]))
|
|
444
455
|
.refine(
|
|
@@ -499,6 +510,7 @@ const zTrailer = function () {
|
|
|
499
510
|
const field = "trailer";
|
|
500
511
|
return z
|
|
501
512
|
.string()
|
|
513
|
+
.min(1, { ...atLeast(field, 1), abort: true })
|
|
502
514
|
.max(255, message(field, ["Must not exceed: 255 characters"]))
|
|
503
515
|
.refine(
|
|
504
516
|
(url) =>
|
|
@@ -514,10 +526,7 @@ const zVersion = function () {
|
|
|
514
526
|
const field = "version";
|
|
515
527
|
return z
|
|
516
528
|
.string(
|
|
517
|
-
|
|
518
|
-
"Must be defined.",
|
|
519
|
-
"A version is required unless one can be derived.",
|
|
520
|
-
]),
|
|
529
|
+
required(field, ["A version is required unless one can be derived."]),
|
|
521
530
|
)
|
|
522
531
|
.refine(
|
|
523
532
|
(value) => validSemver(value) !== null,
|
package/src/schema/workflow.js
CHANGED
|
@@ -33,6 +33,16 @@ const RESERVED = [`${HANDLE}.json`, MEDIA];
|
|
|
33
33
|
|
|
34
34
|
// [function]
|
|
35
35
|
|
|
36
|
+
// whether `build` runs anything: a command that isn't blank, as `arc build`
|
|
37
|
+
// trims and drops blank ones (action/build/tool.js).
|
|
38
|
+
const hasBuild = function (build) {
|
|
39
|
+
return [build]
|
|
40
|
+
.flat()
|
|
41
|
+
.some((cmd) => typeof cmd === "string" && cmd.trim() !== "");
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// [function]
|
|
45
|
+
|
|
36
46
|
const zBuild = function () {
|
|
37
47
|
// const field = "build";
|
|
38
48
|
return z.union([z.string(), z.array(z.string())]);
|
|
@@ -70,7 +80,7 @@ const zDeployDir = function (root, { build }) {
|
|
|
70
80
|
),
|
|
71
81
|
)
|
|
72
82
|
.refine(
|
|
73
|
-
(file) => build || existsCheck(root, file),
|
|
83
|
+
(file) => hasBuild(build) || existsCheck(root, file),
|
|
74
84
|
message(
|
|
75
85
|
field,
|
|
76
86
|
[
|
package/src/util/argv.js
CHANGED
|
@@ -55,20 +55,29 @@ const cwd = function (args) {
|
|
|
55
55
|
|
|
56
56
|
// [function]
|
|
57
57
|
|
|
58
|
+
// whether `argv` passes --json, before the command parses its options.
|
|
59
|
+
const json = function (argv) {
|
|
60
|
+
return parse(normalize(hideBin(argv)), {
|
|
61
|
+
alias: { json: ["j"] },
|
|
62
|
+
boolean: ["json"],
|
|
63
|
+
}).json;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// [function]
|
|
67
|
+
|
|
58
68
|
// yargs' failure handler for a command with --json: an argument error is
|
|
59
69
|
// one JSON document when --json was passed (OUTPUT.md), and yargs' own help
|
|
60
70
|
// and message otherwise.
|
|
61
71
|
const fail = function (argv) {
|
|
62
|
-
const
|
|
63
|
-
alias: { json: ["j"] },
|
|
64
|
-
boolean: ["json"],
|
|
65
|
-
}).json;
|
|
72
|
+
const asJson = json(argv);
|
|
66
73
|
return (message, ex, cli) => {
|
|
67
74
|
if (ex) {
|
|
68
75
|
throw ex;
|
|
69
76
|
}
|
|
70
|
-
if (
|
|
71
|
-
abort("", new ArcError(cfgcode.ARGUMENT_INVALID, message), {
|
|
77
|
+
if (asJson) {
|
|
78
|
+
abort("", new ArcError(cfgcode.ARGUMENT_INVALID, message), {
|
|
79
|
+
json: asJson,
|
|
80
|
+
});
|
|
72
81
|
}
|
|
73
82
|
cli.showHelp("error");
|
|
74
83
|
console.error(`\n${message}`);
|
|
@@ -78,4 +87,4 @@ const fail = function (argv) {
|
|
|
78
87
|
|
|
79
88
|
// [export]
|
|
80
89
|
|
|
81
|
-
module.exports = { CWD, cwd, fail, normalize };
|
|
90
|
+
module.exports = { CWD, cwd, fail, json, normalize };
|
package/src/util/output.js
CHANGED
|
@@ -62,13 +62,14 @@ const print = function (data, { key, nl, toml } = {}) {
|
|
|
62
62
|
// aborted.") and the reason on stderr, then its code and the link to it on
|
|
63
63
|
// the Errors page, once the spinner and progress bar are cleared. Then exits
|
|
64
64
|
// 1. `data`, and the error's own, go beside the error in JSON, such as the
|
|
65
|
-
// release that failed.
|
|
65
|
+
// release that failed. `nl` puts a blank line before the heading, after
|
|
66
|
+
// output the command has already printed, such as arc login's link.
|
|
66
67
|
// `code` is a failed release's reason, which the API may add to, so it isn't
|
|
67
68
|
// checked, and its message already says it.
|
|
68
69
|
const abort = function (
|
|
69
70
|
heading,
|
|
70
71
|
ex,
|
|
71
|
-
{ code, data, json = false, pb, sw } = {},
|
|
72
|
+
{ code, data, json = false, nl = false, pb, sw } = {},
|
|
72
73
|
) {
|
|
73
74
|
const message = ex.message;
|
|
74
75
|
const status = ex.status;
|
|
@@ -89,7 +90,11 @@ const abort = function (
|
|
|
89
90
|
if (sw) {
|
|
90
91
|
sw.stop(true);
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
+
if (nl) {
|
|
94
|
+
log.nlhd(heading);
|
|
95
|
+
} else {
|
|
96
|
+
log.hd(heading);
|
|
97
|
+
}
|
|
93
98
|
log.pd(message);
|
|
94
99
|
if (!code) {
|
|
95
100
|
log.nlpd([
|
package/src/util/rc.js
CHANGED
|
@@ -13,9 +13,15 @@ const ini = require("ini");
|
|
|
13
13
|
// [import]
|
|
14
14
|
|
|
15
15
|
const args = require("./argv");
|
|
16
|
+
const cfgcode = require("../config/code");
|
|
17
|
+
const error = require("./error");
|
|
18
|
+
const output = require("./output");
|
|
19
|
+
const phrase = require("../phrase");
|
|
16
20
|
|
|
17
21
|
// [use]
|
|
18
22
|
|
|
23
|
+
const abort = output.abort;
|
|
24
|
+
const ArcError = error.ArcError;
|
|
19
25
|
const cwd = args.cwd;
|
|
20
26
|
const dirname = path.dirname;
|
|
21
27
|
const existsSync = fs.existsSync; // eslint-disable-line no-sync
|
|
@@ -60,7 +66,6 @@ const files = function (cmd, argv) {
|
|
|
60
66
|
? []
|
|
61
67
|
: [join("/etc", cmd, "config"), join("/etc", `${cmd}rc`)]),
|
|
62
68
|
join(home, ".config", cmd, "config"),
|
|
63
|
-
join(home, ".config", cmd),
|
|
64
69
|
join(home, `.${cmd}`, "config"),
|
|
65
70
|
join(home, `.${cmd}rc`),
|
|
66
71
|
nearest(cmd),
|
|
@@ -70,7 +75,8 @@ const files = function (cmd, argv) {
|
|
|
70
75
|
|
|
71
76
|
// [function]
|
|
72
77
|
|
|
73
|
-
// a file's sections, INI or JSON, or nothing when it can't be read.
|
|
78
|
+
// a file's sections, INI or JSON, or nothing when it can't be read. JSON
|
|
79
|
+
// that doesn't parse is `parse_failed`, naming the file.
|
|
74
80
|
const read = function (file) {
|
|
75
81
|
let str = null;
|
|
76
82
|
try {
|
|
@@ -78,18 +84,37 @@ const read = function (file) {
|
|
|
78
84
|
} catch (ex) {
|
|
79
85
|
return {};
|
|
80
86
|
}
|
|
81
|
-
|
|
87
|
+
if (!/^\s*\{/u.test(str)) {
|
|
88
|
+
return ini.parse(str);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return JSON.parse(str);
|
|
92
|
+
} catch (ex) {
|
|
93
|
+
throw new ArcError(
|
|
94
|
+
cfgcode.PARSE_FAILED,
|
|
95
|
+
phrase.unableToParse(file, ex.message),
|
|
96
|
+
{ cause: ex },
|
|
97
|
+
);
|
|
98
|
+
}
|
|
82
99
|
};
|
|
83
100
|
|
|
84
101
|
// [function]
|
|
85
102
|
|
|
86
103
|
// a command's section of .<cmd>rc, merged from the files `rc` reads. Unlike
|
|
87
|
-
// `rc`, environment variables and `--config` aren't read.
|
|
104
|
+
// `rc`, environment variables and `--config` aren't read. Options are read as
|
|
105
|
+
// the command loads, so a file that doesn't parse aborts the command here,
|
|
106
|
+
// as `<Command> aborted.`.
|
|
88
107
|
const findRc = function (cmd, subcmd, argv) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
try {
|
|
109
|
+
return [...new Set(files(cmd, argv))].reduce(
|
|
110
|
+
(found, file) => ({ ...found, ...read(file)[subcmd] }),
|
|
111
|
+
{},
|
|
112
|
+
);
|
|
113
|
+
} catch (ex) {
|
|
114
|
+
return abort(`${subcmd[0].toUpperCase()}${subcmd.slice(1)} aborted.`, ex, {
|
|
115
|
+
json: args.json(argv),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
93
118
|
};
|
|
94
119
|
|
|
95
120
|
// [export]
|