arcadible 0.1.12 → 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.
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const cp = require("node:child_process");
6
+ const path = require("node:path");
7
+
8
+ // [import]
9
+
10
+ const fs = require("fs-extra");
11
+
12
+ // [import]
13
+
14
+ const project = require("../../parser/project");
15
+
16
+ // [use]
17
+
18
+ const exec = cp.exec;
19
+ const pathExists = fs.pathExists;
20
+ const resolvePath = path.resolve;
21
+
22
+ // [function]
23
+
24
+ const execBuild = function (command, { cwdPath }) {
25
+ return new Promise((resolve, reject) => {
26
+ exec(command, { cwd: cwdPath }, (err) => {
27
+ if (err) {
28
+ reject(err);
29
+ return;
30
+ }
31
+ resolve();
32
+ });
33
+ });
34
+ };
35
+
36
+ // [function]
37
+
38
+ const build = function (command, { cwdPath, outputPath }) {
39
+ return command
40
+ ? execBuild(command, { cwdPath })
41
+ .then(() => pathExists(outputPath))
42
+ .then((exists) => (exists ? { path: outputPath } : null))
43
+ : Promise.resolve(null);
44
+ };
45
+
46
+ // [function]
47
+
48
+ const main = function ({ root }) {
49
+ return project(root).then(({ workflow }) => {
50
+ const command = workflow.build;
51
+ return build(
52
+ Array.isArray(command)
53
+ ? command
54
+ .map((cmd) => cmd.trim())
55
+ .filter(Boolean)
56
+ .join(" && ")
57
+ : command.trim(),
58
+ {
59
+ cwdPath: root,
60
+ outputPath: resolvePath(root, workflow.deploy_dir),
61
+ },
62
+ );
63
+ });
64
+ };
65
+
66
+ // [export]
67
+
68
+ module.exports = main;
@@ -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 };
@@ -8,6 +8,10 @@ const cp = require("node:child_process");
8
8
 
9
9
  const semver = require("semver");
10
10
 
11
+ // [import]
12
+
13
+ const phrase = require("../../phrase");
14
+
11
15
  // [use]
12
16
 
13
17
  const execFile = cp.execFile;
@@ -26,46 +30,34 @@ const git = function (root, args, cb) {
26
30
  // [function]
27
31
 
28
32
  const ensureRepo = function (root, cb) {
29
- const message = [
30
- "Unable to find a Git repository.",
31
- "Ensure you are in a Git repository, or create one before continuing.",
32
- ];
33
33
  git(root, ["rev-parse", "--is-inside-work-tree"], (err) => {
34
34
  if (err) {
35
- cb(new Error(message.join("\n"), { cause: err }));
35
+ cb(new Error(phrase.gitRepoMissing(), { cause: err }));
36
36
  return;
37
37
  }
38
- cb();
38
+ cb(null);
39
39
  });
40
40
  };
41
41
 
42
42
  // [function]
43
43
 
44
44
  const ensureRemote = function (root, cb) {
45
- const message = [
46
- "Unable to access Git remote 'origin'.",
47
- "Ensure the remote 'origin' exists and you have permission to access it.",
48
- ];
49
45
  git(root, ["ls-remote", "origin"], (err) => {
50
46
  if (err) {
51
- cb(new Error(message.join("\n"), { cause: err }));
47
+ cb(new Error(phrase.gitRemoteMissing(), { cause: err }));
52
48
  return;
53
49
  }
54
- cb();
50
+ cb(null);
55
51
  });
56
52
  };
57
53
 
58
54
  // [function]
59
55
 
60
56
  const ensureClean = function (root, cb) {
61
- const message = [
62
- "Unable to continue with Git changes present.",
63
- "Ensure all changes are staged, committed, or discarded before continuing.",
64
- ];
65
57
  git(root, ["diff", "--quiet"], (err) => {
66
58
  if (err) {
67
59
  if (err.code === 1) {
68
- cb(new Error(message.join("\n"), { cause: err }));
60
+ cb(new Error(phrase.gitChangesPresent(), { cause: err }));
69
61
  return;
70
62
  }
71
63
  cb(err);
@@ -88,10 +80,6 @@ const ensureClean = function (root, cb) {
88
80
  // [function]
89
81
 
90
82
  const createTag = function (root, version, cb) {
91
- const message = [
92
- "Unable to create Git tag.",
93
- "Ensure the release tag does not already exist locally.",
94
- ];
95
83
  git(
96
84
  root,
97
85
  [
@@ -105,10 +93,10 @@ const createTag = function (root, version, cb) {
105
93
  ],
106
94
  (err) => {
107
95
  if (err) {
108
- cb(new Error(message.join("\n"), { cause: err }));
96
+ cb(new Error(phrase.gitTagCreateFailed(), { cause: err }));
109
97
  return;
110
98
  }
111
- cb();
99
+ cb(null);
112
100
  },
113
101
  );
114
102
  };
@@ -116,16 +104,12 @@ const createTag = function (root, version, cb) {
116
104
  // [function]
117
105
 
118
106
  const pushTag = function (root, version, cb) {
119
- const message = [
120
- "Unable to push Git tag.",
121
- "Ensure the release tag does not already exist on remote 'origin'.",
122
- ];
123
107
  git(root, ["push", "origin", `${PREFIX}${version}`], (err) => {
124
108
  if (err) {
125
- cb(new Error(message.join("\n"), { cause: err }));
109
+ cb(new Error(phrase.gitTagPushFailed(), { cause: err }));
126
110
  return;
127
111
  }
128
- cb();
112
+ cb(null);
129
113
  });
130
114
  };
131
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]
@@ -11,6 +11,7 @@ const fs = require("fs-extra");
11
11
 
12
12
  // [import]
13
13
 
14
+ const phrase = require("../../phrase");
14
15
  const TOML = require("../../util/toml");
15
16
 
16
17
  // [use]
@@ -31,9 +32,7 @@ const parseToml = function (buf) {
31
32
  try {
32
33
  return TOML.parse(buf);
33
34
  } catch (ex) {
34
- throw new Error(`Unable to parse ${MANIFEST}: ${ex.message}`, {
35
- cause: ex,
36
- });
35
+ throw new Error(phrase.unableToParse(MANIFEST, ex.message), { cause: ex });
37
36
  }
38
37
  };
39
38
 
@@ -6,28 +6,48 @@ 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
 
17
23
  // [function]
18
24
 
19
- const detectVersion = function (root) {
20
- return env(root).then(({ game }) => game?.version ?? null);
25
+ const detectVersion = function (dest) {
26
+ return env(dest).then(({ game }) => game?.version ?? null);
21
27
  };
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)
@@ -13,6 +13,7 @@ const fs = require("fs-extra");
13
13
 
14
14
  const env = require("../../parser/env");
15
15
  const manifest = require("./manifest");
16
+ const phrase = require("../../phrase");
16
17
 
17
18
  // [use]
18
19
 
@@ -34,16 +35,22 @@ const removeLicense = function (dest) {
34
35
 
35
36
  // [function]
36
37
 
37
- const detectVersion = function (root) {
38
- return env(root).then(({ game }) => game?.version ?? null);
38
+ const detectVersion = function (dest) {
39
+ return env(dest).then(({ game }) => game?.version ?? null);
39
40
  };
40
41
 
41
42
  // [function]
42
43
 
43
- const scaffold = function (src, dest, { onBegin, onInfo }) {
44
- onBegin({ dest, src });
44
+ const scaffold = function (src, dest, { onInitBegin, onLogInfo }) {
45
+ if (onInitBegin) {
46
+ onInitBegin({ dest, src });
47
+ }
45
48
  return degit(src, { cache: false, force: true, verbose: false })
46
- .on("info", onInfo)
49
+ .on("info", ({ message }) => {
50
+ if (onLogInfo) {
51
+ onLogInfo({ message });
52
+ }
53
+ })
47
54
  .clone(dest);
48
55
  };
49
56
 
@@ -52,7 +59,7 @@ const scaffold = function (src, dest, { onBegin, onInfo }) {
52
59
  const init = function (dest, { force, template }, handler) {
53
60
  return pathExists(dest).then((exists) => {
54
61
  if (exists && !force) {
55
- throw new Error("Directory already exists (overwrite with `--force`).");
62
+ throw new Error(phrase.overwriteWithForce());
56
63
  }
57
64
  return scaffold(template, dest, handler);
58
65
  });
@@ -9,6 +9,7 @@ const crypto = require("node:crypto");
9
9
  const api = require("../../api");
10
10
  const cfgurl = require("../../config/url");
11
11
  const delay = require("../../util/delay");
12
+ const phrase = require("../../phrase");
12
13
  const time = require("../../util/time");
13
14
 
14
15
  // [use]
@@ -23,31 +24,31 @@ const POLL = {
23
24
  factor: 2,
24
25
  interval: time.s(30),
25
26
  maxDelay: time.s(15),
26
- timeoutError: "Login request expired.",
27
+ timeoutError: phrase.loginExpired(),
27
28
  };
28
29
 
29
30
  // [function]
30
31
 
31
- const postFlow = function ({ expiresAt, token, type }) {
32
+ const postFlow = function ({ expiresAt, secret, type }) {
32
33
  const form = new FormData();
33
34
  form.append("expires_at", expiresAt.toISOString());
34
- form.append("token", token);
35
+ form.append("secret", secret);
35
36
  form.append("type", type);
36
37
  return api.postFlow(form);
37
38
  };
38
39
 
39
40
  // [function]
40
41
 
41
- const getFlow = function ({ id, token }) {
42
- return api.getFlow(id, { token });
42
+ const getFlow = function ({ id, secret }) {
43
+ return api.getFlow(id, { token: secret });
43
44
  };
44
45
 
45
46
  // [function]
46
47
 
47
- const createFlow = function ({ expiresAt, token, type }, onCreated) {
48
- return postFlow({ expiresAt, token, type }).then(({ code, id }) => {
49
- if (onCreated) {
50
- 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 });
51
52
  }
52
53
  return { id };
53
54
  });
@@ -55,10 +56,10 @@ const createFlow = function ({ expiresAt, token, type }, onCreated) {
55
56
 
56
57
  // [function]
57
58
 
58
- const pollFlow = function ({ id, token }, onPoll) {
59
- return getFlow({ id, token }).then(({ data, status }) => {
60
- if (onPoll) {
61
- onPoll({ status });
59
+ const pollFlow = function ({ id, secret }, onLoginPoll) {
60
+ return getFlow({ id, secret }).then(({ data, status }) => {
61
+ if (onLoginPoll) {
62
+ onLoginPoll({ status });
62
63
  }
63
64
  switch (status) {
64
65
  case "pending":
@@ -66,30 +67,30 @@ const pollFlow = function ({ id, token }, onPoll) {
66
67
  case "completed":
67
68
  return data;
68
69
  case "failed":
69
- throw new Error("Login request failed.");
70
+ throw new Error(phrase.loginFailed());
70
71
  default:
71
- throw new Error("Login request expired.");
72
+ throw new Error(phrase.loginExpired());
72
73
  }
73
74
  });
74
75
  };
75
76
 
76
77
  // [function]
77
78
 
78
- const main = function ({ onCreated, onPoll }) {
79
+ const main = function ({ onLoginCreated, onLoginPoll }) {
79
80
  const expiresAt = new Date(Date.now() + time.m(5));
80
- const token = randomUUID();
81
+ const secret = randomUUID();
81
82
  return createFlow(
82
83
  {
83
84
  expiresAt,
84
- token,
85
+ secret,
85
86
  type: "cli-login",
86
87
  },
87
- onCreated,
88
+ onLoginCreated,
88
89
  ).then(({ id }) => {
89
90
  const timeout = Math.max(0, expiresAt.getTime() - Date.now() - time.s(15));
90
91
  return poll(
91
- (flow) => pollFlow(flow, onPoll),
92
- { id, token },
92
+ (flow) => pollFlow(flow, onLoginPoll),
93
+ { id, secret },
93
94
  { ...POLL, timeout },
94
95
  );
95
96
  });
@@ -10,6 +10,7 @@ const fs = require("fs-extra");
10
10
 
11
11
  // [import]
12
12
 
13
+ const phrase = require("../../phrase");
13
14
  const project = require("../../parser/project");
14
15
  const size = require("../../util/size");
15
16
  const Zip = require("../../util/zip");
@@ -36,11 +37,11 @@ const SIZE_TOTAL = size.mb(256);
36
37
 
37
38
  const verifyPartial = function (zip) {
38
39
  if (!zip.has(MAIN)) {
39
- throw new Error(`Package is missing "${MAIN}".`);
40
+ throw new Error(phrase.packageFileMissing(MAIN));
40
41
  }
41
42
  if (zip.stat().size > SIZE_PARTIAL) {
42
43
  const max = SIZE_PARTIAL / 1024 / 1024;
43
- throw new Error(`Package size (excluding store assets) exceeds ${max} MB.`);
44
+ throw new Error(phrase.packageTooLarge(max, false));
44
45
  }
45
46
  return zip;
46
47
  };
@@ -50,19 +51,19 @@ const verifyPartial = function (zip) {
50
51
  const verifyTotal = function (zip) {
51
52
  if (zip.stat().size > SIZE_TOTAL) {
52
53
  const max = SIZE_TOTAL / 1024 / 1024;
53
- throw new Error(`Package size (including store assets) exceeds ${max} MB.`);
54
+ throw new Error(phrase.packageTooLarge(max, true));
54
55
  }
55
56
  return zip;
56
57
  };
57
58
 
58
59
  // [function]
59
60
 
60
- const pack = function (name, game, { deployPath, mediaPath, zipPath }) {
61
+ const pack = function (name, game, { inputPath, mediaPath, outputPath }) {
61
62
  const zip = new Zip(name);
62
- return pathExists(deployPath)
63
- .then((existsDeploy) => {
64
- if (existsDeploy) {
65
- zip.addDir(deployPath);
63
+ return pathExists(inputPath)
64
+ .then((existsInput) => {
65
+ if (existsInput) {
66
+ zip.addDir(inputPath);
66
67
  }
67
68
  return zip;
68
69
  })
@@ -77,21 +78,21 @@ const pack = function (name, game, { deployPath, mediaPath, zipPath }) {
77
78
  })
78
79
  .then(verifyTotal)
79
80
  .then((file) => {
80
- file.write(zipPath);
81
- return { path: zipPath, ...file.stat() };
81
+ file.write(outputPath);
82
+ return { path: outputPath, ...file.stat() };
82
83
  });
83
84
  };
84
85
 
85
86
  // [function]
86
87
 
87
- const main = function ({ output, root }) {
88
+ const main = function ({ input, output, root }) {
88
89
  return project(root).then(({ game, workflow }) => {
89
- const name = game.handle || game.id;
90
- const file = output || `${OUTPUT}/${name}-v${game.version}.zip`;
90
+ const name = game.handle ?? game.id;
91
+ const file = output ?? `${OUTPUT}/${name}-v${game.version}.zip`;
91
92
  return pack(parse(file).name, game, {
92
- deployPath: resolve(root, workflow.deploy_dir),
93
+ inputPath: resolve(root, input ?? workflow.deploy_dir),
93
94
  mediaPath: resolve(root, MEDIA),
94
- zipPath: resolve(root, file),
95
+ outputPath: resolve(root, file),
95
96
  });
96
97
  });
97
98
  };
@@ -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]
@@ -34,6 +40,12 @@ const postFlow = function (form, options) {
34
40
  return request.post(endpoint("/flows"), form, options);
35
41
  };
36
42
 
43
+ // [function]
44
+
45
+ const postUpload = function (form, options) {
46
+ return request.post(endpoint("/uploads"), form, options);
47
+ };
48
+
37
49
  // [export]
38
50
 
39
- module.exports = { authRefresh, getFlow, postFlow };
51
+ module.exports = { authRefresh, getFlow, getGameBuild, postFlow, postUpload };