arcadible 1.0.2 → 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 CHANGED
@@ -17,19 +17,16 @@ const build = require("../src/cli/build");
17
17
  const cfgcode = require("../src/config/code");
18
18
  const cfgpackage = require("../src/config/package");
19
19
  const cfgproduct = require("../src/config/product");
20
- const error = require("../src/util/error");
20
+ const checked = require("../src/action/validate/checked");
21
21
  const log = require("../src/util/log");
22
22
  const output = require("../src/util/output");
23
23
  const phrase = require("../src/phrase");
24
- const project = require("../src/parser/project");
25
24
  const rc = require("../src/util/rc");
26
25
  const spinner = require("../src/util/spinner");
27
- const validate = require("../src/cli/validate");
28
26
 
29
27
  // [use]
30
28
 
31
29
  const abort = output.abort;
32
- const ArcError = error.ArcError;
33
30
  const findRc = rc.findRc;
34
31
  const print = output.print;
35
32
  const relative = path.relative;
@@ -62,26 +59,16 @@ const start = function (argv) {
62
59
  let parsed = null;
63
60
  // what --json lists under `warnings`.
64
61
  let warnings = [];
65
- let sw = new SpinnerWheel("Validating... %s");
62
+ let sw = new SpinnerWheel("Validating… %s");
66
63
  sw.start(json || quiet);
67
- return project(root)
64
+ return checked(root, (found) => {
65
+ warnings = found;
66
+ })
68
67
  .then((proj) => {
69
68
  parsed = proj;
70
- return validate({ project: parsed, root });
71
- })
72
- .then((validated) => {
73
- const count = validated.issues.length;
74
- warnings = validated.warnings;
75
- if (count) {
76
- throw new ArcError(
77
- cfgcode.VALIDATION_FAILED,
78
- phrase.issuesFound(count),
79
- { data: { issues: validated.issues } },
80
- );
81
- }
82
69
  sw.stop(true);
83
70
  warn(warnings, { json, quiet });
84
- sw = new SpinnerWheel("Building... %s");
71
+ sw = new SpinnerWheel("Building… %s");
85
72
  sw.start(json || quiet);
86
73
  return build({ project: parsed, root });
87
74
  })
@@ -110,9 +97,7 @@ const start = function (argv) {
110
97
  }
111
98
  if (artifact?.missing) {
112
99
  log.result(phrase.buildSucceeded(), [], { color: "yellow" });
113
- log.nlpw(
114
- `⚠ ${phrase.buildOutputMissing(relative(root, artifact.missing))}`,
115
- );
100
+ log.nlpw(phrase.buildOutputMissing(relative(root, artifact.missing)));
116
101
  return;
117
102
  }
118
103
  log.hs(phrase.nothingToDo());
@@ -34,17 +34,17 @@ const main = function (argv) {
34
34
  yargs(args.normalize(hideBin(argv)))
35
35
  .scriptName(TOOL)
36
36
  .usage("$0 <command> [options]")
37
- .command("init", "Initialize project")
38
- .command("inspect", "Inspect project")
39
- .command("validate", "Validate project")
40
- .command("build", "Build project")
41
- .command("pack", "Package project")
42
- .command("serve", "Serve a game locally")
43
- .command("deploy", "Deploy project")
37
+ .command("init", "Initialize a project")
38
+ .command("inspect", "Print the resolved manifest")
39
+ .command("validate", "Check the project for issues")
40
+ .command("build", "Run the project's build")
41
+ .command("pack", "Pack the game into a zip")
42
+ .command("serve", "Serve the game locally")
43
+ .command("deploy", "Deploy the game")
44
44
  .command("open", "Open a game's store page")
45
45
  .command("play", "Play a game")
46
46
  .command("login", `Log in to ${TITLE}`)
47
- .command("whoami", `Show ${TITLE} account`)
47
+ .command("whoami", "Show the logged-in account")
48
48
  .command("logout", `Log out of ${TITLE}`)
49
49
  .help("help")
50
50
  .alias("help", "h")
package/bin/arc-deploy.js CHANGED
@@ -17,6 +17,7 @@ const build = require("../src/cli/build");
17
17
  const cfgcode = require("../src/config/code");
18
18
  const cfgpackage = require("../src/config/package");
19
19
  const cfgproduct = require("../src/config/product");
20
+ const checked = require("../src/action/validate/checked");
20
21
  const deploy = require("../src/cli/deploy");
21
22
  const error = require("../src/util/error");
22
23
  const links = require("../src/util/links");
@@ -97,7 +98,7 @@ const handler = function ({ json, pb, quiet, sw, warnings }) {
97
98
  if (pb) {
98
99
  pb.stop();
99
100
  }
100
- log.pw(`⚠ ${message}`);
101
+ log.pw(message);
101
102
  sw.start(false);
102
103
  if (pb) {
103
104
  pb.start();
@@ -126,7 +127,11 @@ const report = function (
126
127
  heading = phrase.releasePublished(version.to, channel, built);
127
128
  next = null;
128
129
  }
129
- log.result(heading, [store ? ["Store:", store] : null, ["Play:", url], next]);
130
+ log.result(heading, [
131
+ store ? [phrase.storeLabel(), store] : null,
132
+ [phrase.playLabel(), url],
133
+ next,
134
+ ]);
130
135
  };
131
136
 
132
137
  // [function]
@@ -259,27 +264,19 @@ const start = function (argv) {
259
264
  let parsed = null;
260
265
  // what --json lists under `warnings`: arc validate's, then the deploy's.
261
266
  const warnings = [];
262
- let sw = new SpinnerWheel("Validating... %s");
267
+ let sw = new SpinnerWheel("Validating… %s");
263
268
  sw.start(json || quiet);
264
269
  return checkTimeout(timeout)
265
- .then(() => project(root))
270
+ .then(() =>
271
+ checked(root, (found) => {
272
+ warnings.push(...found);
273
+ }),
274
+ )
266
275
  .then((proj) => {
267
276
  parsed = proj;
268
- return validate({ project: parsed, root });
269
- })
270
- .then((validated) => {
271
- const count = validated.issues.length;
272
- warnings.push(...validated.warnings);
273
- if (count) {
274
- throw new ArcError(
275
- cfgcode.VALIDATION_FAILED,
276
- phrase.issuesFound(count),
277
- { data: { issues: validated.issues } },
278
- );
279
- }
280
277
  sw.stop(true);
281
- warn(validated.warnings, { json, quiet });
282
- sw = new SpinnerWheel("Checking... %s");
278
+ warn(warnings, { json, quiet });
279
+ sw = new SpinnerWheel("Checking… %s");
283
280
  // git deploys need no login: anyone who can push to the repository can
284
281
  // release, and the Arcadible GitHub App publishes the release. Anyone
285
282
  // can wait for it too; the game's owner, logged in, waits among their
@@ -296,7 +293,7 @@ const start = function (argv) {
296
293
  throw new ArcError(cfgcode.NOT_LOGGED_IN, phrase.notLoggedIn());
297
294
  }
298
295
  sw.stop(true);
299
- sw = new SpinnerWheel("Preparing... %s");
296
+ sw = new SpinnerWheel("Preparing… %s");
300
297
  return Promise.all([
301
298
  // whoami
302
299
  current,
@@ -314,7 +311,7 @@ const start = function (argv) {
314
311
  sw.stop(true);
315
312
  owner = predeployed.owner ?? null;
316
313
  held = predeployed.held ?? false;
317
- sw = new SpinnerWheel("Building... %s");
314
+ sw = new SpinnerWheel("Building… %s");
318
315
  sw.start(git || json || quiet);
319
316
  return Promise.all([
320
317
  // whoami
@@ -345,7 +342,7 @@ const start = function (argv) {
345
342
  }
346
343
  parsed = proj;
347
344
  sw.stop(true);
348
- sw = new SpinnerWheel("Packing... %s");
345
+ sw = new SpinnerWheel("Packing… %s");
349
346
  sw.start(git || json || quiet);
350
347
  return Promise.all([
351
348
  // whoami
@@ -441,7 +438,8 @@ const main = function (argv) {
441
438
  })
442
439
  .option("timeout", {
443
440
  default: conf.timeout,
444
- describe: "Seconds to wait [default: 300, or 900 for git]",
441
+ defaultDescription: "300, or 900 for git",
442
+ describe: "Seconds to wait",
445
443
  type: "number",
446
444
  })
447
445
  .option("cwd", args.CWD)
package/bin/arc-init.js CHANGED
@@ -31,6 +31,7 @@ const spinner = require("../src/util/spinner");
31
31
 
32
32
  const abort = output.abort;
33
33
  const ArcError = error.ArcError;
34
+ const exit = output.exit;
34
35
  const findRc = rc.findRc;
35
36
  const pathExists = fs.pathExists;
36
37
  const print = output.print;
@@ -69,7 +70,7 @@ const handler = function ({ json, quiet, sw }) {
69
70
  const start = function (argv) {
70
71
  const json = argv.json;
71
72
  const quiet = argv.quiet;
72
- const sw = new SpinnerWheel("Initializing... %s");
73
+ const sw = new SpinnerWheel("Initializing… %s");
73
74
  return init({
74
75
  handler: handler({ json, quiet, sw }),
75
76
  patch: argv.patch,
@@ -86,7 +87,7 @@ const start = function (argv) {
86
87
  print(project, { nl: true, toml: true });
87
88
  }
88
89
  // degit sometimes hangs, so exit once stdout is written.
89
- process.stdout.write("", () => process.exit(0));
90
+ return exit(0);
90
91
  })
91
92
  .catch((ex) => abort(phrase.aborted(COMMAND), ex, { json, sw }));
92
93
  };
@@ -149,7 +150,7 @@ const main = function (argv) {
149
150
  default: conf.template,
150
151
  describe: [
151
152
  "Project template",
152
- "Public GitHub repository, or a folder in one (user/repo[/folder]).",
153
+ "Public GitHub repository, or a folder in one (user/repo[/folder])",
153
154
  ].join("\n"),
154
155
  type: "string",
155
156
  })
package/bin/arc-login.js CHANGED
@@ -137,12 +137,12 @@ const main = function (argv) {
137
137
  .usage("$0 [options]")
138
138
  .option("browser", {
139
139
  default: conf.browser,
140
- describe: "Open a web browser on Enter (disable with --no-browser)",
140
+ describe: "Open a web browser on Enter",
141
141
  type: "boolean",
142
142
  })
143
143
  .option("qrcode", {
144
144
  default: conf.qrcode,
145
- describe: "Display a qrcode (disable with --no-qrcode)",
145
+ describe: "Show a QR code",
146
146
  type: "boolean",
147
147
  })
148
148
  .help("help")
package/bin/arc-pack.js CHANGED
@@ -13,23 +13,19 @@ const yargs = require("yargs/yargs");
13
13
  // [import]
14
14
 
15
15
  const args = require("../src/util/argv");
16
- const cfgcode = require("../src/config/code");
17
16
  const cfgpackage = require("../src/config/package");
18
17
  const cfgproduct = require("../src/config/product");
19
- const error = require("../src/util/error");
18
+ const checked = require("../src/action/validate/checked");
20
19
  const log = require("../src/util/log");
21
20
  const output = require("../src/util/output");
22
21
  const pack = require("../src/cli/pack");
23
22
  const phrase = require("../src/phrase");
24
- const project = require("../src/parser/project");
25
23
  const rc = require("../src/util/rc");
26
24
  const spinner = require("../src/util/spinner");
27
- const validate = require("../src/cli/validate");
28
25
 
29
26
  // [use]
30
27
 
31
28
  const abort = output.abort;
32
- const ArcError = error.ArcError;
33
29
  const findRc = rc.findRc;
34
30
  const print = output.print;
35
31
  const resolve = path.resolve;
@@ -62,26 +58,16 @@ const start = function (argv) {
62
58
  let parsed = null;
63
59
  // what --json lists under `warnings`.
64
60
  let warnings = [];
65
- let sw = new SpinnerWheel("Validating... %s");
61
+ let sw = new SpinnerWheel("Validating… %s");
66
62
  sw.start(json || quiet);
67
- return project(root)
63
+ return checked(root, (found) => {
64
+ warnings = found;
65
+ })
68
66
  .then((proj) => {
69
67
  parsed = proj;
70
- return validate({ project: parsed, root });
71
- })
72
- .then((validated) => {
73
- const count = validated.issues.length;
74
- warnings = validated.warnings;
75
- if (count) {
76
- throw new ArcError(
77
- cfgcode.VALIDATION_FAILED,
78
- phrase.issuesFound(count),
79
- { data: { issues: validated.issues } },
80
- );
81
- }
82
68
  sw.stop(true);
83
69
  warn(warnings, { json, quiet });
84
- sw = new SpinnerWheel("Packing... %s");
70
+ sw = new SpinnerWheel("Packing… %s");
85
71
  sw.start(json || quiet);
86
72
  return pack({
87
73
  input: argv.input,
@@ -116,13 +102,13 @@ const main = function (argv) {
116
102
  .option("input", {
117
103
  alias: "i",
118
104
  default: conf.input,
119
- describe: "Set the input directory",
105
+ describe: "Pack this directory instead of deploy_dir",
120
106
  type: "string",
121
107
  })
122
108
  .option("output", {
123
109
  alias: "o",
124
110
  default: conf.output,
125
- describe: "Set the output file",
111
+ describe: "Write the zip to this path",
126
112
  type: "string",
127
113
  })
128
114
  .option("json", { ...args.JSON_OUTPUT, default: conf.json })
package/bin/arc-play.js CHANGED
@@ -64,7 +64,7 @@ const handler = function ({ quiet, sw }) {
64
64
  // [function]
65
65
 
66
66
  const start = function (argv) {
67
- const sw = new SpinnerWheel("Opening... %s");
67
+ const sw = new SpinnerWheel("Opening… %s");
68
68
  return play({
69
69
  game: argv.game,
70
70
  handler: handler({ quiet: argv.quiet, sw }),
package/bin/arc-serve.js CHANGED
@@ -111,7 +111,7 @@ const start = function (argv) {
111
111
  // `.arcrc` values are strings, and a flag that isn't a number is NaN.
112
112
  const port = Number(argv.port);
113
113
  const root = resolve(process.cwd(), argv.cwd);
114
- const sw = new SpinnerWheel("Building... %s");
114
+ const sw = new SpinnerWheel("Building… %s");
115
115
  return checkPort(port)
116
116
  .then(() => checkUrl(argv.url))
117
117
  .then((url) =>
@@ -141,7 +141,7 @@ const start = function (argv) {
141
141
  process.once("SIGTERM", stop);
142
142
  if (!quiet) {
143
143
  log.result(phrase.served(served), [
144
- ["Play:", `${served.page}/`],
144
+ [phrase.playLabel(), `${served.page}/`],
145
145
  [phrase.serveAlone(), served.game],
146
146
  served.url
147
147
  ? phrase.serveNextUrl()
@@ -173,7 +173,7 @@ const main = function (argv) {
173
173
  .option("port", {
174
174
  alias: "p",
175
175
  default: conf.port,
176
- describe: "Port to serve on",
176
+ describe: "Serve on this port",
177
177
  type: "number",
178
178
  })
179
179
  .option("build", {
@@ -182,6 +182,7 @@ const main = function (argv) {
182
182
  type: "boolean",
183
183
  })
184
184
  .option("url", {
185
+ default: conf.url,
185
186
  describe: "Frame another server's page instead of deploy_dir",
186
187
  type: "string",
187
188
  })
@@ -26,6 +26,7 @@ const validate = require("../src/cli/validate");
26
26
 
27
27
  const abort = output.abort;
28
28
  const dereference = schema.dereference;
29
+ const exit = output.exit;
29
30
  const findRc = rc.findRc;
30
31
  const print = output.print;
31
32
  const resolve = path.resolve;
@@ -75,7 +76,7 @@ const start = function (argv) {
75
76
  log.hs(phrase.noIssuesFound());
76
77
  }
77
78
  }
78
- process.exit(count ? 1 : 0);
79
+ return exit(count ? 1 : 0);
79
80
  })
80
81
  .catch((ex) => abort(phrase.aborted(COMMAND), ex, { json }));
81
82
  };
package/bin/arc-whoami.js CHANGED
@@ -54,7 +54,7 @@ const handler = function ({ json, sw }) {
54
54
 
55
55
  const start = function (argv) {
56
56
  const json = argv.json;
57
- const sw = new SpinnerWheel("Checking... %s");
57
+ const sw = new SpinnerWheel("Checking… %s");
58
58
  return whoami({ handler: handler({ json, sw }) })
59
59
  .then((current) => {
60
60
  const user = current?.user;
package/package.json CHANGED
@@ -65,5 +65,5 @@
65
65
  "scripts": {
66
66
  "test": "node --test \"test/**/*.test.js\""
67
67
  },
68
- "version": "1.0.2"
68
+ "version": "1.0.4"
69
69
  }
package/src/account.js CHANGED
@@ -102,7 +102,9 @@ const getSaved = function (onRefresh) {
102
102
  return readFile(file, "utf8")
103
103
  .then(JSON.parse)
104
104
  .catch((ex) => {
105
- if (ex.code === "ENOENT") {
105
+ // a session file cut short (a full disk, a crash while saving) is no
106
+ // session: `arc login` writes a new one
107
+ if (ex.code === "ENOENT" || ex instanceof SyntaxError) {
106
108
  return null;
107
109
  }
108
110
  throw ex;
@@ -33,18 +33,19 @@ const uploadBuild = function (current, artifact, { id, version }, onProgress) {
33
33
  s3.upload(upload.upload_url, artifact, onProgress),
34
34
  ]),
35
35
  (err) => {
36
- // the API refuses a game that was deleted or is another account's,
37
- // and the same version uploaded again within 5 minutes.
36
+ // the API refuses a game that was deleted or is another account's
37
+ // (403), and the same version deployed again within 5 minutes (429).
38
38
  if (err.status === 403) {
39
39
  throw new ArcError(
40
40
  cfgcode.GAME_UNAVAILABLE,
41
41
  phrase.gameUnavailable(id),
42
+ { cause: err },
42
43
  );
43
44
  }
44
45
  if (err.status === 429) {
45
46
  throw new ArcError(
46
- cfgcode.UPLOAD_RATE_LIMITED,
47
- phrase.uploadRateLimited(version),
47
+ cfgcode.DEPLOY_RATE_LIMITED,
48
+ phrase.deployRateLimited(version),
48
49
  { cause: err },
49
50
  );
50
51
  }
@@ -68,7 +68,10 @@ const ensureHandle = function (current, { handle, id, version }, handler) {
68
68
  );
69
69
  }
70
70
  if (status === "limit") {
71
- warn(cfgcode.WARNING.GAME_HANDLE_LIMIT, phrase.gameHandleLimit(handle));
71
+ warn(
72
+ cfgcode.WARNING.GAME_HANDLE_LIMIT_REACHED,
73
+ phrase.gameHandleLimit(handle),
74
+ );
72
75
  return true;
73
76
  }
74
77
  if (status === "lapsed") {
@@ -6,6 +6,7 @@
6
6
  // [import]
7
7
 
8
8
  const path = require("node:path");
9
+ const timers = require("node:timers/promises");
9
10
 
10
11
  // [import]
11
12
 
@@ -39,6 +40,7 @@ const relative = path.relative;
39
40
  const remoteFiles = remote.remoteFiles;
40
41
  const resolvePath = path.resolve;
41
42
  const serve = server.serve;
43
+ const sleep = timers.setTimeout;
42
44
  const watchDir = reload.watchDir;
43
45
 
44
46
  // [declare]
@@ -48,7 +50,7 @@ const CHANNEL = "local";
48
50
  // the saves of a game with no id yet, kept apart from any other's.
49
51
  const UNNAMED = "local";
50
52
 
51
- // [function]
53
+ // [declare]
52
54
 
53
55
  // the headers a page needs for the play page to frame it: the play page is
54
56
  // cross-origin isolated, so a cross-origin frame must be too, and allow it.
@@ -57,19 +59,33 @@ const FRAMEABLE = {
57
59
  "cross-origin-resource-policy": ["cross-origin"],
58
60
  };
59
61
 
62
+ // [declare]
63
+
64
+ // how long `url` has to answer before it counts as unreachable: a server
65
+ // that takes the connection and never answers would otherwise hold `arc
66
+ // serve` for minutes.
67
+ const PROBE_MS = 10000;
68
+
60
69
  // [function]
61
70
 
62
71
  // what `url` says when asked: `{ reachable, frameable }`, where `frameable`
63
72
  // says whether it sends the headers the play page needs to frame it.
64
73
  const probe = async function (url) {
65
74
  try {
66
- const res = await fetch(url, { method: "GET" });
75
+ // null when it hasn't answered in time
76
+ const res = await Promise.race([
77
+ fetch(url, { method: "GET" }),
78
+ sleep(PROBE_MS, null, { ref: false }),
79
+ ]);
80
+ if (!res) {
81
+ return { frameable: false, reachable: false };
82
+ }
67
83
  await res.body?.cancel();
68
84
  const frameable = Object.entries(FRAMEABLE).every(([name, values]) =>
69
85
  values.includes(res.headers.get(name)?.trim().toLowerCase()),
70
86
  );
71
87
  return { frameable, reachable: true };
72
- } catch (ex) {
88
+ } catch {
73
89
  return { frameable: false, reachable: false };
74
90
  }
75
91
  };
@@ -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]