arcadible 0.1.13 → 0.1.14

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-deploy.js CHANGED
@@ -19,7 +19,9 @@ const output = require("../src/util/output");
19
19
  const pack = require("../src/cli/pack");
20
20
  const phrase = require("../src/phrase");
21
21
  const pkg = require("../package.json");
22
+ const progress = require("../src/util/progress");
22
23
  const rc = require("../src/util/rc");
24
+ const spinner = require("../src/util/spinner");
23
25
  const validate = require("../src/cli/validate");
24
26
  const whoami = require("../src/cli/whoami");
25
27
 
@@ -27,7 +29,9 @@ const whoami = require("../src/cli/whoami");
27
29
 
28
30
  const findRc = rc.findRc;
29
31
  const print = output.print;
32
+ const ProgressBar = progress.ProgressBar;
30
33
  const resolve = path.resolve;
34
+ const SpinnerWheel = spinner.SpinnerWheel;
31
35
 
32
36
  // [declare]
33
37
 
@@ -45,30 +49,36 @@ const conf = {
45
49
 
46
50
  // [function]
47
51
 
48
- const handler = function ({ json, quiet }) {
52
+ const handler = function ({ json, pb, quiet }) {
49
53
  return {
50
- onBegin() {
54
+ onAccountRefresh(refresh) {
55
+ return refresh(true);
56
+ },
57
+ onDeployBegin() {
51
58
  if (!json && !quiet) {
52
- log.pnl("Deploying...");
59
+ log.p("Submitting...");
60
+ if (pb) {
61
+ pb.start();
62
+ }
53
63
  }
54
64
  },
55
- onInfo({ level, message }) {
56
- if (json || quiet) {
57
- return;
58
- }
59
- switch (level) {
60
- case "warn":
61
- log.pw(`⚠ ${message}`);
62
- return;
63
- default:
64
- log.p(`· ${message}`);
65
+ onLogInfo({ level, message }) {
66
+ if (!json && !quiet) {
67
+ switch (level) {
68
+ case "warn":
69
+ log.pw(`⚠ ${message}`);
70
+ return;
71
+ default:
72
+ log.p(`· ${message}`);
73
+ }
65
74
  }
66
75
  },
67
- onRefresh(refresh) {
68
- if (!json) {
69
- // log.p("Checking login...");
76
+ onUploadProgress(step) {
77
+ if (!json && !quiet) {
78
+ if (pb) {
79
+ pb.increment(step);
80
+ }
70
81
  }
71
- return refresh(true);
72
82
  },
73
83
  };
74
84
  };
@@ -80,11 +90,17 @@ const start = function (argv) {
80
90
  const json = argv.json;
81
91
  const quiet = argv.quiet;
82
92
  const root = resolve(process.cwd(), argv.cwd);
83
- return whoami({ handler: handler({ json, quiet }) })
93
+ let pb = null;
94
+ let sw = new SpinnerWheel("Checking login... %s");
95
+ sw.start(git || json || quiet);
96
+ return whoami({ handler: handler({ json, pb, quiet }) })
84
97
  .then((current) => {
85
98
  if (!current || !current.session) {
86
99
  throw new Error(phrase.notLoggedIn());
87
100
  }
101
+ sw.stop();
102
+ sw = new SpinnerWheel("Validating... %s");
103
+ sw.start(git || json || quiet);
88
104
  return Promise.all([
89
105
  // whoami
90
106
  current.session,
@@ -97,6 +113,9 @@ const start = function (argv) {
97
113
  if (count) {
98
114
  throw new Error(phrase.issuesFound(count));
99
115
  }
116
+ sw.stop();
117
+ sw = new SpinnerWheel("Building... %s");
118
+ sw.start(git || json || quiet);
100
119
  return Promise.all([
101
120
  // whoami
102
121
  session,
@@ -104,32 +123,43 @@ const start = function (argv) {
104
123
  git ? null : build({ root }),
105
124
  ]);
106
125
  })
107
- .then(([session, artifact]) =>
108
- Promise.all([
126
+ .then(([session, artifact]) => {
127
+ sw.stop();
128
+ sw = new SpinnerWheel("Packing... %s");
129
+ sw.start(git || json || quiet);
130
+ return Promise.all([
109
131
  // whoami
110
132
  session,
111
133
  // pack
112
134
  git ? null : pack({ input: artifact?.path, root }),
113
- ]),
114
- )
115
- .then(([session, artifact]) =>
116
- deploy(
117
- git
118
- ? { handler: handler({ json, quiet }), root }
119
- : {
120
- artifact,
121
- handler: handler({ json, quiet }),
122
- root,
123
- session,
124
- },
125
- ),
126
- )
135
+ ]);
136
+ })
137
+ .then(([session, artifact]) => {
138
+ sw.stop(true);
139
+ if (!json && !quiet && !git) {
140
+ pb = new ProgressBar(artifact.size);
141
+ }
142
+ return git
143
+ ? deploy({ handler: handler({ json, pb, quiet }), root })
144
+ : deploy({
145
+ artifact,
146
+ handler: handler({ json, pb, quiet }),
147
+ root,
148
+ session,
149
+ });
150
+ })
127
151
  .then((version) => {
128
152
  if (json) {
129
153
  print({ version });
130
154
  return;
131
155
  }
132
156
  if (!quiet) {
157
+ if (pb) {
158
+ sw.stop();
159
+ pb.stop();
160
+ } else {
161
+ sw.stop(true);
162
+ }
133
163
  log.hs("Done.");
134
164
  if (version) {
135
165
  log.p(`Build v${version.to} submitted.`);
@@ -143,6 +173,12 @@ const start = function (argv) {
143
173
  if (json) {
144
174
  print({ error: { message } });
145
175
  } else {
176
+ if (pb) {
177
+ sw.stop();
178
+ pb.stop();
179
+ } else {
180
+ sw.stop(true);
181
+ }
146
182
  log.hd("Deploy aborted.");
147
183
  log.p(message);
148
184
  }
package/bin/arc-init.js CHANGED
@@ -14,7 +14,6 @@ const yargs = require("yargs/yargs");
14
14
 
15
15
  // [import]
16
16
 
17
- const cfgurl = require("../src/config/url");
18
17
  const init = require("../src/cli/init");
19
18
  const log = require("../src/util/log");
20
19
  const output = require("../src/util/output");
@@ -28,7 +27,6 @@ const findRc = rc.findRc;
28
27
  const join = path.join;
29
28
  const pathExists = fs.pathExists;
30
29
  const print = output.print;
31
- const relative = path.relative;
32
30
  const resolve = path.resolve;
33
31
  const select = prompts.select;
34
32
 
@@ -51,12 +49,22 @@ const conf = {
51
49
 
52
50
  const handler = function ({ json, quiet }) {
53
51
  return {
54
- onBegin() {
52
+ onInitBegin() {
55
53
  if (!json && !quiet) {
56
- log.pnl("Initializing...");
54
+ log.p("Initializing...");
55
+ }
56
+ },
57
+ onLogInfo({ level, message }) {
58
+ if (!json && !quiet) {
59
+ switch (level) {
60
+ case "warn":
61
+ log.pw(`⚠ ${message}`);
62
+ return;
63
+ default:
64
+ log.p(`· ${message}`);
65
+ }
57
66
  }
58
67
  },
59
- onInfo() {},
60
68
  };
61
69
  };
62
70
 
@@ -67,7 +75,7 @@ const start = function (argv) {
67
75
  const quiet = argv.quiet;
68
76
  const root = resolve(process.cwd(), argv.cwd);
69
77
  return init({
70
- force: false,
78
+ force: true,
71
79
  handler: handler({ json, quiet }),
72
80
  patch: argv.patch,
73
81
  project: argv.project,
@@ -80,19 +88,7 @@ const start = function (argv) {
80
88
  return;
81
89
  }
82
90
  if (!quiet) {
83
- log.hsnl("Done.");
84
- log.h("Next steps:");
85
- log.pnl(
86
- [
87
- project.path === root ? null : `cd ${relative(root, project.path)}`,
88
- "arc login",
89
- "arc deploy (or: arc deploy --git)",
90
- ]
91
- .filter(Boolean)
92
- .map((step, i) => `${i + 1}. ${step}`),
93
- );
94
- log.h("Getting started:");
95
- log.p(cfgurl.GETTING_STARTED);
91
+ log.hs("Done.");
96
92
  }
97
93
  // degit sometimes hangs
98
94
  process.exit(0);
package/bin/arc-login.js CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  const hideBin = require("yargs/helpers").hideBin;
7
7
  const open = require("open");
8
+ const qrcode = require("qrcode-terminal");
8
9
  const yargs = require("yargs/yargs");
9
10
 
10
11
  // [import]
@@ -27,12 +28,13 @@ const SUBCMD = "login";
27
28
 
28
29
  const conf = {
29
30
  browser: true,
31
+ qrcode: true,
30
32
  ...findRc(CMD, SUBCMD, process.argv, ["--cwd", "-C"]),
31
33
  };
32
34
 
33
35
  // [function]
34
36
 
35
- const onEnter = function (fn) {
37
+ const onLoginEnter = function (fn) {
36
38
  const stdin = process.stdin;
37
39
  if (!stdin.isTTY) {
38
40
  return;
@@ -58,38 +60,43 @@ const onEnter = function (fn) {
58
60
 
59
61
  // [function]
60
62
 
61
- const handler = function ({ browser }) {
63
+ const handler = function ({ browser, qrcode: qr }) {
62
64
  return {
63
- onCreated({ code, url }) {
64
- log.p(url);
65
- log.h(code.toUpperCase());
66
- if (browser) {
67
- log.p("");
68
- log.p("Press Enter to open the URL.");
69
- onEnter(() => {
70
- open(url).catch(() => {});
71
- });
72
- }
65
+ onLoginCreated({ code: dac, id, url }) {
66
+ const link = `${url}/${id}`;
67
+ qrcode.generate(link, { small: true }, (code) => {
68
+ if (qr) {
69
+ log.p(code);
70
+ }
71
+ log.nlp(url);
72
+ log.h(dac.toUpperCase());
73
+ if (browser) {
74
+ log.nlp("Press Enter to open the URL.");
75
+ onLoginEnter(() => {
76
+ open(link).catch(() => {});
77
+ });
78
+ }
79
+ });
73
80
  },
74
- onPoll() {},
81
+ onLoginPoll() {},
75
82
  };
76
83
  };
77
84
 
78
85
  // [function]
79
86
 
80
87
  const start = function (argv) {
81
- const browser = argv.browser;
82
- log.pnl("Logging in...");
83
- return login({ handler: handler({ browser }) })
88
+ log.p("Logging in...");
89
+ return login({
90
+ handler: handler({ browser: argv.browser, qrcode: argv.qrcode }),
91
+ })
84
92
  .then(({ profile }) => {
85
93
  process.stdin.pause();
86
- log.p("");
87
- log.hs("Done.");
94
+ log.nlhs("Logged in.");
88
95
  log.p(profile.display_name);
89
96
  })
90
97
  .catch((ex) => {
91
98
  process.stdin.pause();
92
- log.hd("Login aborted.");
99
+ log.nlhd("Login aborted.");
93
100
  log.p(ex.message);
94
101
  process.exit(1);
95
102
  });
@@ -104,8 +111,12 @@ const main = function (argv) {
104
111
  .usage("$0 [options]")
105
112
  .option("browser", {
106
113
  default: conf.browser,
107
- describe:
108
- "Open a web browser automatically (disable with --no-browser)",
114
+ describe: "Open a web browser on Enter (disable with --no-browser)",
115
+ type: "boolean",
116
+ })
117
+ .option("qrcode", {
118
+ default: conf.qrcode,
119
+ describe: "Display a qrcode (disable with --no-qrcode)",
109
120
  type: "boolean",
110
121
  })
111
122
  .help("help")
package/bin/arc-whoami.js CHANGED
@@ -35,7 +35,7 @@ const conf = {
35
35
 
36
36
  const handler = function ({ json }) {
37
37
  return {
38
- onRefresh(refresh) {
38
+ onAccountRefresh(refresh) {
39
39
  if (!json) {
40
40
  // log.p("Checking login...");
41
41
  }
package/package.json CHANGED
@@ -15,6 +15,8 @@
15
15
  "@inquirer/prompts": "^8.5.2",
16
16
  "adm-zip": "^0.5.16",
17
17
  "chalk": "^4.1.2",
18
+ "cli-progress": "^3.12.0",
19
+ "cli-spinner": "^0.2.10",
18
20
  "degit": "^2.8.6",
19
21
  "dompurify": "^3.3.1",
20
22
  "dot-prop": "^6.0.1",
@@ -26,6 +28,7 @@
26
28
  "mp4box": "^2.3.0",
27
29
  "open": "^8.4.2",
28
30
  "pretty-toml": "^1.0.0",
31
+ "qrcode-terminal": "^0.12.0",
29
32
  "rc": "^1.2.8",
30
33
  "semver": "^7.7.3",
31
34
  "yargs": "^17.7.2",
@@ -53,5 +56,5 @@
53
56
  "license": "Apache-2.0",
54
57
  "main": "./src/cli/index.js",
55
58
  "name": "arcadible",
56
- "version": "0.1.13"
59
+ "version": "0.1.14"
57
60
  }
package/src/account.js CHANGED
@@ -62,7 +62,7 @@ const refresh = function ({ session, ...account }) {
62
62
 
63
63
  // [function]
64
64
 
65
- const get = function ({ onRefresh }) {
65
+ const get = function (onRefresh) {
66
66
  return readFile(file, "utf8")
67
67
  .then(JSON.parse)
68
68
  .catch((ex) => {
@@ -76,7 +76,9 @@ const get = function ({ onRefresh }) {
76
76
  return null;
77
77
  }
78
78
  return expired(account.session)
79
- ? onRefresh((renew) => (renew ? refresh(account) : null))
79
+ ? (onRefresh &&
80
+ onRefresh((renew) => (renew ? refresh(account) : null))) ||
81
+ null
80
82
  : account;
81
83
  });
82
84
  };
@@ -17,7 +17,6 @@ const project = require("../../parser/project");
17
17
 
18
18
  const exec = cp.exec;
19
19
  const pathExists = fs.pathExists;
20
- const remove = fs.remove;
21
20
  const resolvePath = path.resolve;
22
21
 
23
22
  // [function]
@@ -38,8 +37,7 @@ const execBuild = function (command, { cwdPath }) {
38
37
 
39
38
  const build = function (command, { cwdPath, outputPath }) {
40
39
  return command
41
- ? remove(outputPath)
42
- .then(() => execBuild(command, { cwdPath }))
40
+ ? execBuild(command, { cwdPath })
43
41
  .then(() => pathExists(outputPath))
44
42
  .then((exists) => (exists ? { path: outputPath } : null))
45
43
  : Promise.resolve(null);
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const api = require("../../api");
6
+ const phrase = require("../../phrase");
7
+ const s3 = require("../../util/s3");
8
+
9
+ // [function]
10
+
11
+ const ensureBuild = function (token, { id, version }, cb) {
12
+ return api.getGameBuild(id, version, { token }).then(
13
+ () => cb(new Error(phrase.versionExists(version))),
14
+ (err) => {
15
+ if (err.status === 404) {
16
+ cb(null);
17
+ return;
18
+ }
19
+ cb(err);
20
+ },
21
+ );
22
+ };
23
+
24
+ // [function]
25
+
26
+ const uploadBuild = function (
27
+ token,
28
+ artifact,
29
+ { id, version },
30
+ onUploadProgress,
31
+ cb,
32
+ ) {
33
+ const form = new FormData();
34
+ form.append("artifact", id);
35
+ form.append("version", version);
36
+ form.append("sha256", artifact.sha256);
37
+ form.append("size", artifact.size);
38
+ return api.postUpload(form, { token }).then((upload) => {
39
+ s3.upload(upload.upload_url, artifact, onUploadProgress, cb);
40
+ }, cb);
41
+ };
42
+
43
+ // [function]
44
+
45
+ const release = function (session, artifact, game, onUploadProgress, cb) {
46
+ const token = session.access_token;
47
+ ensureBuild(token, game, (err) => {
48
+ if (err) {
49
+ cb(err);
50
+ return;
51
+ }
52
+ uploadBuild(token, artifact, game, onUploadProgress, cb);
53
+ });
54
+ };
55
+
56
+ // [export]
57
+
58
+ module.exports = { release };
@@ -35,7 +35,7 @@ const ensureRepo = function (root, cb) {
35
35
  cb(new Error(phrase.gitRepoMissing(), { cause: err }));
36
36
  return;
37
37
  }
38
- cb();
38
+ cb(null);
39
39
  });
40
40
  };
41
41
 
@@ -47,7 +47,7 @@ const ensureRemote = function (root, cb) {
47
47
  cb(new Error(phrase.gitRemoteMissing(), { cause: err }));
48
48
  return;
49
49
  }
50
- cb();
50
+ cb(null);
51
51
  });
52
52
  };
53
53
 
@@ -96,7 +96,7 @@ const createTag = function (root, version, cb) {
96
96
  cb(new Error(phrase.gitTagCreateFailed(), { cause: err }));
97
97
  return;
98
98
  }
99
- cb();
99
+ cb(null);
100
100
  },
101
101
  );
102
102
  };
@@ -109,7 +109,7 @@ const pushTag = function (root, version, cb) {
109
109
  cb(new Error(phrase.gitTagPushFailed(), { cause: err }));
110
110
  return;
111
111
  }
112
- cb();
112
+ cb(null);
113
113
  });
114
114
  };
115
115
 
@@ -26,7 +26,7 @@ const deployRelease = function (version, { root }, handler, cb) {
26
26
 
27
27
  // [function]
28
28
 
29
- const deployEnsure = function ({ root }, { onInfo }, cb) {
29
+ const deployEnsure = function ({ root }, { onLogInfo }, cb) {
30
30
  ensureRepo(root, (err) => {
31
31
  if (err) {
32
32
  cb(err);
@@ -37,8 +37,8 @@ const deployEnsure = function ({ root }, { onInfo }, cb) {
37
37
  cb(err);
38
38
  return;
39
39
  }
40
- if (diff.cached) {
41
- onInfo({
40
+ if (diff.cached && onLogInfo) {
41
+ onLogInfo({
42
42
  level: "warn",
43
43
  message: "Staged but uncommitted changes will not be included.",
44
44
  });
@@ -50,7 +50,7 @@ const deployEnsure = function ({ root }, { onInfo }, cb) {
50
50
 
51
51
  // [function]
52
52
 
53
- const deploy = function (version, { root }, handler, cb) {
53
+ const deploy = function ({ version }, { root }, handler, cb) {
54
54
  deployEnsure({ root }, handler, (err) => {
55
55
  if (err) {
56
56
  cb(err);
@@ -62,12 +62,14 @@ const deploy = function (version, { root }, handler, cb) {
62
62
 
63
63
  // [function]
64
64
 
65
- const main = function ({ root }, { onBegin, ...handler }) {
66
- onBegin({ root });
65
+ const main = function ({ root }, { onDeployBegin, ...handler }) {
66
+ if (onDeployBegin) {
67
+ onDeployBegin({ root });
68
+ }
67
69
  return project(root).then(
68
70
  ({ game }) =>
69
71
  new Promise((resolve, reject) => {
70
- deploy(game.version, { root }, handler, (err, data) => {
72
+ deploy(game, { root }, handler, (err, data) => {
71
73
  if (err) {
72
74
  reject(err);
73
75
  return;
@@ -1,9 +1,61 @@
1
1
  "use strict";
2
2
 
3
+ // [import]
4
+
5
+ const ac = require("./ac");
6
+ const project = require("../../parser/project");
7
+
8
+ // [use]
9
+
10
+ const release = ac.release;
11
+
12
+ // [function]
13
+
14
+ const deployRelease = function (
15
+ session,
16
+ artifact,
17
+ game,
18
+ { onUploadProgress },
19
+ cb,
20
+ ) {
21
+ release(session, artifact, game, onUploadProgress, (err) => {
22
+ if (err) {
23
+ cb(err);
24
+ return;
25
+ }
26
+ cb(null, { to: game.version });
27
+ });
28
+ };
29
+
30
+ // [function]
31
+
32
+ const deploy = function (session, artifact, game, handler, cb) {
33
+ deployRelease(session, artifact, game, handler, cb);
34
+ };
35
+
3
36
  // [function]
4
37
 
5
- const main = function () {
6
- return Promise.reject(new Error("Unimplemented command."));
38
+ const main = function (
39
+ session,
40
+ artifact,
41
+ { root },
42
+ { onDeployBegin, ...handler },
43
+ ) {
44
+ if (onDeployBegin) {
45
+ onDeployBegin({ root });
46
+ }
47
+ return project(root).then(
48
+ ({ game }) =>
49
+ new Promise((resolve, reject) => {
50
+ deploy(session, artifact, game, handler, (err, data) => {
51
+ if (err) {
52
+ reject(err);
53
+ return;
54
+ }
55
+ resolve(data);
56
+ });
57
+ }),
58
+ );
7
59
  };
8
60
 
9
61
  // [export]
@@ -6,11 +6,17 @@ const path = require("node:path");
6
6
 
7
7
  // [import]
8
8
 
9
+ const fs = require("fs-extra");
10
+
11
+ // [import]
12
+
9
13
  const env = require("../../parser/env");
10
14
  const manifest = require("./manifest");
15
+ const phrase = require("../../phrase");
11
16
 
12
17
  // [use]
13
18
 
19
+ const pathExists = fs.pathExists;
14
20
  const prepare = manifest.prepare;
15
21
  const resolve = path.resolve;
16
22
 
@@ -22,12 +28,26 @@ const detectVersion = function (dest) {
22
28
 
23
29
  // [function]
24
30
 
25
- const init = function () {
31
+ const scaffold = function (src, dest, { onInitBegin }) {
32
+ if (onInitBegin) {
33
+ onInitBegin({ dest, src });
34
+ }
26
35
  return Promise.resolve();
27
36
  };
28
37
 
29
38
  // [function]
30
39
 
40
+ const init = function (dest, { force, template }, handler) {
41
+ return pathExists(dest).then((exists) => {
42
+ if (exists && !force) {
43
+ throw new Error(phrase.overwriteWithForce());
44
+ }
45
+ return scaffold(template, dest, handler);
46
+ });
47
+ };
48
+
49
+ // [function]
50
+
31
51
  const main = function ({ force, project, root, template }, handler) {
32
52
  const dest = resolve(root, project);
33
53
  return init(dest, { force, template }, handler)
@@ -41,10 +41,16 @@ const detectVersion = function (dest) {
41
41
 
42
42
  // [function]
43
43
 
44
- const scaffold = function (src, dest, { onBegin, onInfo }) {
45
- onBegin({ dest, src });
44
+ const scaffold = function (src, dest, { onInitBegin, onLogInfo }) {
45
+ if (onInitBegin) {
46
+ onInitBegin({ dest, src });
47
+ }
46
48
  return degit(src, { cache: false, force: true, verbose: false })
47
- .on("info", onInfo)
49
+ .on("info", ({ message }) => {
50
+ if (onLogInfo) {
51
+ onLogInfo({ message });
52
+ }
53
+ })
48
54
  .clone(dest);
49
55
  };
50
56
 
@@ -29,26 +29,26 @@ const POLL = {
29
29
 
30
30
  // [function]
31
31
 
32
- const postFlow = function ({ expiresAt, token, type }) {
32
+ const postFlow = function ({ expiresAt, secret, type }) {
33
33
  const form = new FormData();
34
34
  form.append("expires_at", expiresAt.toISOString());
35
- form.append("token", token);
35
+ form.append("secret", secret);
36
36
  form.append("type", type);
37
37
  return api.postFlow(form);
38
38
  };
39
39
 
40
40
  // [function]
41
41
 
42
- const getFlow = function ({ id, token }) {
43
- return api.getFlow(id, { token });
42
+ const getFlow = function ({ id, secret }) {
43
+ return api.getFlow(id, { token: secret });
44
44
  };
45
45
 
46
46
  // [function]
47
47
 
48
- const createFlow = function ({ expiresAt, token, type }, onCreated) {
49
- return postFlow({ expiresAt, token, type }).then(({ code, id }) => {
50
- if (onCreated) {
51
- onCreated({ code, url: cfgurl.LINK });
48
+ const createFlow = function ({ expiresAt, secret, type }, onLoginCreated) {
49
+ return postFlow({ expiresAt, secret, type }).then(({ code, id }) => {
50
+ if (onLoginCreated) {
51
+ onLoginCreated({ code, id, url: cfgurl.LINK });
52
52
  }
53
53
  return { id };
54
54
  });
@@ -56,10 +56,10 @@ const createFlow = function ({ expiresAt, token, type }, onCreated) {
56
56
 
57
57
  // [function]
58
58
 
59
- const pollFlow = function ({ id, token }, onPoll) {
60
- return getFlow({ id, token }).then(({ data, status }) => {
61
- if (onPoll) {
62
- onPoll({ status });
59
+ const pollFlow = function ({ id, secret }, onLoginPoll) {
60
+ return getFlow({ id, secret }).then(({ data, status }) => {
61
+ if (onLoginPoll) {
62
+ onLoginPoll({ status });
63
63
  }
64
64
  switch (status) {
65
65
  case "pending":
@@ -76,21 +76,21 @@ const pollFlow = function ({ id, token }, onPoll) {
76
76
 
77
77
  // [function]
78
78
 
79
- const main = function ({ onCreated, onPoll }) {
79
+ const main = function ({ onLoginCreated, onLoginPoll }) {
80
80
  const expiresAt = new Date(Date.now() + time.m(5));
81
- const token = randomUUID();
81
+ const secret = randomUUID();
82
82
  return createFlow(
83
83
  {
84
84
  expiresAt,
85
- token,
85
+ secret,
86
86
  type: "cli-login",
87
87
  },
88
- onCreated,
88
+ onLoginCreated,
89
89
  ).then(({ id }) => {
90
90
  const timeout = Math.max(0, expiresAt.getTime() - Date.now() - time.s(15));
91
91
  return poll(
92
- (flow) => pollFlow(flow, onPoll),
93
- { id, token },
92
+ (flow) => pollFlow(flow, onLoginPoll),
93
+ { id, secret },
94
94
  { ...POLL, timeout },
95
95
  );
96
96
  });
@@ -41,7 +41,7 @@ const verifyPartial = function (zip) {
41
41
  }
42
42
  if (zip.stat().size > SIZE_PARTIAL) {
43
43
  const max = SIZE_PARTIAL / 1024 / 1024;
44
- throw new Error(phrase.packageTooLarge(false, max));
44
+ throw new Error(phrase.packageTooLarge(max, false));
45
45
  }
46
46
  return zip;
47
47
  };
@@ -51,7 +51,7 @@ const verifyPartial = function (zip) {
51
51
  const verifyTotal = function (zip) {
52
52
  if (zip.stat().size > SIZE_TOTAL) {
53
53
  const max = SIZE_TOTAL / 1024 / 1024;
54
- throw new Error(phrase.packageTooLarge(true, max));
54
+ throw new Error(phrase.packageTooLarge(max, true));
55
55
  }
56
56
  return zip;
57
57
  };
@@ -61,8 +61,8 @@ const verifyTotal = function (zip) {
61
61
  const pack = function (name, game, { inputPath, mediaPath, outputPath }) {
62
62
  const zip = new Zip(name);
63
63
  return pathExists(inputPath)
64
- .then((existsDeploy) => {
65
- if (existsDeploy) {
64
+ .then((existsInput) => {
65
+ if (existsInput) {
66
66
  zip.addDir(inputPath);
67
67
  }
68
68
  return zip;
@@ -6,8 +6,8 @@ const account = require("../../account");
6
6
 
7
7
  // [function]
8
8
 
9
- const main = function (conf, handler) {
10
- return account.get(handler);
9
+ const main = function (conf, { onAccountRefresh }) {
10
+ return account.get(onAccountRefresh);
11
11
  };
12
12
 
13
13
  // [export]
package/src/api.js CHANGED
@@ -24,8 +24,14 @@ const authRefresh = function (form, options) {
24
24
 
25
25
  // [function]
26
26
 
27
- const getFlow = function (id, options) {
28
- return request.get(endpoint(`/flows/${id}`), options);
27
+ const getFlow = function (flow, options) {
28
+ return request.get(endpoint(`/flows/${flow}`), options);
29
+ };
30
+
31
+ // [function]
32
+
33
+ const getGameBuild = function (game, version, options) {
34
+ return request.get(endpoint(`/games/${game}/builds/${version}`), options);
29
35
  };
30
36
 
31
37
  // [function]
@@ -42,4 +48,4 @@ const postUpload = function (form, options) {
42
48
 
43
49
  // [export]
44
50
 
45
- module.exports = { authRefresh, getFlow, postFlow, postUpload };
51
+ module.exports = { authRefresh, getFlow, getGameBuild, postFlow, postUpload };
package/src/phrase.js CHANGED
@@ -90,7 +90,7 @@ const overwriteWithForce = function () {
90
90
  // [function]
91
91
 
92
92
  const packageFileMissing = function (file) {
93
- return `Package is missing "${file}".`;
93
+ return `Package is missing '${file}'.`;
94
94
  };
95
95
 
96
96
  // [function]
@@ -111,6 +111,18 @@ const unableToParse = function (file, message) {
111
111
  return `Unable to parse ${file}: ${message}`;
112
112
  };
113
113
 
114
+ // [function]
115
+
116
+ const uploadFailed = function (status) {
117
+ return `Upload failed with status ${status}.`;
118
+ };
119
+
120
+ // [function]
121
+
122
+ const versionExists = function (version) {
123
+ return `Version 'v${version}' already exists.`;
124
+ };
125
+
114
126
  // [export]
115
127
 
116
128
  module.exports = {
@@ -130,4 +142,6 @@ module.exports = {
130
142
  packageTooLarge,
131
143
  timedOut,
132
144
  unableToParse,
145
+ uploadFailed,
146
+ versionExists,
133
147
  };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ // [class]
4
+
5
+ const HttpError = class extends Error {
6
+
7
+ // [constructor]
8
+
9
+ constructor(status, message) {
10
+ super(message);
11
+ this.name = "HttpError";
12
+ this.status = status;
13
+ }
14
+ };
15
+
16
+ // [export]
17
+
18
+ module.exports = { HttpError };
package/src/util/log.js CHANGED
@@ -19,7 +19,7 @@ const log = function (
19
19
  if (bold) {
20
20
  marker = chalk.bold;
21
21
  }
22
- out(marker[color](text.trim().concat(nl ? "\n" : "")));
22
+ out(marker[color]((nl ? "\n" : "").concat(text.trim())));
23
23
  };
24
24
 
25
25
  // [function]
@@ -30,7 +30,7 @@ const h = function (message) {
30
30
 
31
31
  // [function]
32
32
 
33
- const hnl = function (message) {
33
+ const nlh = function (message) {
34
34
  log(console.log, message, { bold: true, nl: true });
35
35
  };
36
36
 
@@ -42,7 +42,7 @@ const p = function (message) {
42
42
 
43
43
  // [function]
44
44
 
45
- const pnl = function (message) {
45
+ const nlp = function (message) {
46
46
  log(console.log, message, { nl: true });
47
47
  };
48
48
 
@@ -54,7 +54,7 @@ const hd = function (message) {
54
54
 
55
55
  // [function]
56
56
 
57
- const hdnl = function (message) {
57
+ const nlhd = function (message) {
58
58
  log(console.error, message, { bold: true, color: "red", nl: true });
59
59
  };
60
60
 
@@ -66,7 +66,7 @@ const pd = function (message) {
66
66
 
67
67
  // [function]
68
68
 
69
- const pdnl = function (message) {
69
+ const nlpd = function (message) {
70
70
  log(console.error, message, { color: "red", nl: true });
71
71
  };
72
72
 
@@ -78,7 +78,7 @@ const hw = function (message) {
78
78
 
79
79
  // [function]
80
80
 
81
- const hwnl = function (message) {
81
+ const nlhw = function (message) {
82
82
  log(console.warn, message, { bold: true, color: "yellow", nl: true });
83
83
  };
84
84
 
@@ -90,7 +90,7 @@ const pw = function (message) {
90
90
 
91
91
  // [function]
92
92
 
93
- const pwnl = function (message) {
93
+ const nlpw = function (message) {
94
94
  log(console.warn, message, { color: "yellow", nl: true });
95
95
  };
96
96
 
@@ -102,7 +102,7 @@ const hs = function (message) {
102
102
 
103
103
  // [function]
104
104
 
105
- const hsnl = function (message) {
105
+ const nlhs = function (message) {
106
106
  log(console.log, message, { bold: true, color: "green", nl: true });
107
107
  };
108
108
 
@@ -114,7 +114,7 @@ const ps = function (message) {
114
114
 
115
115
  // [function]
116
116
 
117
- const psnl = function (message) {
117
+ const nlps = function (message) {
118
118
  log(console.log, message, { color: "green", nl: true });
119
119
  };
120
120
 
@@ -123,18 +123,18 @@ const psnl = function (message) {
123
123
  module.exports = {
124
124
  h,
125
125
  hd,
126
- hdnl,
127
- hnl,
128
126
  hs,
129
- hsnl,
130
127
  hw,
131
- hwnl,
128
+ nlh,
129
+ nlhd,
130
+ nlhs,
131
+ nlhw,
132
+ nlp,
133
+ nlpd,
134
+ nlps,
135
+ nlpw,
132
136
  p,
133
137
  pd,
134
- pdnl,
135
- pnl,
136
138
  ps,
137
- psnl,
138
139
  pw,
139
- pwnl,
140
140
  };
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const cliProgress = require("cli-progress");
6
+
7
+ // [use]
8
+
9
+ const Presets = cliProgress.Presets;
10
+ const SingleBar = cliProgress.SingleBar;
11
+
12
+ // [declare]
13
+
14
+ const FORMAT = "[{bar}] {percentage}% | {value}/{total}";
15
+
16
+ // [function]
17
+
18
+ const formatBytes = function (bytes) {
19
+ switch (true) {
20
+ case bytes < 1000:
21
+ return `${bytes} B`;
22
+ case bytes < 1000 * 1000:
23
+ return `${(bytes / 1000).toFixed(1)} KB`;
24
+ case bytes < 1000 * 1000 * 1000:
25
+ return `${(bytes / 1000 / 1000).toFixed(1)} MB`;
26
+ default:
27
+ return `${(bytes / 1000 / 1000 / 1000).toFixed(1)} GB`;
28
+ }
29
+ };
30
+
31
+ // [function]
32
+
33
+ const formatValue = function (value, options, type) {
34
+ if (type === "percentage") {
35
+ return value;
36
+ }
37
+ return formatBytes(value);
38
+ };
39
+
40
+ // [function]
41
+
42
+ const singleBar = function (format) {
43
+ return new SingleBar({ format, formatValue }, Presets.shades_classic);
44
+ };
45
+
46
+ // [class]
47
+
48
+ const ProgressBar = class {
49
+
50
+ // [constructor]
51
+
52
+ constructor(total, format = FORMAT) {
53
+ this.bar = singleBar(format);
54
+ this.total = total;
55
+ }
56
+
57
+ // [method]
58
+
59
+ increment(step) {
60
+ this.bar.increment(step);
61
+ return this;
62
+ }
63
+
64
+ // [method]
65
+
66
+ start(start) {
67
+ this.bar.start(this.total, start);
68
+ return this;
69
+ }
70
+
71
+ // [method]
72
+
73
+ stop() {
74
+ this.bar.stop();
75
+ return this;
76
+ }
77
+ };
78
+
79
+ // [export]
80
+
81
+ module.exports = { ProgressBar };
@@ -2,8 +2,13 @@
2
2
 
3
3
  // [import]
4
4
 
5
+ const http = require("./http");
5
6
  const pkg = require("../../package.json");
6
7
 
8
+ // [use]
9
+
10
+ const HttpError = http.HttpError;
11
+
7
12
  // [declare]
8
13
 
9
14
  const CLIENT_ID = "cli";
@@ -14,7 +19,7 @@ const CLIENT_VERSION = pkg.version;
14
19
  const parse = function (resp) {
15
20
  return resp.json().then((json) => {
16
21
  if (!resp.ok) {
17
- throw new Error(json.data.message);
22
+ throw new HttpError(resp.status, json.data.message);
18
23
  }
19
24
  return json.data;
20
25
  });
package/src/util/s3.js CHANGED
@@ -1 +1,56 @@
1
1
  "use strict";
2
+
3
+ // [import]
4
+
5
+ const fs = require("node:fs");
6
+ const https = require("node:https");
7
+
8
+ // [import]
9
+
10
+ const phrase = require("../phrase");
11
+
12
+ // [use]
13
+
14
+ const createReadStream = fs.createReadStream;
15
+ const request = https.request;
16
+
17
+ // [function]
18
+
19
+ const requestOptions = function (size) {
20
+ return {
21
+ headers: {
22
+ "Content-Length": size,
23
+ "Content-Type": "application/zip",
24
+ },
25
+ method: "PUT",
26
+ };
27
+ };
28
+
29
+ // [function]
30
+
31
+ const upload = function (url, { path, size }, onProgress, cb) {
32
+ const req = request(url, requestOptions(size), (resp) => {
33
+ resp.resume();
34
+ const status = resp.statusCode;
35
+ if (status >= 200 && status < 300) {
36
+ cb(null);
37
+ return;
38
+ }
39
+ cb(new Error(phrase.uploadFailed(status)));
40
+ });
41
+ req.on("error", cb);
42
+ createReadStream(path)
43
+ .on("data", (chunk) => {
44
+ if (onProgress) {
45
+ onProgress(chunk.length);
46
+ }
47
+ })
48
+ .on("error", (err) => {
49
+ req.destroy(err);
50
+ })
51
+ .pipe(req);
52
+ };
53
+
54
+ // [export]
55
+
56
+ module.exports = { upload };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const cliSpinner = require("cli-spinner");
6
+
7
+ // [use]
8
+
9
+ const Spinner = cliSpinner.Spinner;
10
+
11
+ // [class]
12
+
13
+ const SpinnerWheel = class {
14
+
15
+ // [constructor]
16
+
17
+ constructor(text) {
18
+ this.wheel = new Spinner(text);
19
+ this.wheel.setSpinnerString(2);
20
+ }
21
+
22
+ // [method]
23
+
24
+ start(quiet) {
25
+ if (!quiet) {
26
+ this.wheel.start();
27
+ }
28
+ return this;
29
+ }
30
+
31
+ // [method]
32
+
33
+ stop(clear) {
34
+ this.wheel.stop(clear);
35
+ return this;
36
+ }
37
+ };
38
+
39
+ // [export]
40
+
41
+ module.exports = { SpinnerWheel };
package/src/util/video.js CHANGED
@@ -48,7 +48,7 @@ const readMp4 = function (file) {
48
48
  const mp4 = createFile();
49
49
  let error = null;
50
50
  let video = null;
51
- mp4.onReady = function (info) {
51
+ mp4.onReady = (info) => {
52
52
  const track = info.tracks.find((t) => t.video);
53
53
  if (!track || !track.video) {
54
54
  error = new Error(phrase.noVideoTrack());
@@ -60,7 +60,7 @@ const readMp4 = function (file) {
60
60
  width: track.video.width,
61
61
  };
62
62
  };
63
- mp4.onError = function (mod, msg) {
63
+ mp4.onError = (mod, msg) => {
64
64
  error = new Error(msg);
65
65
  };
66
66
  const buffer = data.buffer.slice(
package/src/artifact.js DELETED
@@ -1 +0,0 @@
1
- "use strict";