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/api.js
CHANGED
|
@@ -11,6 +11,18 @@ const VERSION = "v1";
|
|
|
11
11
|
|
|
12
12
|
// [function]
|
|
13
13
|
|
|
14
|
+
// an API path with each value encoded as one segment, so a handle or version
|
|
15
|
+
// can't add a segment or a query: pathOf`/games/${id}`.
|
|
16
|
+
const pathOf = function (strings, ...values) {
|
|
17
|
+
return strings.reduce(
|
|
18
|
+
(out, each, i) =>
|
|
19
|
+
out + each + (i < values.length ? encodeURIComponent(values[i]) : ""),
|
|
20
|
+
"",
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// [function]
|
|
25
|
+
|
|
14
26
|
// the full URL of an API path, with `params` as its query. Undefined and null
|
|
15
27
|
// params are left out.
|
|
16
28
|
const endpoint = function (path, params) {
|
|
@@ -45,7 +57,7 @@ const postFlow = function (form, params, headers) {
|
|
|
45
57
|
// [function]
|
|
46
58
|
|
|
47
59
|
const flow = function (id, params, headers) {
|
|
48
|
-
return request.get(endpoint(`/flows/${id}`, params), headers);
|
|
60
|
+
return request.get(endpoint(pathOf`/flows/${id}`, params), headers);
|
|
49
61
|
};
|
|
50
62
|
|
|
51
63
|
// [function]
|
|
@@ -57,20 +69,23 @@ const postUpload = function (form, params, headers) {
|
|
|
57
69
|
// [function]
|
|
58
70
|
|
|
59
71
|
const discoverGame = function (id, params, headers) {
|
|
60
|
-
return request.get(endpoint(`/discover/games/${id}`, params), headers);
|
|
72
|
+
return request.get(endpoint(pathOf`/discover/games/${id}`, params), headers);
|
|
61
73
|
};
|
|
62
74
|
|
|
63
75
|
// [function]
|
|
64
76
|
|
|
65
77
|
const discoverGameBuilds = function (id, params, headers) {
|
|
66
|
-
return request.get(
|
|
78
|
+
return request.get(
|
|
79
|
+
endpoint(pathOf`/discover/games/${id}/builds`, params),
|
|
80
|
+
headers,
|
|
81
|
+
);
|
|
67
82
|
};
|
|
68
83
|
|
|
69
84
|
// [function]
|
|
70
85
|
|
|
71
86
|
const discoverGameBuild = function (id, version, params, headers) {
|
|
72
87
|
return request.get(
|
|
73
|
-
endpoint(`/discover/games/${id}/builds/${version}`, params),
|
|
88
|
+
endpoint(pathOf`/discover/games/${id}/builds/${version}`, params),
|
|
74
89
|
headers,
|
|
75
90
|
);
|
|
76
91
|
};
|
|
@@ -80,7 +95,7 @@ const discoverGameBuild = function (id, version, params, headers) {
|
|
|
80
95
|
// a game's releases, which anyone can read: what each says about itself.
|
|
81
96
|
const discoverGameReleases = function (id, params, headers) {
|
|
82
97
|
return request.get(
|
|
83
|
-
endpoint(`/discover/games/${id}/releases`, params),
|
|
98
|
+
endpoint(pathOf`/discover/games/${id}/releases`, params),
|
|
84
99
|
headers,
|
|
85
100
|
);
|
|
86
101
|
};
|
|
@@ -90,10 +105,7 @@ const discoverGameReleases = function (id, params, headers) {
|
|
|
90
105
|
// the game's connected repository, if it's `owner/name`; otherwise 404.
|
|
91
106
|
const discoverGameRepo = function (id, owner, name, params, headers) {
|
|
92
107
|
return request.get(
|
|
93
|
-
endpoint(
|
|
94
|
-
`/discover/games/${id}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`,
|
|
95
|
-
params,
|
|
96
|
-
),
|
|
108
|
+
endpoint(pathOf`/discover/games/${id}/repos/${owner}/${name}`, params),
|
|
97
109
|
headers,
|
|
98
110
|
);
|
|
99
111
|
};
|
|
@@ -102,7 +114,18 @@ const discoverGameRepo = function (id, owner, name, params, headers) {
|
|
|
102
114
|
|
|
103
115
|
const gameBuild = function (id, version, params, headers) {
|
|
104
116
|
return request.get(
|
|
105
|
-
endpoint(`/games/${id}/builds/${version}`, params),
|
|
117
|
+
endpoint(pathOf`/games/${id}/builds/${version}`, params),
|
|
118
|
+
headers,
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// [function]
|
|
123
|
+
|
|
124
|
+
// whether the caller's game could take a handle on a deploy to `channel`:
|
|
125
|
+
// its status is available, taken, limit, or lapsed.
|
|
126
|
+
const gameHandle = function (id, handle, params, headers) {
|
|
127
|
+
return request.get(
|
|
128
|
+
endpoint(pathOf`/games/${id}/handles/${handle}`, params),
|
|
106
129
|
headers,
|
|
107
130
|
);
|
|
108
131
|
};
|
|
@@ -110,13 +133,16 @@ const gameBuild = function (id, version, params, headers) {
|
|
|
110
133
|
// [function]
|
|
111
134
|
|
|
112
135
|
const release = function (id, params, headers) {
|
|
113
|
-
return request.get(endpoint(`/releases/${id}`, params), headers);
|
|
136
|
+
return request.get(endpoint(pathOf`/releases/${id}`, params), headers);
|
|
114
137
|
};
|
|
115
138
|
|
|
116
139
|
// [function]
|
|
117
140
|
|
|
118
141
|
const accountReleases = function (id, params, headers) {
|
|
119
|
-
return request.get(
|
|
142
|
+
return request.get(
|
|
143
|
+
endpoint(pathOf`/accounts/${id}/releases`, params),
|
|
144
|
+
headers,
|
|
145
|
+
);
|
|
120
146
|
};
|
|
121
147
|
|
|
122
148
|
// [export]
|
|
@@ -131,6 +157,7 @@ module.exports = {
|
|
|
131
157
|
discoverGameRepo,
|
|
132
158
|
flow,
|
|
133
159
|
gameBuild,
|
|
160
|
+
gameHandle,
|
|
134
161
|
postAuthRefresh,
|
|
135
162
|
postFlow,
|
|
136
163
|
postUpload,
|
package/src/config/code.js
CHANGED
|
@@ -13,6 +13,7 @@ const CLI = {
|
|
|
13
13
|
ARGUMENT_INVALID: "argument_invalid",
|
|
14
14
|
BUILD_FAILED: "build_failed",
|
|
15
15
|
DEPLOY_DIR_MISSING: "deploy_dir_missing",
|
|
16
|
+
DEPLOY_RATE_LIMITED: "deploy_rate_limited",
|
|
16
17
|
GAME_HANDLE_TAKEN: "game_handle_taken",
|
|
17
18
|
GAME_ID_MISSING: "game_id_missing",
|
|
18
19
|
GAME_NOT_DEPLOYED: "game_not_deployed",
|
|
@@ -43,7 +44,6 @@ const CLI = {
|
|
|
43
44
|
TEMPLATE_MISSING: "template_missing",
|
|
44
45
|
TEMPLATE_UNAVAILABLE: "template_unavailable",
|
|
45
46
|
UPLOAD_FAILED: "upload_failed",
|
|
46
|
-
UPLOAD_RATE_LIMITED: "upload_rate_limited",
|
|
47
47
|
VALIDATION_FAILED: "validation_failed",
|
|
48
48
|
WAIT_TIMED_OUT: "wait_timed_out",
|
|
49
49
|
};
|
|
@@ -104,6 +104,8 @@ const ISSUE = {
|
|
|
104
104
|
const WARNING = {
|
|
105
105
|
DEPLOY_DIR_NOT_BUILT: "deploy_dir_not_built",
|
|
106
106
|
FIELD_UNKNOWN: "field_unknown",
|
|
107
|
+
GAME_HANDLE_LAPSED: "game_handle_lapsed",
|
|
108
|
+
GAME_HANDLE_LIMIT_REACHED: "game_handle_limit_reached",
|
|
107
109
|
VERSION_UNCHECKED: "version_unchecked",
|
|
108
110
|
};
|
|
109
111
|
// every error code, for checking one exists.
|
package/src/parser/readme.js
CHANGED
package/src/phrase.js
CHANGED
|
@@ -142,19 +142,19 @@ const didYouMean = function (near) {
|
|
|
142
142
|
// [function]
|
|
143
143
|
|
|
144
144
|
const docAttrInvalid = function (tag, attr, value) {
|
|
145
|
-
return `Value '${value}'
|
|
145
|
+
return `Value '${value}' isn't allowed for ${attr} on <${tag}>.`;
|
|
146
146
|
};
|
|
147
147
|
|
|
148
148
|
// [function]
|
|
149
149
|
|
|
150
150
|
const docAttrUnallowed = function (tag, attr) {
|
|
151
|
-
return `Attribute
|
|
151
|
+
return `Attribute ${attr} isn't allowed on <${tag}>.`;
|
|
152
152
|
};
|
|
153
153
|
|
|
154
154
|
// [function]
|
|
155
155
|
|
|
156
156
|
const docCommentUnallowed = function () {
|
|
157
|
-
return "HTML comments
|
|
157
|
+
return "HTML comments aren't allowed.";
|
|
158
158
|
};
|
|
159
159
|
|
|
160
160
|
// [function]
|
|
@@ -186,7 +186,7 @@ const docMediaType = function (src) {
|
|
|
186
186
|
// [function]
|
|
187
187
|
|
|
188
188
|
const docTagUnallowed = function (tag) {
|
|
189
|
-
return `Tag
|
|
189
|
+
return `Tag <${tag}> isn't allowed.`;
|
|
190
190
|
};
|
|
191
191
|
|
|
192
192
|
// [function]
|
|
@@ -207,6 +207,18 @@ const gameHandleTaken = function (handle) {
|
|
|
207
207
|
|
|
208
208
|
// [function]
|
|
209
209
|
|
|
210
|
+
const gameHandleLapsed = function (handle) {
|
|
211
|
+
return `Handle ${handle} lapsed, so deploying without it.\nA production release takes it back.`;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// [function]
|
|
215
|
+
|
|
216
|
+
const gameHandleLimit = function (handle) {
|
|
217
|
+
return `Handle ${handle} not applied, so deploying without it.\nYour unreleased games already hold 5 handles.`;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// [function]
|
|
221
|
+
|
|
210
222
|
const gameNotDeployed = function (game) {
|
|
211
223
|
return blocks(`${game} isn't on ${TITLE} yet.`, [
|
|
212
224
|
`Deploy it once with ${cmdDeploy()}.`,
|
|
@@ -273,7 +285,7 @@ const packed = function () {
|
|
|
273
285
|
// [function]
|
|
274
286
|
|
|
275
287
|
const portInvalid = function () {
|
|
276
|
-
return "
|
|
288
|
+
return "`--port` must be a whole number from 1 to 65535.";
|
|
277
289
|
};
|
|
278
290
|
|
|
279
291
|
// [function]
|
|
@@ -299,13 +311,13 @@ const remoteName = function (name) {
|
|
|
299
311
|
|
|
300
312
|
// arc serve's copy of one of Arcadible's files, kept from `fetchedAt`.
|
|
301
313
|
const remoteKept = function (name, fetchedAt) {
|
|
302
|
-
return
|
|
314
|
+
return `Unable to reach ${TITLE}.\nServing ${remoteName(name)} saved on ${fetchedAt.slice(0, 10)}.`;
|
|
303
315
|
};
|
|
304
316
|
|
|
305
317
|
// [function]
|
|
306
318
|
|
|
307
319
|
const remoteUnreachable = function (name) {
|
|
308
|
-
return
|
|
320
|
+
return `Unable to reach ${TITLE}, and ${remoteName(name)} isn't saved.\nThe game runs without it until ${TITLE} is back.`;
|
|
309
321
|
};
|
|
310
322
|
|
|
311
323
|
// [function]
|
|
@@ -322,6 +334,20 @@ const serveAlone = function () {
|
|
|
322
334
|
|
|
323
335
|
// [function]
|
|
324
336
|
|
|
337
|
+
// the label before a play link in a result.
|
|
338
|
+
const playLabel = function () {
|
|
339
|
+
return "Play:";
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// [function]
|
|
343
|
+
|
|
344
|
+
// the label before a store page's link in a result.
|
|
345
|
+
const storeLabel = function () {
|
|
346
|
+
return "Store:";
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// [function]
|
|
350
|
+
|
|
325
351
|
const serveNext = function (dir) {
|
|
326
352
|
return `Reloads when ${dir}/ changes. Press Ctrl+C to stop.`;
|
|
327
353
|
};
|
|
@@ -347,7 +373,7 @@ const serveNextUrl = function () {
|
|
|
347
373
|
// [function]
|
|
348
374
|
|
|
349
375
|
const urlInvalid = function () {
|
|
350
|
-
return "
|
|
376
|
+
return "`--url` must start with http:// or https://.";
|
|
351
377
|
};
|
|
352
378
|
|
|
353
379
|
// [function]
|
|
@@ -356,8 +382,12 @@ const urlInvalid = function () {
|
|
|
356
382
|
// says how to add them.
|
|
357
383
|
const urlNotFrameable = function (url, link) {
|
|
358
384
|
return blocks(
|
|
359
|
-
|
|
360
|
-
|
|
385
|
+
`The play page can't frame ${url}.`,
|
|
386
|
+
[
|
|
387
|
+
"Its server doesn't send the headers the play page needs:",
|
|
388
|
+
"Cross-Origin-Embedder-Policy: require-corp",
|
|
389
|
+
"Cross-Origin-Resource-Policy: cross-origin",
|
|
390
|
+
],
|
|
361
391
|
["Add them to your server, as the starters' vite.config.js does:", link],
|
|
362
392
|
);
|
|
363
393
|
};
|
|
@@ -365,7 +395,7 @@ const urlNotFrameable = function (url, link) {
|
|
|
365
395
|
// [function]
|
|
366
396
|
|
|
367
397
|
const urlUnreachable = function (url) {
|
|
368
|
-
return
|
|
398
|
+
return `Nothing answers at ${url}.\nStart your server, then reload the play page.`;
|
|
369
399
|
};
|
|
370
400
|
|
|
371
401
|
// [function]
|
|
@@ -384,10 +414,11 @@ const releaseFailedHeading = function () {
|
|
|
384
414
|
|
|
385
415
|
// origin isn't the game's connected repository: none is, or another is.
|
|
386
416
|
const repoNotConnected = function (game, repo, url) {
|
|
387
|
-
return blocks(
|
|
388
|
-
|
|
389
|
-
url,
|
|
390
|
-
|
|
417
|
+
return blocks(
|
|
418
|
+
`${repo} isn't ${game}'s repository on ${TITLE}.`,
|
|
419
|
+
[`Connect it on the game's Repository tab in ${TITLE} Studio:`, url],
|
|
420
|
+
"If it was renamed on GitHub, connect it again.",
|
|
421
|
+
);
|
|
391
422
|
};
|
|
392
423
|
|
|
393
424
|
// [function]
|
|
@@ -399,10 +430,10 @@ const gameNotFound = function (idOrHandle) {
|
|
|
399
430
|
// [function]
|
|
400
431
|
|
|
401
432
|
const gameUnavailable = function (id) {
|
|
402
|
-
return blocks(
|
|
403
|
-
|
|
433
|
+
return blocks(
|
|
434
|
+
`Game unavailable: ${id}\nIt was deleted, or belongs to another account.`,
|
|
404
435
|
"Give game.id a new UUID to deploy it as a new game.",
|
|
405
|
-
|
|
436
|
+
);
|
|
406
437
|
};
|
|
407
438
|
|
|
408
439
|
// [function]
|
|
@@ -418,7 +449,7 @@ const gitUncommitted = function () {
|
|
|
418
449
|
|
|
419
450
|
const gitRemoteMissing = function () {
|
|
420
451
|
return blocks(
|
|
421
|
-
"No Git remote
|
|
452
|
+
"No Git remote origin.",
|
|
422
453
|
"Add the game's GitHub repository as origin.",
|
|
423
454
|
);
|
|
424
455
|
};
|
|
@@ -427,8 +458,8 @@ const gitRemoteMissing = function () {
|
|
|
427
458
|
|
|
428
459
|
const gitRemoteUnreachable = function () {
|
|
429
460
|
return blocks(
|
|
430
|
-
"Unable to reach Git remote
|
|
431
|
-
"Check your connection, and that you can access it.",
|
|
461
|
+
"Unable to reach Git remote origin.",
|
|
462
|
+
"Check your internet connection, and that you can access it.",
|
|
432
463
|
);
|
|
433
464
|
};
|
|
434
465
|
|
|
@@ -438,8 +469,14 @@ const manifestMissing = function (file, dir, found) {
|
|
|
438
469
|
return blocks(
|
|
439
470
|
dir === "." ? `No ${file} in this directory.` : `No ${file} in ${dir}.`,
|
|
440
471
|
found
|
|
441
|
-
?
|
|
442
|
-
|
|
472
|
+
? [
|
|
473
|
+
`Found a project in ${found}.`,
|
|
474
|
+
`Run \`${TOOL}\` there, or pass \`-C ${found}\`.`,
|
|
475
|
+
]
|
|
476
|
+
: [
|
|
477
|
+
`Run \`${TOOL}\` in a project's directory, or pass \`-C <dir>\`.`,
|
|
478
|
+
`To start a project, run ${cmdInit()}.`,
|
|
479
|
+
],
|
|
443
480
|
);
|
|
444
481
|
};
|
|
445
482
|
|
|
@@ -447,7 +484,7 @@ const manifestMissing = function (file, dir, found) {
|
|
|
447
484
|
|
|
448
485
|
const projectNotRepoRoot = function (prefix) {
|
|
449
486
|
return blocks(
|
|
450
|
-
|
|
487
|
+
`Project is in ${prefix}, not the repository's root.\n${cmdDeployGit()} releases only a project at the root.`,
|
|
451
488
|
`Deploy it with ${cmdDeploy()}, or give it a repository of its own.`,
|
|
452
489
|
);
|
|
453
490
|
};
|
|
@@ -475,7 +512,7 @@ const gitTagCreateFailed = function (version) {
|
|
|
475
512
|
const gitTagPushFailed = function (version) {
|
|
476
513
|
return blocks(
|
|
477
514
|
`Unable to push Git tag for v${version}.`,
|
|
478
|
-
"Check that you can push to
|
|
515
|
+
"Check that you can push to origin.",
|
|
479
516
|
);
|
|
480
517
|
};
|
|
481
518
|
|
|
@@ -552,7 +589,7 @@ const imageWidthMin = function (width) {
|
|
|
552
589
|
// [function]
|
|
553
590
|
|
|
554
591
|
const timeoutInvalid = function () {
|
|
555
|
-
return "
|
|
592
|
+
return "`--timeout` must be a number of seconds above 0.";
|
|
556
593
|
};
|
|
557
594
|
|
|
558
595
|
// [function]
|
|
@@ -561,8 +598,8 @@ const timeoutInvalid = function () {
|
|
|
561
598
|
// parsed the project again.
|
|
562
599
|
const issuesAfterBuild = function (count) {
|
|
563
600
|
return blocks(
|
|
564
|
-
`${count} ${count === 1 ? "issue" : "issues"} found after the build.`,
|
|
565
|
-
`
|
|
601
|
+
`${count} ${count === 1 ? "issue" : "issues"} found after the build.\nThe build writes files the manifest reads.`,
|
|
602
|
+
`Run ${cmdValidate()} for details.`,
|
|
566
603
|
);
|
|
567
604
|
};
|
|
568
605
|
|
|
@@ -578,13 +615,13 @@ const issuesFound = function (count) {
|
|
|
578
615
|
// [function]
|
|
579
616
|
|
|
580
617
|
const loginCodeExpired = function () {
|
|
581
|
-
return "Login code expired.";
|
|
618
|
+
return blocks("Login code expired.", `Run ${cmdLogin()} again.`);
|
|
582
619
|
};
|
|
583
620
|
|
|
584
621
|
// [function]
|
|
585
622
|
|
|
586
623
|
const loginFailed = function () {
|
|
587
|
-
return "Login request failed.";
|
|
624
|
+
return blocks("Login request failed.", `Run ${cmdLogin()} again.`);
|
|
588
625
|
};
|
|
589
626
|
|
|
590
627
|
// [function]
|
|
@@ -599,10 +636,10 @@ const gameIdMissing = function () {
|
|
|
599
636
|
// [function]
|
|
600
637
|
|
|
601
638
|
const lockfileMissing = function () {
|
|
602
|
-
return blocks(
|
|
603
|
-
"
|
|
604
|
-
"
|
|
605
|
-
|
|
639
|
+
return blocks(
|
|
640
|
+
"No lockfile found.",
|
|
641
|
+
"Install your dependencies to create one, and commit it.",
|
|
642
|
+
);
|
|
606
643
|
};
|
|
607
644
|
|
|
608
645
|
// [function]
|
|
@@ -676,7 +713,7 @@ const packagePathReserved = function (folder) {
|
|
|
676
713
|
const packageTooLarge = function (size) {
|
|
677
714
|
return blocks(
|
|
678
715
|
`Package is larger than ${size} MB.`,
|
|
679
|
-
"
|
|
716
|
+
".arcadible/ doesn't count toward it.",
|
|
680
717
|
);
|
|
681
718
|
};
|
|
682
719
|
|
|
@@ -700,7 +737,7 @@ const packageUncompressedTooLarge = function (size) {
|
|
|
700
737
|
// open it.
|
|
701
738
|
const releaseFailed = function ({ message }, studio) {
|
|
702
739
|
return blocks(
|
|
703
|
-
(message ?? "").split(/(?<=\.)\s+/u).join("\n"),
|
|
740
|
+
(message ?? "No reason given.").split(/(?<=\.)\s+/u).join("\n"),
|
|
704
741
|
...(studio ? [[`${TITLE} Studio:`, studio]] : []),
|
|
705
742
|
);
|
|
706
743
|
};
|
|
@@ -730,10 +767,10 @@ const releaseTimedOut = function (
|
|
|
730
767
|
]);
|
|
731
768
|
}
|
|
732
769
|
if (found) {
|
|
733
|
-
return blocks(
|
|
734
|
-
|
|
735
|
-
`
|
|
736
|
-
);
|
|
770
|
+
return blocks(head, [
|
|
771
|
+
"It may still finish.",
|
|
772
|
+
`The ${TITLE} check on the tagged commit says how it went.`,
|
|
773
|
+
]);
|
|
737
774
|
}
|
|
738
775
|
return blocks(
|
|
739
776
|
head,
|
|
@@ -741,7 +778,7 @@ const releaseTimedOut = function (
|
|
|
741
778
|
"GitHub Actions hasn't released it yet, or its workflow failed:",
|
|
742
779
|
actions ?? "See the repository's Actions tab.",
|
|
743
780
|
],
|
|
744
|
-
`If the workflow passed, the ${TITLE} check on the tagged commit
|
|
781
|
+
`If the workflow passed, see the ${TITLE} check on the tagged commit.`,
|
|
745
782
|
);
|
|
746
783
|
};
|
|
747
784
|
|
|
@@ -750,7 +787,7 @@ const releaseTimedOut = function (
|
|
|
750
787
|
// the spinner while `--wait` waits: on GitHub Actions until the release
|
|
751
788
|
// exists, then on Arcadible.
|
|
752
789
|
const releaseWaiting = function (building) {
|
|
753
|
-
return building ? "Waiting for GitHub Actions
|
|
790
|
+
return building ? "Waiting for GitHub Actions… %s" : "Publishing… %s";
|
|
754
791
|
};
|
|
755
792
|
|
|
756
793
|
// [function]
|
|
@@ -875,9 +912,9 @@ const uploadFailed = function (status) {
|
|
|
875
912
|
|
|
876
913
|
// [function]
|
|
877
914
|
|
|
878
|
-
const
|
|
915
|
+
const deployRateLimited = function (version) {
|
|
879
916
|
return blocks(
|
|
880
|
-
`v${version} was
|
|
917
|
+
`v${version} was deployed in the last 5 minutes.`,
|
|
881
918
|
"Wait, then deploy again.",
|
|
882
919
|
);
|
|
883
920
|
};
|
|
@@ -1010,6 +1047,7 @@ module.exports = {
|
|
|
1010
1047
|
cmdInit,
|
|
1011
1048
|
cmdInspect,
|
|
1012
1049
|
deployDirMissing,
|
|
1050
|
+
deployRateLimited,
|
|
1013
1051
|
didYouMean,
|
|
1014
1052
|
docAttrInvalid,
|
|
1015
1053
|
docAttrUnallowed,
|
|
@@ -1020,6 +1058,8 @@ module.exports = {
|
|
|
1020
1058
|
docMediaType,
|
|
1021
1059
|
docTagUnallowed,
|
|
1022
1060
|
errorCode,
|
|
1061
|
+
gameHandleLapsed,
|
|
1062
|
+
gameHandleLimit,
|
|
1023
1063
|
gameHandleTaken,
|
|
1024
1064
|
gameIdMissing,
|
|
1025
1065
|
gameNotDeployed,
|
|
@@ -1069,6 +1109,7 @@ module.exports = {
|
|
|
1069
1109
|
packageTooManyFiles,
|
|
1070
1110
|
packageUncompressedTooLarge,
|
|
1071
1111
|
packed,
|
|
1112
|
+
playLabel,
|
|
1072
1113
|
portInUse,
|
|
1073
1114
|
portInvalid,
|
|
1074
1115
|
pressEnterToOpen,
|
|
@@ -1096,6 +1137,7 @@ module.exports = {
|
|
|
1096
1137
|
starterPhaser,
|
|
1097
1138
|
starterPixiJs,
|
|
1098
1139
|
starterThreeJs,
|
|
1140
|
+
storeLabel,
|
|
1099
1141
|
tagPushed,
|
|
1100
1142
|
templateMissing,
|
|
1101
1143
|
templateUnavailable,
|
|
@@ -1107,7 +1149,6 @@ module.exports = {
|
|
|
1107
1149
|
unknownField,
|
|
1108
1150
|
unknownTable,
|
|
1109
1151
|
uploadFailed,
|
|
1110
|
-
uploadRateLimited,
|
|
1111
1152
|
urlInvalid,
|
|
1112
1153
|
urlNotFrameable,
|
|
1113
1154
|
urlUnreachable,
|
package/src/schema/game.js
CHANGED
|
@@ -123,16 +123,20 @@ const GALLERY_DIMENSIONS = {
|
|
|
123
123
|
// leaving a field out is how to unset it, so an empty one is always a mistake.
|
|
124
124
|
const atLeast = function (field, min, unit) {
|
|
125
125
|
return min === 1
|
|
126
|
-
? message(field, ["Must not be empty. Leave the field out instead."])
|
|
127
|
-
: message(field, [
|
|
126
|
+
? message(field, ["Must not be empty.", "Leave the field out instead."])
|
|
127
|
+
: message(field, [
|
|
128
|
+
unit === "character"
|
|
129
|
+
? `Must be at least ${min} characters.`
|
|
130
|
+
: `Must have at least ${min} ${unit}s.`,
|
|
131
|
+
]);
|
|
128
132
|
};
|
|
129
133
|
|
|
130
134
|
// [function]
|
|
131
135
|
|
|
132
|
-
// a required string's error: "Must be
|
|
136
|
+
// a required string's error: "Must be set." and `lines` when it's missing,
|
|
133
137
|
// and zod's own type message (null) when it's there but isn't a string.
|
|
134
138
|
const required = function (field, lines) {
|
|
135
|
-
const missing = message(field, ["Must be
|
|
139
|
+
const missing = message(field, ["Must be set.", ...lines]).message;
|
|
136
140
|
return {
|
|
137
141
|
error(issue) {
|
|
138
142
|
return typeof issue.input === "undefined" ? missing : null;
|
|
@@ -144,14 +148,14 @@ const required = function (field, lines) {
|
|
|
144
148
|
|
|
145
149
|
// a list of distinct values. Without a max, its length is up to the values.
|
|
146
150
|
const zSet = function (field, schema, { max, min }) {
|
|
147
|
-
const list = z.array(schema).min(min, atLeast(field, min, "
|
|
151
|
+
const list = z.array(schema).min(min, atLeast(field, min, "item"));
|
|
148
152
|
return (
|
|
149
153
|
max
|
|
150
|
-
? list.max(max, message(field, [`Must
|
|
154
|
+
? list.max(max, message(field, [`Must have at most ${max} items.`]))
|
|
151
155
|
: list
|
|
152
156
|
).refine(
|
|
153
157
|
(items) => new Set(items).size === items.length,
|
|
154
|
-
message(field, ["Must not
|
|
158
|
+
message(field, ["Must not repeat an item."], ISSUE.DUPLICATE),
|
|
155
159
|
);
|
|
156
160
|
};
|
|
157
161
|
|
|
@@ -161,12 +165,12 @@ const zSetBasefile = function (field, schema, { max, min }) {
|
|
|
161
165
|
return z
|
|
162
166
|
.array(schema)
|
|
163
167
|
.min(min, atLeast(field, min, "file"))
|
|
164
|
-
.max(max, message(field, [`Must
|
|
168
|
+
.max(max, message(field, [`Must have at most ${max} files.`]))
|
|
165
169
|
.refine(
|
|
166
170
|
(items) => new Set(items.map(basefile)).size === items.length,
|
|
167
171
|
message(
|
|
168
172
|
field,
|
|
169
|
-
["Must not
|
|
173
|
+
["Must not have two files of one name, whatever their extensions."],
|
|
170
174
|
ISSUE.DUPLICATE,
|
|
171
175
|
),
|
|
172
176
|
);
|
|
@@ -183,7 +187,7 @@ const zString = function (field, char, { max, min }) {
|
|
|
183
187
|
.min(min, { ...atLeast(field, min, "character"), abort: min === 1 })
|
|
184
188
|
.refine(
|
|
185
189
|
(str) => [...str].length <= max,
|
|
186
|
-
message(field, [`Must
|
|
190
|
+
message(field, [`Must be at most ${max} characters.`], ISSUE.TOO_LONG),
|
|
187
191
|
)
|
|
188
192
|
.superRefine((str, ctx) => {
|
|
189
193
|
const invalid = invalidChars(str, char);
|
|
@@ -458,7 +462,7 @@ const zHandle = function () {
|
|
|
458
462
|
const field = "handle";
|
|
459
463
|
return z.optional(
|
|
460
464
|
zString(field, /[a-z0-9-]/u, { max: 24, min: 1 })
|
|
461
|
-
.min(3, atLeast(field, 3, "
|
|
465
|
+
.min(3, atLeast(field, 3, "character"))
|
|
462
466
|
.refine(
|
|
463
467
|
(str) => !str.startsWith("-") && !str.endsWith("-"),
|
|
464
468
|
message(
|
|
@@ -487,7 +491,7 @@ const zId = function () {
|
|
|
487
491
|
required(field, [`Run ${phrase.cmdInit()} to generate a new game ID.`]),
|
|
488
492
|
)
|
|
489
493
|
.min(1, { ...atLeast(field, 1), abort: true })
|
|
490
|
-
.uuid(message(field, ["Must be a
|
|
494
|
+
.uuid(message(field, ["Must be a UUID."]))
|
|
491
495
|
.refine(
|
|
492
496
|
(value) => value === value.toLowerCase(),
|
|
493
497
|
message(field, ["Must be lowercase."], ISSUE.UUID_INVALID),
|
|
@@ -514,8 +518,8 @@ const zPrice = function () {
|
|
|
514
518
|
return z.optional(
|
|
515
519
|
z
|
|
516
520
|
.int()
|
|
517
|
-
.min(0, message(field, ["Must
|
|
518
|
-
.max(25, message(field, ["Must
|
|
521
|
+
.min(0, message(field, ["Must be 0 or more."]))
|
|
522
|
+
.max(25, message(field, ["Must be 25 or less."])),
|
|
519
523
|
);
|
|
520
524
|
};
|
|
521
525
|
|
|
@@ -547,7 +551,7 @@ const zTrailer = function () {
|
|
|
547
551
|
return z
|
|
548
552
|
.string()
|
|
549
553
|
.min(1, { ...atLeast(field, 1), abort: true })
|
|
550
|
-
.max(255, message(field, ["Must
|
|
554
|
+
.max(255, message(field, ["Must be at most 255 characters."]))
|
|
551
555
|
.refine(
|
|
552
556
|
(url) =>
|
|
553
557
|
zVimeo().safeParse(url).success || zYouTube().safeParse(url).success,
|
|
@@ -561,18 +565,26 @@ const zTrailer = function () {
|
|
|
561
565
|
const zVersion = function () {
|
|
562
566
|
const field = "version";
|
|
563
567
|
return z
|
|
564
|
-
.string(
|
|
565
|
-
required(field, ["A version is required unless one can be derived."]),
|
|
566
|
-
)
|
|
568
|
+
.string(required(field, ["Set it here, or in package.json."]))
|
|
567
569
|
.min(1, { ...atLeast(field, 1), abort: true })
|
|
568
570
|
.refine((value) => validSemver(value) !== null, {
|
|
569
|
-
...message(
|
|
571
|
+
...message(
|
|
572
|
+
field,
|
|
573
|
+
["Must be a version, such as 1.2.0."],
|
|
574
|
+
ISSUE.VERSION_INVALID,
|
|
575
|
+
),
|
|
570
576
|
abort: true,
|
|
571
577
|
})
|
|
572
578
|
.refine(
|
|
573
579
|
// lowercase too, since the database refuses an uppercase prerelease.
|
|
574
580
|
(value) => cleanSemver(value) === value && value === value.toLowerCase(),
|
|
575
|
-
message(
|
|
581
|
+
message(
|
|
582
|
+
field,
|
|
583
|
+
[
|
|
584
|
+
"Must be written as 1.2.0 or 1.2.0-beta.1: lowercase, with no v, spaces, or build metadata.",
|
|
585
|
+
],
|
|
586
|
+
ISSUE.VERSION_INVALID,
|
|
587
|
+
),
|
|
576
588
|
);
|
|
577
589
|
};
|
|
578
590
|
|
package/src/schema/readme.js
CHANGED
|
@@ -29,7 +29,8 @@ const main = function (value, { file }) {
|
|
|
29
29
|
...message(
|
|
30
30
|
"description",
|
|
31
31
|
[
|
|
32
|
-
|
|
32
|
+
"Needs two --- rules around the description.",
|
|
33
|
+
`${file} has content after its title, tagline, and bio.`,
|
|
33
34
|
],
|
|
34
35
|
cfgcode.ISSUE.DESCRIPTION_RULES_MISSING,
|
|
35
36
|
),
|