arcadible 1.0.2 → 1.0.5

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.
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const cfgcode = require("../../config/code");
6
+ const error = require("../../util/error");
7
+ const phrase = require("../../phrase");
8
+ const project = require("../../parser/project");
9
+ const validateTool = require("./tool");
10
+
11
+ // [use]
12
+
13
+ const ArcError = error.ArcError;
14
+
15
+ // [function]
16
+
17
+ // parses and validates the project at `root` for a command that goes on from
18
+ // it (arc build, arc pack, arc deploy): resolves with the parsed project, or
19
+ // rejects as validation_failed with its issues in `data`. `onWarnings` gets
20
+ // the warnings either way, for --json to list beside the result or the error.
21
+ const checked = async function (root, onWarnings) {
22
+ const parsed = await project(root);
23
+ const { issues, warnings } = await validateTool({ project: parsed, root });
24
+ onWarnings(warnings);
25
+ if (issues.length) {
26
+ throw new ArcError(
27
+ cfgcode.VALIDATION_FAILED,
28
+ phrase.issuesFound(issues.length),
29
+ { data: { issues } },
30
+ );
31
+ }
32
+ return parsed;
33
+ };
34
+
35
+ // [export]
36
+
37
+ module.exports = checked;
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(endpoint(`/discover/games/${id}/builds`, params), headers);
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,7 @@ 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),
106
118
  headers,
107
119
  );
108
120
  };
@@ -113,7 +125,7 @@ const gameBuild = function (id, version, params, headers) {
113
125
  // its status is available, taken, limit, or lapsed.
114
126
  const gameHandle = function (id, handle, params, headers) {
115
127
  return request.get(
116
- endpoint(`/games/${id}/handles/${handle}`, params),
128
+ endpoint(pathOf`/games/${id}/handles/${handle}`, params),
117
129
  headers,
118
130
  );
119
131
  };
@@ -121,13 +133,16 @@ const gameHandle = function (id, handle, params, headers) {
121
133
  // [function]
122
134
 
123
135
  const release = function (id, params, headers) {
124
- return request.get(endpoint(`/releases/${id}`, params), headers);
136
+ return request.get(endpoint(pathOf`/releases/${id}`, params), headers);
125
137
  };
126
138
 
127
139
  // [function]
128
140
 
129
141
  const accountReleases = function (id, params, headers) {
130
- return request.get(endpoint(`/accounts/${id}/releases`, params), headers);
142
+ return request.get(
143
+ endpoint(pathOf`/accounts/${id}/releases`, params),
144
+ headers,
145
+ );
131
146
  };
132
147
 
133
148
  // [export]
@@ -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
  };
@@ -105,7 +105,7 @@ const WARNING = {
105
105
  DEPLOY_DIR_NOT_BUILT: "deploy_dir_not_built",
106
106
  FIELD_UNKNOWN: "field_unknown",
107
107
  GAME_HANDLE_LAPSED: "game_handle_lapsed",
108
- GAME_HANDLE_LIMIT: "game_handle_limit",
108
+ GAME_HANDLE_LIMIT_REACHED: "game_handle_limit_reached",
109
109
  VERSION_UNCHECKED: "version_unchecked",
110
110
  };
111
111
  // every error code, for checking one exists.
@@ -12,7 +12,7 @@ const strs = require("../util/strs");
12
12
  const deepCompact = objs.deepCompact;
13
13
  const trimWhitespace = strs.trimWhitespace;
14
14
 
15
- // [define]
15
+ // [declare]
16
16
 
17
17
  const COMMENT = 8;
18
18
 
package/src/phrase.js CHANGED
@@ -6,8 +6,10 @@ const cfgproduct = require("./config/product");
6
6
 
7
7
  // [declare]
8
8
 
9
+ const HANDLE = cfgproduct.handle;
9
10
  const TITLE = cfgproduct.title;
10
11
  const TOOL = cfgproduct.tool;
12
+ const TAIL_LINES = 20;
11
13
 
12
14
  // [function]
13
15
 
@@ -21,6 +23,22 @@ const blocks = function (reason, ...details) {
21
23
 
22
24
  // [function]
23
25
 
26
+ // the last lines a tool printed, stdout's then stderr's, since some, such as
27
+ // tsc, print their errors on stdout, or "" when it printed nothing. Lines
28
+ // left out are marked with "…".
29
+ const tail = function (...outputs) {
30
+ const lines = outputs
31
+ .map((output) => output?.trim())
32
+ .filter(Boolean)
33
+ .join("\n")
34
+ .split("\n");
35
+ return lines.length > TAIL_LINES
36
+ ? ["…", ...lines.slice(-TAIL_LINES)].join("\n")
37
+ : lines.join("\n");
38
+ };
39
+
40
+ // [function]
41
+
24
42
  // a wait, in words: "5 minutes", "90 seconds".
25
43
  const waited = function (seconds) {
26
44
  if (seconds % 60 === 0) {
@@ -39,10 +57,10 @@ const aborted = function (command) {
39
57
 
40
58
  // [function]
41
59
 
42
- // a build that exited with `code`, or was stopped by `signal`, with what it
43
- // wrote to stderr.
44
- const buildFailed = function ({ code, signal, stderr }) {
45
- const output = stderr?.trim();
60
+ // a build that exited with `code`, or was stopped by `signal`, with the end
61
+ // of what it printed.
62
+ const buildFailed = function ({ code, signal, stderr, stdout }) {
63
+ const output = tail(stdout, stderr);
46
64
  return blocks(
47
65
  signal
48
66
  ? `Build stopped by ${signal}.`
@@ -142,19 +160,19 @@ const didYouMean = function (near) {
142
160
  // [function]
143
161
 
144
162
  const docAttrInvalid = function (tag, attr, value) {
145
- return `Value '${value}' is not valid for the '${attr}' attribute on the '${tag}' tag.`;
163
+ return `Value '${value}' isn't allowed for ${attr} on <${tag}>.`;
146
164
  };
147
165
 
148
166
  // [function]
149
167
 
150
168
  const docAttrUnallowed = function (tag, attr) {
151
- return `Attribute '${attr}' is not permitted on the '${tag}' tag.`;
169
+ return `Attribute ${attr} isn't allowed on <${tag}>.`;
152
170
  };
153
171
 
154
172
  // [function]
155
173
 
156
174
  const docCommentUnallowed = function () {
157
- return "HTML comments are not permitted.";
175
+ return "HTML comments aren't allowed.";
158
176
  };
159
177
 
160
178
  // [function]
@@ -186,7 +204,7 @@ const docMediaType = function (src) {
186
204
  // [function]
187
205
 
188
206
  const docTagUnallowed = function (tag) {
189
- return `Tag '${tag}' is not permitted.`;
207
+ return `Tag <${tag}> isn't allowed.`;
190
208
  };
191
209
 
192
210
  // [function]
@@ -208,13 +226,13 @@ const gameHandleTaken = function (handle) {
208
226
  // [function]
209
227
 
210
228
  const gameHandleLapsed = function (handle) {
211
- return `Handle ${handle} lapsed: it comes back with a production release, so deploying without it.`;
229
+ return `Handle ${handle} lapsed, so deploying without it.\nA production release takes it back.`;
212
230
  };
213
231
 
214
232
  // [function]
215
233
 
216
234
  const gameHandleLimit = function (handle) {
217
- return `Handle ${handle} not applied: your unreleased games already hold 5 handles, so deploying without it.`;
235
+ return `Handle ${handle} not applied, so deploying without it.\nYour unreleased games already hold 5 handles.`;
218
236
  };
219
237
 
220
238
  // [function]
@@ -285,7 +303,7 @@ const packed = function () {
285
303
  // [function]
286
304
 
287
305
  const portInvalid = function () {
288
- return "The port must be a whole number from 1 to 65535.";
306
+ return "`--port` must be a whole number from 1 to 65535.";
289
307
  };
290
308
 
291
309
  // [function]
@@ -311,13 +329,13 @@ const remoteName = function (name) {
311
329
 
312
330
  // arc serve's copy of one of Arcadible's files, kept from `fetchedAt`.
313
331
  const remoteKept = function (name, fetchedAt) {
314
- return `${TITLE} can't be reached, so serving ${remoteName(name)} saved on ${fetchedAt.slice(0, 10)}.`;
332
+ return `Unable to reach ${TITLE}.\nServing ${remoteName(name)} saved on ${fetchedAt.slice(0, 10)}.`;
315
333
  };
316
334
 
317
335
  // [function]
318
336
 
319
337
  const remoteUnreachable = function (name) {
320
- return `${TITLE} can't be reached, and ${remoteName(name)} isn't saved yet. The game runs without it until ${TITLE} is back.`;
338
+ return `Unable to reach ${TITLE}, and ${remoteName(name)} isn't saved.\nThe game runs without it until ${TITLE} is back.`;
321
339
  };
322
340
 
323
341
  // [function]
@@ -334,6 +352,20 @@ const serveAlone = function () {
334
352
 
335
353
  // [function]
336
354
 
355
+ // the label before a play link in a result.
356
+ const playLabel = function () {
357
+ return "Play:";
358
+ };
359
+
360
+ // [function]
361
+
362
+ // the label before a store page's link in a result.
363
+ const storeLabel = function () {
364
+ return "Store:";
365
+ };
366
+
367
+ // [function]
368
+
337
369
  const serveNext = function (dir) {
338
370
  return `Reloads when ${dir}/ changes. Press Ctrl+C to stop.`;
339
371
  };
@@ -359,7 +391,7 @@ const serveNextUrl = function () {
359
391
  // [function]
360
392
 
361
393
  const urlInvalid = function () {
362
- return "The URL must start with http:// or https://, such as http://localhost:5173.";
394
+ return "`--url` must start with http:// or https://.";
363
395
  };
364
396
 
365
397
  // [function]
@@ -368,8 +400,12 @@ const urlInvalid = function () {
368
400
  // says how to add them.
369
401
  const urlNotFrameable = function (url, link) {
370
402
  return blocks(
371
- `⚠ The play page can't frame ${url}.`,
372
- "Send Cross-Origin-Embedder-Policy: require-corp and Cross-Origin-Resource-Policy: cross-origin.",
403
+ `The play page can't frame ${url}.`,
404
+ [
405
+ "Its server doesn't send the headers the play page needs:",
406
+ "Cross-Origin-Embedder-Policy: require-corp",
407
+ "Cross-Origin-Resource-Policy: cross-origin",
408
+ ],
373
409
  ["Add them to your server, as the starters' vite.config.js does:", link],
374
410
  );
375
411
  };
@@ -377,7 +413,7 @@ const urlNotFrameable = function (url, link) {
377
413
  // [function]
378
414
 
379
415
  const urlUnreachable = function (url) {
380
- return `⚠ Nothing answers at ${url} yet. Start your server, then reload the play page.`;
416
+ return `Nothing answers at ${url}.\nStart your server, then reload the play page.`;
381
417
  };
382
418
 
383
419
  // [function]
@@ -396,10 +432,11 @@ const releaseFailedHeading = function () {
396
432
 
397
433
  // origin isn't the game's connected repository: none is, or another is.
398
434
  const repoNotConnected = function (game, repo, url) {
399
- return blocks(`${repo} isn't ${game}'s repository on ${TITLE}.`, [
400
- `Connect it in ${TITLE} Studio, on the game's Repository tab (again if it was renamed on GitHub):`,
401
- url,
402
- ]);
435
+ return blocks(
436
+ `${repo} isn't ${game}'s repository on ${TITLE}.`,
437
+ [`Connect it on the game's Repository tab in ${TITLE} Studio:`, url],
438
+ "If it was renamed on GitHub, connect it again.",
439
+ );
403
440
  };
404
441
 
405
442
  // [function]
@@ -411,10 +448,10 @@ const gameNotFound = function (idOrHandle) {
411
448
  // [function]
412
449
 
413
450
  const gameUnavailable = function (id) {
414
- return blocks(`Game unavailable: ${id}`, [
415
- "It was deleted, or belongs to another account.",
451
+ return blocks(
452
+ `Game unavailable: ${id}\nIt was deleted, or belongs to another account.`,
416
453
  "Give game.id a new UUID to deploy it as a new game.",
417
- ]);
454
+ );
418
455
  };
419
456
 
420
457
  // [function]
@@ -430,7 +467,7 @@ const gitUncommitted = function () {
430
467
 
431
468
  const gitRemoteMissing = function () {
432
469
  return blocks(
433
- "No Git remote 'origin'.",
470
+ "No Git remote origin.",
434
471
  "Add the game's GitHub repository as origin.",
435
472
  );
436
473
  };
@@ -439,8 +476,8 @@ const gitRemoteMissing = function () {
439
476
 
440
477
  const gitRemoteUnreachable = function () {
441
478
  return blocks(
442
- "Unable to reach Git remote 'origin'.",
443
- "Check your connection, and that you can access it.",
479
+ "Unable to reach Git remote origin.",
480
+ "Check your internet connection, and that you can access it.",
444
481
  );
445
482
  };
446
483
 
@@ -450,8 +487,14 @@ const manifestMissing = function (file, dir, found) {
450
487
  return blocks(
451
488
  dir === "." ? `No ${file} in this directory.` : `No ${file} in ${dir}.`,
452
489
  found
453
- ? `The project is in \`${found}\`: run ${TOOL} there, or pass \`-C ${found}\`.`
454
- : `Run ${TOOL} in the project's directory, or pass \`-C\`, or start a project with ${cmdInit()}.`,
490
+ ? [
491
+ `Found a project in ${found}.`,
492
+ `Run \`${TOOL}\` there, or pass \`-C ${found}\`.`,
493
+ ]
494
+ : [
495
+ `Run \`${TOOL}\` in a project's directory, or pass \`-C <dir>\`.`,
496
+ `To start a project, run ${cmdInit()}.`,
497
+ ],
455
498
  );
456
499
  };
457
500
 
@@ -459,7 +502,7 @@ const manifestMissing = function (file, dir, found) {
459
502
 
460
503
  const projectNotRepoRoot = function (prefix) {
461
504
  return blocks(
462
- `${cmdDeployGit()} releases the project at the repository's root, and this one is in ${prefix}.`,
505
+ `Project is in ${prefix}, not the repository's root.\n${cmdDeployGit()} releases only a project at the root.`,
463
506
  `Deploy it with ${cmdDeploy()}, or give it a repository of its own.`,
464
507
  );
465
508
  };
@@ -475,19 +518,28 @@ const gitRepoMissing = function () {
475
518
 
476
519
  // [function]
477
520
 
478
- const gitTagCreateFailed = function (version) {
479
- return blocks(`Unable to create Git tag for v${version}.`, [
480
- "Check that the repository has a commit.",
481
- "Check that your Git name and email are set.",
482
- ]);
521
+ // with the end of what git printed, such as a lock file it found.
522
+ const gitTagCreateFailed = function (version, stderr) {
523
+ const output = tail(stderr);
524
+ return blocks(
525
+ `Unable to create Git tag for v${version}.`,
526
+ ...(output ? [output] : []),
527
+ [
528
+ "Check that the repository has a commit.",
529
+ "Check that your Git name and email are set.",
530
+ ],
531
+ );
483
532
  };
484
533
 
485
534
  // [function]
486
535
 
487
- const gitTagPushFailed = function (version) {
536
+ // with the end of what git printed, such as a hook's refusal.
537
+ const gitTagPushFailed = function (version, stderr) {
538
+ const output = tail(stderr);
488
539
  return blocks(
489
540
  `Unable to push Git tag for v${version}.`,
490
- "Check that you can push to 'origin'.",
541
+ ...(output ? [output] : []),
542
+ "Check that you can push to origin.",
491
543
  );
492
544
  };
493
545
 
@@ -564,7 +616,7 @@ const imageWidthMin = function (width) {
564
616
  // [function]
565
617
 
566
618
  const timeoutInvalid = function () {
567
- return "The timeout must be a number of seconds above 0.";
619
+ return "`--timeout` must be a number of seconds above 0.";
568
620
  };
569
621
 
570
622
  // [function]
@@ -573,8 +625,8 @@ const timeoutInvalid = function () {
573
625
  // parsed the project again.
574
626
  const issuesAfterBuild = function (count) {
575
627
  return blocks(
576
- `${count} ${count === 1 ? "issue" : "issues"} found after the build.`,
577
- `The build writes files the manifest reads. Run ${cmdValidate()} for details.`,
628
+ `${count} ${count === 1 ? "issue" : "issues"} found after the build.\nThe build writes files the manifest reads.`,
629
+ `Run ${cmdValidate()} for details.`,
578
630
  );
579
631
  };
580
632
 
@@ -590,13 +642,13 @@ const issuesFound = function (count) {
590
642
  // [function]
591
643
 
592
644
  const loginCodeExpired = function () {
593
- return "Login code expired.";
645
+ return blocks("Login code expired.", `Run ${cmdLogin()} again.`);
594
646
  };
595
647
 
596
648
  // [function]
597
649
 
598
650
  const loginFailed = function () {
599
- return "Login request failed.";
651
+ return blocks("Login request failed.", `Run ${cmdLogin()} again.`);
600
652
  };
601
653
 
602
654
  // [function]
@@ -611,10 +663,10 @@ const gameIdMissing = function () {
611
663
  // [function]
612
664
 
613
665
  const lockfileMissing = function () {
614
- return blocks("No lockfile found.", [
615
- "Install your dependencies to create one.",
616
- "Then commit it.",
617
- ]);
666
+ return blocks(
667
+ "No lockfile found.",
668
+ "Install your dependencies to create one, and commit it.",
669
+ );
618
670
  };
619
671
 
620
672
  // [function]
@@ -676,10 +728,14 @@ const packageFileTooLarge = function (file, size) {
676
728
 
677
729
  // [function]
678
730
 
679
- const packagePathReserved = function (folder) {
731
+ // `name` is a folder when it ends with "/": the reserved folder, which a
732
+ // build may load from, or the media folder. A file is the manifest.
733
+ const packagePathReserved = function (name) {
680
734
  return blocks(
681
- `'${folder}/' is reserved for ${TITLE}.`,
682
- "Rename the folder, and the paths that load from it.",
735
+ `'${name}' is reserved for ${TITLE}.`,
736
+ name.toLowerCase() === `${HANDLE}/`
737
+ ? "Rename the folder, and the paths that load from it."
738
+ : `${TITLE} adds its own, so leave it out of the folder you pack.`,
683
739
  );
684
740
  };
685
741
 
@@ -688,7 +744,7 @@ const packagePathReserved = function (folder) {
688
744
  const packageTooLarge = function (size) {
689
745
  return blocks(
690
746
  `Package is larger than ${size} MB.`,
691
- "Store assets don't count toward it.",
747
+ ".arcadible/ doesn't count toward it.",
692
748
  );
693
749
  };
694
750
 
@@ -712,7 +768,7 @@ const packageUncompressedTooLarge = function (size) {
712
768
  // open it.
713
769
  const releaseFailed = function ({ message }, studio) {
714
770
  return blocks(
715
- (message ?? "").split(/(?<=\.)\s+/u).join("\n"),
771
+ (message ?? "No reason given.").split(/(?<=\.)\s+/u).join("\n"),
716
772
  ...(studio ? [[`${TITLE} Studio:`, studio]] : []),
717
773
  );
718
774
  };
@@ -742,10 +798,10 @@ const releaseTimedOut = function (
742
798
  ]);
743
799
  }
744
800
  if (found) {
745
- return blocks(
746
- head,
747
- `It may still finish. The ${TITLE} check on the tagged commit says how it went.`,
748
- );
801
+ return blocks(head, [
802
+ "It may still finish.",
803
+ `The ${TITLE} check on the tagged commit says how it went.`,
804
+ ]);
749
805
  }
750
806
  return blocks(
751
807
  head,
@@ -753,7 +809,7 @@ const releaseTimedOut = function (
753
809
  "GitHub Actions hasn't released it yet, or its workflow failed:",
754
810
  actions ?? "See the repository's Actions tab.",
755
811
  ],
756
- `If the workflow passed, the ${TITLE} check on the tagged commit says why.`,
812
+ `If the workflow passed, see the ${TITLE} check on the tagged commit.`,
757
813
  );
758
814
  };
759
815
 
@@ -762,7 +818,7 @@ const releaseTimedOut = function (
762
818
  // the spinner while `--wait` waits: on GitHub Actions until the release
763
819
  // exists, then on Arcadible.
764
820
  const releaseWaiting = function (building) {
765
- return building ? "Waiting for GitHub Actions... %s" : "Publishing... %s";
821
+ return building ? "Waiting for GitHub Actions… %s" : "Publishing… %s";
766
822
  };
767
823
 
768
824
  // [function]
@@ -833,10 +889,13 @@ const tagPushed = function (tag) {
833
889
 
834
890
  // [function]
835
891
 
836
- const templateUnavailable = function (template) {
892
+ // `starter` is the starter its name suggests.
893
+ const templateUnavailable = function (template, starter) {
837
894
  return blocks(
838
895
  `Unable to download template ${template}.`,
839
- "Check that it's a public GitHub repository, or a folder in one.",
896
+ starter
897
+ ? `Did you mean: ${starter}?`
898
+ : "Check that it's a public GitHub repository, or a folder in one.",
840
899
  );
841
900
  };
842
901
 
@@ -887,9 +946,9 @@ const uploadFailed = function (status) {
887
946
 
888
947
  // [function]
889
948
 
890
- const uploadRateLimited = function (version) {
949
+ const deployRateLimited = function (version) {
891
950
  return blocks(
892
- `v${version} was uploaded in the last 5 minutes.`,
951
+ `v${version} was deployed in the last 5 minutes.`,
893
952
  "Wait, then deploy again.",
894
953
  );
895
954
  };
@@ -1022,6 +1081,7 @@ module.exports = {
1022
1081
  cmdInit,
1023
1082
  cmdInspect,
1024
1083
  deployDirMissing,
1084
+ deployRateLimited,
1025
1085
  didYouMean,
1026
1086
  docAttrInvalid,
1027
1087
  docAttrUnallowed,
@@ -1083,6 +1143,7 @@ module.exports = {
1083
1143
  packageTooManyFiles,
1084
1144
  packageUncompressedTooLarge,
1085
1145
  packed,
1146
+ playLabel,
1086
1147
  portInUse,
1087
1148
  portInvalid,
1088
1149
  pressEnterToOpen,
@@ -1110,6 +1171,7 @@ module.exports = {
1110
1171
  starterPhaser,
1111
1172
  starterPixiJs,
1112
1173
  starterThreeJs,
1174
+ storeLabel,
1113
1175
  tagPushed,
1114
1176
  templateMissing,
1115
1177
  templateUnavailable,
@@ -1121,7 +1183,6 @@ module.exports = {
1121
1183
  unknownField,
1122
1184
  unknownTable,
1123
1185
  uploadFailed,
1124
- uploadRateLimited,
1125
1186
  urlInvalid,
1126
1187
  urlNotFrameable,
1127
1188
  urlUnreachable,