arcadible 1.0.1 → 1.0.4
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-build.js +7 -22
- package/bin/arc-default.js +8 -8
- package/bin/arc-deploy.js +31 -23
- package/bin/arc-init.js +4 -3
- package/bin/arc-login.js +2 -2
- package/bin/arc-pack.js +8 -22
- package/bin/arc-play.js +1 -1
- package/bin/arc-serve.js +4 -3
- package/bin/arc-validate.js +2 -1
- package/bin/arc-whoami.js +1 -1
- package/package.json +1 -1
- package/src/account.js +3 -1
- package/src/action/deploy/tool.js +5 -4
- package/src/action/predeploy/ac.js +47 -15
- package/src/action/predeploy/tool.js +3 -3
- package/src/action/serve/tool.js +19 -3
- package/src/action/validate/checked.js +37 -0
- package/src/api.js +39 -12
- package/src/config/code.js +3 -1
- package/src/parser/readme.js +1 -1
- package/src/phrase.js +86 -45
- package/src/schema/game.js +32 -20
- package/src/schema/readme.js +2 -1
- package/src/schema/workflow.js +8 -10
- package/src/serve/game.js +7 -1
- package/src/serve/page.js +11 -11
- package/src/serve/reload.js +5 -0
- package/src/util/log.js +9 -2
- package/src/util/md.js +1 -1
- package/src/util/output.js +17 -2
- package/src/util/schema.js +53 -1
package/src/schema/workflow.js
CHANGED
|
@@ -68,7 +68,7 @@ const zDeployDir = function (root, { build }) {
|
|
|
68
68
|
return z
|
|
69
69
|
.string()
|
|
70
70
|
.min(1, {
|
|
71
|
-
...message(field, ["Must not be empty. Leave the field out instead."]),
|
|
71
|
+
...message(field, ["Must not be empty.", "Leave the field out instead."]),
|
|
72
72
|
abort: true,
|
|
73
73
|
})
|
|
74
74
|
.refine((file) => isRelativeCheck(root, file), {
|
|
@@ -82,24 +82,20 @@ const zDeployDir = function (root, { build }) {
|
|
|
82
82
|
.refine((file) => !isRootCheck(root, file), {
|
|
83
83
|
...message(
|
|
84
84
|
field,
|
|
85
|
-
["Must be a
|
|
85
|
+
["Must be a folder in the project, not its root."],
|
|
86
86
|
ISSUE.PATH_INVALID,
|
|
87
87
|
),
|
|
88
88
|
abort: true,
|
|
89
89
|
})
|
|
90
90
|
.refine((file) => avoidsCheck(root, file, MEDIA), {
|
|
91
|
-
...message(
|
|
92
|
-
field,
|
|
93
|
-
[`Must not contain ${MEDIA} in path.`],
|
|
94
|
-
ISSUE.PATH_INVALID,
|
|
95
|
-
),
|
|
91
|
+
...message(field, [`Must not be in ${MEDIA}.`], ISSUE.PATH_INVALID),
|
|
96
92
|
abort: true,
|
|
97
93
|
})
|
|
98
94
|
.refine((file) => hasBuild(build) || existsCheck(root, file), {
|
|
99
95
|
...message(
|
|
100
96
|
field,
|
|
101
97
|
[
|
|
102
|
-
"Must exist
|
|
98
|
+
"Must exist, since there's no build.",
|
|
103
99
|
`Run ${phrase.cmdInspect()} for details.`,
|
|
104
100
|
],
|
|
105
101
|
ISSUE.PATH_INVALID,
|
|
@@ -118,7 +114,8 @@ const zDeployDir = function (root, { build }) {
|
|
|
118
114
|
...message(
|
|
119
115
|
field,
|
|
120
116
|
[
|
|
121
|
-
`Must not have ${RESERVED.join(" or ")} at its root
|
|
117
|
+
`Must not have ${RESERVED.join(" or ")} at its root.`,
|
|
118
|
+
`They're reserved for the files ${cfgproduct.title} adds.`,
|
|
122
119
|
],
|
|
123
120
|
ISSUE.PATH_INVALID,
|
|
124
121
|
),
|
|
@@ -128,7 +125,8 @@ const zDeployDir = function (root, { build }) {
|
|
|
128
125
|
...message(
|
|
129
126
|
field,
|
|
130
127
|
[
|
|
131
|
-
`Must not have an ${RESERVED_FOLDER} folder at its root, in any letter case
|
|
128
|
+
`Must not have an ${RESERVED_FOLDER} folder at its root, in any letter case.`,
|
|
129
|
+
`It's reserved for ${cfgproduct.title}'s own files.`,
|
|
132
130
|
],
|
|
133
131
|
ISSUE.PATH_INVALID,
|
|
134
132
|
),
|
package/src/serve/game.js
CHANGED
|
@@ -98,7 +98,13 @@ const sendFile = function (req, res, file, headers) {
|
|
|
98
98
|
res.end();
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
file
|
|
101
|
+
// the file can go between finding and reading it, as a rebuild empties
|
|
102
|
+
// deploy_dir: the headers are sent, so the response just ends
|
|
103
|
+
const stream = file.open(range);
|
|
104
|
+
stream.on("error", () => {
|
|
105
|
+
res.destroy();
|
|
106
|
+
});
|
|
107
|
+
stream.pipe(res);
|
|
102
108
|
};
|
|
103
109
|
|
|
104
110
|
// [function]
|
package/src/serve/page.js
CHANGED
|
@@ -24,6 +24,17 @@ const SANDBOX =
|
|
|
24
24
|
const HOST = "/_arcadible/host.js";
|
|
25
25
|
const RELOAD = "/_arcadible/reload";
|
|
26
26
|
|
|
27
|
+
// [declare]
|
|
28
|
+
|
|
29
|
+
// the headers of the page's responses, as the play page's: it's
|
|
30
|
+
// cross-origin isolated, and nothing frames it.
|
|
31
|
+
const HEADERS = {
|
|
32
|
+
"cache-control": "no-store",
|
|
33
|
+
"content-security-policy": "frame-ancestors 'none';",
|
|
34
|
+
"cross-origin-embedder-policy": "require-corp",
|
|
35
|
+
"cross-origin-opener-policy": "same-origin",
|
|
36
|
+
};
|
|
37
|
+
|
|
27
38
|
// [function]
|
|
28
39
|
|
|
29
40
|
// `value` as JSON that's safe inside a <script>.
|
|
@@ -105,17 +116,6 @@ const html = function (game) {
|
|
|
105
116
|
|
|
106
117
|
// [function]
|
|
107
118
|
|
|
108
|
-
// the headers of the page's responses, as the play page's: it's
|
|
109
|
-
// cross-origin isolated, and nothing frames it.
|
|
110
|
-
const HEADERS = {
|
|
111
|
-
"cache-control": "no-store",
|
|
112
|
-
"content-security-policy": "frame-ancestors 'none';",
|
|
113
|
-
"cross-origin-embedder-policy": "require-corp",
|
|
114
|
-
"cross-origin-opener-policy": "same-origin",
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
// [function]
|
|
118
|
-
|
|
119
119
|
// the request handler for the page's origin. `reloads` keeps the pages
|
|
120
120
|
// listening for a reload; `remote` has the host.
|
|
121
121
|
const pageHandler = function ({
|
package/src/serve/reload.js
CHANGED
|
@@ -52,6 +52,11 @@ const watchDir = function (dir, onChange) {
|
|
|
52
52
|
clearTimeout(timer);
|
|
53
53
|
timer = setTimeout(onChange, SETTLE);
|
|
54
54
|
});
|
|
55
|
+
// deploy_dir removed while it's watched (EPERM on Windows): stop watching
|
|
56
|
+
// rather than crash the server
|
|
57
|
+
watcher.on("error", () => {
|
|
58
|
+
watcher.close();
|
|
59
|
+
});
|
|
55
60
|
return () => {
|
|
56
61
|
clearTimeout(timer);
|
|
57
62
|
watcher.close();
|
package/src/util/log.js
CHANGED
|
@@ -30,6 +30,13 @@ const log = function (out, message, { bold = false, color, nl = false } = {}) {
|
|
|
30
30
|
|
|
31
31
|
// [function]
|
|
32
32
|
|
|
33
|
+
// a warning, marked with ⚠ (OUTPUT.md), on its first line.
|
|
34
|
+
const warned = function (message) {
|
|
35
|
+
return `⚠ ${[message].flat().join("\n").trim()}`;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// [function]
|
|
39
|
+
|
|
33
40
|
const h = function (message) {
|
|
34
41
|
log(console.log, message, { bold: true });
|
|
35
42
|
};
|
|
@@ -91,13 +98,13 @@ const hwo = function (message) {
|
|
|
91
98
|
// [function]
|
|
92
99
|
|
|
93
100
|
const pw = function (message) {
|
|
94
|
-
log(console.warn, message, { color: "yellow" });
|
|
101
|
+
log(console.warn, warned(message), { color: "yellow" });
|
|
95
102
|
};
|
|
96
103
|
|
|
97
104
|
// [function]
|
|
98
105
|
|
|
99
106
|
const nlpw = function (message) {
|
|
100
|
-
log(console.warn, message, { color: "yellow", nl: true });
|
|
107
|
+
log(console.warn, warned(message), { color: "yellow", nl: true });
|
|
101
108
|
};
|
|
102
109
|
|
|
103
110
|
// [function]
|
package/src/util/md.js
CHANGED
|
@@ -32,7 +32,7 @@ const escape = function (str) {
|
|
|
32
32
|
.replace(/>/gu, ">");
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
// [
|
|
35
|
+
// [define]
|
|
36
36
|
|
|
37
37
|
// there is no video syntax in Markdown, so an image of a video renders as the
|
|
38
38
|
// video the developer would have written: its src and title, and no alt.
|
package/src/util/output.js
CHANGED
|
@@ -59,6 +59,20 @@ const print = function (data, { key, nl, toml } = {}) {
|
|
|
59
59
|
|
|
60
60
|
// [function]
|
|
61
61
|
|
|
62
|
+
// exits with `code` once stdout has written what it holds. A pipe on macOS
|
|
63
|
+
// writes later, so exiting at once would cut a large --json document short;
|
|
64
|
+
// with nothing held, it exits at once, as a caller that goes on expects.
|
|
65
|
+
const exit = function (code) {
|
|
66
|
+
if (!process.stdout.writableLength) {
|
|
67
|
+
process.exit(code);
|
|
68
|
+
}
|
|
69
|
+
process.exitCode = code;
|
|
70
|
+
process.stdout.write("", () => process.exit(code));
|
|
71
|
+
return new Promise(() => {});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// [function]
|
|
75
|
+
|
|
62
76
|
// a command's error path: the error as JSON, or its heading ("Deploy
|
|
63
77
|
// aborted.") and the reason on stderr, then its code and the link to it on
|
|
64
78
|
// the Errors page, once the spinner and progress bar are cleared. Then exits
|
|
@@ -102,7 +116,7 @@ const abort = function (
|
|
|
102
116
|
log.pd(message);
|
|
103
117
|
log.nlpd([phrase.errorCode(shown), chalk.cyan.underline(link)]);
|
|
104
118
|
}
|
|
105
|
-
|
|
119
|
+
return exit(1);
|
|
106
120
|
};
|
|
107
121
|
|
|
108
122
|
// [function]
|
|
@@ -128,7 +142,7 @@ const warn = function (warnings, { json, quiet } = {}) {
|
|
|
128
142
|
if (json || quiet) {
|
|
129
143
|
return;
|
|
130
144
|
}
|
|
131
|
-
warnings.forEach((each) => log.pw(
|
|
145
|
+
warnings.forEach((each) => log.pw(schema.print(each)));
|
|
132
146
|
};
|
|
133
147
|
|
|
134
148
|
// [function]
|
|
@@ -150,6 +164,7 @@ const warning = function (code, message, path = null) {
|
|
|
150
164
|
|
|
151
165
|
module.exports = {
|
|
152
166
|
abort,
|
|
167
|
+
exit,
|
|
153
168
|
launched,
|
|
154
169
|
print,
|
|
155
170
|
printJson,
|
package/src/util/schema.js
CHANGED
|
@@ -17,6 +17,14 @@ const ISSUE = cfgcode.ISSUE;
|
|
|
17
17
|
|
|
18
18
|
// [declare]
|
|
19
19
|
|
|
20
|
+
// how a value's kind is named, as TOML writes it.
|
|
21
|
+
const KINDS = {
|
|
22
|
+
array: "a list",
|
|
23
|
+
boolean: "true or false",
|
|
24
|
+
number: "a number",
|
|
25
|
+
object: "a table",
|
|
26
|
+
string: "a string",
|
|
27
|
+
};
|
|
20
28
|
const NUMBERS = new Set(["bigint", "int", "number"]);
|
|
21
29
|
|
|
22
30
|
// [function]
|
|
@@ -65,11 +73,54 @@ const issueCodeOf = function (issue) {
|
|
|
65
73
|
|
|
66
74
|
// [function]
|
|
67
75
|
|
|
76
|
+
// a value's kind, as TOML writes it: "a string", "a list", "a table".
|
|
77
|
+
const kindOf = function (type) {
|
|
78
|
+
return KINDS[type] ?? `a ${type}`;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// [function]
|
|
82
|
+
|
|
83
|
+
// what zod reports itself (a value of the wrong type, or not one of the
|
|
84
|
+
// options), in arc's words, as `{ message, details }`: "Must be a string, not
|
|
85
|
+
// a number." Null for a message of our own.
|
|
86
|
+
const zodMessage = function (issue) {
|
|
87
|
+
if (issue.code === "invalid_value" && issue.values) {
|
|
88
|
+
return { details: [issue.values.join(", ")], message: "Must be one of:" };
|
|
89
|
+
}
|
|
90
|
+
const given = Array.isArray(issue.input) ? "array" : typeof issue.input;
|
|
91
|
+
if (issue.code === "invalid_type" && typeof issue.input !== "undefined") {
|
|
92
|
+
return {
|
|
93
|
+
details: [],
|
|
94
|
+
message: `Must be ${kindOf(issue.expected)}, not ${kindOf(given)}.`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (
|
|
98
|
+
issue.code === "invalid_union" &&
|
|
99
|
+
issue.errors.every((branch) =>
|
|
100
|
+
branch.every((each) => each.code === "invalid_type"),
|
|
101
|
+
)
|
|
102
|
+
) {
|
|
103
|
+
const expected = [
|
|
104
|
+
...new Set(issue.errors.map((branch) => kindOf(branch[0].expected))),
|
|
105
|
+
];
|
|
106
|
+
return {
|
|
107
|
+
details: [],
|
|
108
|
+
message: `Must be ${expected.join(" or ")}, not ${kindOf(given)}.`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// [function]
|
|
115
|
+
|
|
68
116
|
// a zod issue as arc validate reports it: the field's path, the rule's code,
|
|
69
117
|
// the message's first line and its details, and the link to the field's
|
|
70
118
|
// rules, or null for a field the docs leave out.
|
|
71
119
|
const toIssue = function (name, issue) {
|
|
72
|
-
const
|
|
120
|
+
const parsed = schemaMessage.parse(issue.message);
|
|
121
|
+
const { details, message } =
|
|
122
|
+
(/^Invalid (input|option)\b/u.test(parsed.message) && zodMessage(issue)) ||
|
|
123
|
+
parsed;
|
|
73
124
|
return {
|
|
74
125
|
code: issueCodeOf(issue),
|
|
75
126
|
details,
|
|
@@ -133,5 +184,6 @@ module.exports = {
|
|
|
133
184
|
dereference,
|
|
134
185
|
issueCodeOf,
|
|
135
186
|
print,
|
|
187
|
+
toIssue,
|
|
136
188
|
validator,
|
|
137
189
|
};
|