arcadible 0.1.0 → 0.1.2

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.
Files changed (69) hide show
  1. package/bin/arc-default.js +32 -32
  2. package/bin/arc-deploy.js +113 -42
  3. package/bin/arc-init.js +196 -0
  4. package/bin/arc-inspect.js +65 -44
  5. package/bin/arc-login.js +127 -0
  6. package/bin/arc-logout.js +58 -0
  7. package/bin/arc-pack.js +81 -49
  8. package/bin/arc-validate.js +115 -0
  9. package/bin/arc-whoami.js +111 -0
  10. package/bin/arc.js +20 -15
  11. package/package.json +22 -9
  12. package/src/action/deploy/tool.js +11 -0
  13. package/src/action/deploy-git/git.js +192 -0
  14. package/src/action/deploy-git/tool.js +86 -0
  15. package/src/action/init/tool.js +44 -0
  16. package/src/action/inspect/tool.js +25 -0
  17. package/src/action/login/flow.js +94 -0
  18. package/src/action/login/tool.js +16 -0
  19. package/src/action/logout/tool.js +15 -0
  20. package/src/action/pack/tool.js +60 -0
  21. package/src/action/validate/tool.js +39 -0
  22. package/src/action/whoami/tool.js +15 -0
  23. package/src/api.js +39 -0
  24. package/src/cli/deploy.js +17 -0
  25. package/src/cli/index.js +25 -0
  26. package/src/cli/init.js +15 -0
  27. package/src/cli/inspect.js +15 -0
  28. package/src/cli/login.js +15 -0
  29. package/src/cli/logout.js +15 -0
  30. package/src/cli/pack.js +15 -0
  31. package/src/cli/validate.js +15 -0
  32. package/src/cli/whoami.js +15 -0
  33. package/src/config/html.js +27 -0
  34. package/src/config/uri.js +14 -0
  35. package/src/config/url.js +17 -0
  36. package/src/config/workflow.js +6 -1
  37. package/src/{manifest.js → parser/manifest.js} +5 -6
  38. package/src/{media.js → parser/media.js} +1 -1
  39. package/src/parser/pkg.js +56 -0
  40. package/src/parser/project.js +59 -0
  41. package/src/{readme.js → parser/readme.js} +25 -15
  42. package/src/prompt/project.js +10 -0
  43. package/src/prompt/starter.js +41 -0
  44. package/src/schema/game.js +38 -15
  45. package/src/schema/workflow.js +7 -5
  46. package/src/user.js +91 -0
  47. package/src/util/dom.js +10 -36
  48. package/src/util/log.js +44 -3
  49. package/src/util/md.js +2 -2
  50. package/src/util/objs.js +14 -2
  51. package/src/util/os.js +24 -0
  52. package/src/util/output.js +54 -0
  53. package/src/util/request.js +62 -0
  54. package/src/util/schema.js +25 -0
  55. package/src/util/time.js +79 -0
  56. package/bin/arc-check.js +0 -74
  57. package/npm-shrinkwrap.json +0 -988
  58. package/src/cmd/check.js +0 -26
  59. package/src/cmd/deploy.js +0 -22
  60. package/src/cmd/index.js +0 -12
  61. package/src/cmd/inspect.js +0 -26
  62. package/src/cmd/pack.js +0 -24
  63. package/src/cmd-check/index.js +0 -57
  64. package/src/cmd-deploy/index.js +0 -43
  65. package/src/cmd-inspect/index.js +0 -53
  66. package/src/cmd-pack/index.js +0 -83
  67. package/src/project.js +0 -62
  68. package/src/util/arc.js +0 -74
  69. package/src/util/git.js +0 -23
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ // [function]
4
+
5
+ const main = function () {
6
+ return Promise.reject(new Error("Unimplemented command."));
7
+ };
8
+
9
+ // [export]
10
+
11
+ module.exports = main;
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const execFile = require("node:child_process").execFile;
6
+
7
+ // [import]
8
+
9
+ const semver = require("semver");
10
+
11
+ // [import]
12
+
13
+ const strs = require("../../util/strs");
14
+
15
+ // [use]
16
+
17
+ const compareSemver = semver.compare;
18
+ const trimWhitespace = strs.trimWhitespace;
19
+ const validSemver = semver.valid;
20
+
21
+ // [declare]
22
+
23
+ const PREFIX = "arcadible/release/v";
24
+
25
+ // [function]
26
+
27
+ const git = function (root, args, cb) {
28
+ execFile("git", ["-C", root, ...args], cb);
29
+ };
30
+
31
+ // [function]
32
+
33
+ const ensureRepo = function (root, cb) {
34
+ const message = [
35
+ "Unable to find Git repository.",
36
+ "Run this command from a Git repository.",
37
+ ];
38
+ git(root, ["rev-parse", "--is-inside-work-tree"], (err) => {
39
+ if (err) {
40
+ cb(new Error(message.join("\n"), { cause: err }));
41
+ return;
42
+ }
43
+ cb();
44
+ });
45
+ };
46
+
47
+ // [function]
48
+
49
+ const ensureRemote = function (root, cb) {
50
+ const message = [
51
+ "Unable to access Git remote 'origin'.",
52
+ "Verify the remote exists and you have permission to access it.",
53
+ ];
54
+ git(root, ["ls-remote", "origin"], (err) => {
55
+ if (err) {
56
+ cb(new Error(message.join("\n"), { cause: err }));
57
+ return;
58
+ }
59
+ cb();
60
+ });
61
+ };
62
+
63
+ // [function]
64
+
65
+ const ensureClean = function (root, cb) {
66
+ const message = [
67
+ "Unable to continue with unstaged changes.",
68
+ "Stage, commit, or discard local changes before deploying.",
69
+ ];
70
+ git(root, ["diff", "--quiet"], (err) => {
71
+ if (err) {
72
+ if (err.code === 1) {
73
+ cb(new Error(message.join("\n"), { cause: err }));
74
+ return;
75
+ }
76
+ cb(err);
77
+ return;
78
+ }
79
+ git(root, ["diff", "--cached", "--quiet"], (err) => {
80
+ if (!err) {
81
+ cb(null, { cached: false });
82
+ return;
83
+ }
84
+ if (err.code === 1) {
85
+ cb(null, { cached: true });
86
+ return;
87
+ }
88
+ cb(err);
89
+ });
90
+ });
91
+ };
92
+
93
+ // [function]
94
+
95
+ const fetchTags = function (root, cb) {
96
+ const message = [
97
+ "Unable to synchronize Git release tags.",
98
+ "Run `arc deploy` again to retry with the latest release tags.",
99
+ ];
100
+ git(
101
+ root,
102
+ ["fetch", "origin", `refs/tags/${PREFIX}*:refs/tags/${PREFIX}*`],
103
+ (err) => {
104
+ if (err) {
105
+ cb(new Error(message.join("\n"), { cause: err }));
106
+ return;
107
+ }
108
+ cb();
109
+ },
110
+ );
111
+ };
112
+
113
+ // [function]
114
+
115
+ const listTags = function (root, cb) {
116
+ fetchTags(root, (err) => {
117
+ if (err) {
118
+ cb(err);
119
+ return;
120
+ }
121
+ git(root, ["tag", "--list", `${PREFIX}*`], (err, stdOut) => {
122
+ if (err) {
123
+ cb(err);
124
+ return;
125
+ }
126
+ const versions = trimWhitespace(stdOut)
127
+ .split("\n")
128
+ .map((tag) => tag.slice(PREFIX.length))
129
+ .filter(validSemver)
130
+ .sort(compareSemver);
131
+ cb(null, versions.at(-1) || "0.0.0");
132
+ });
133
+ });
134
+ };
135
+
136
+ // [function]
137
+
138
+ const createTag = function (root, version, pre, cb) {
139
+ const message = [
140
+ "Unable to create Git tag.",
141
+ "Verify the release tag does not already exist locally.",
142
+ ];
143
+ git(
144
+ root,
145
+ [
146
+ "tag",
147
+ "-a",
148
+ `${PREFIX}${version}`,
149
+ "-m",
150
+ pre ? `Prerelease v${version}` : `Release v${version}`,
151
+ ],
152
+ (err) => {
153
+ if (err) {
154
+ cb(new Error(message.join("\n"), { cause: err }));
155
+ return;
156
+ }
157
+ cb();
158
+ },
159
+ );
160
+ };
161
+
162
+ // [function]
163
+
164
+ const pushTag = function (root, version, cb) {
165
+ const message = [
166
+ "Unable to push Git tag.",
167
+ "Run `arc deploy` again to retry with the latest release version.",
168
+ ];
169
+ git(root, ["push", "origin", `${PREFIX}${version}`], (err) => {
170
+ if (err) {
171
+ cb(new Error(message.join("\n"), { cause: err }));
172
+ return;
173
+ }
174
+ cb();
175
+ });
176
+ };
177
+
178
+ // [function]
179
+
180
+ const release = function (root, version, pre, cb) {
181
+ createTag(root, version, pre, (err) => {
182
+ if (err) {
183
+ cb(err);
184
+ return;
185
+ }
186
+ pushTag(root, version, cb);
187
+ });
188
+ };
189
+
190
+ // [export]
191
+
192
+ module.exports = { ensureClean, ensureRemote, ensureRepo, listTags, release };
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const semver = require("semver");
6
+
7
+ // [import]
8
+
9
+ const git = require("./git");
10
+
11
+ // [use]
12
+
13
+ const ensureClean = git.ensureClean;
14
+ const ensureRemote = git.ensureRemote;
15
+ const ensureRepo = git.ensureRepo;
16
+ const incSemver = semver.inc;
17
+ const listTags = git.listTags;
18
+ const release = git.release;
19
+
20
+ // [function]
21
+
22
+ const deployGit = function ({ pre, preId, root }, handler, cb) {
23
+ listTags(root, (err, from) => {
24
+ if (err) {
25
+ cb(err);
26
+ return;
27
+ }
28
+ const to = incSemver(from, pre ? "prerelease" : "patch", preId);
29
+ release(root, to, pre, (err) => {
30
+ if (err) {
31
+ cb(err);
32
+ return;
33
+ }
34
+ cb(null, { from, to });
35
+ });
36
+ });
37
+ };
38
+
39
+ // [function]
40
+
41
+ const deploy = function ({ pre, preId, root }, { onInfo }, cb) {
42
+ ensureRepo(root, (err) => {
43
+ if (err) {
44
+ cb(err);
45
+ return;
46
+ }
47
+ ensureClean(root, (err, diff) => {
48
+ if (err) {
49
+ cb(err);
50
+ return;
51
+ }
52
+ if (diff.cached) {
53
+ onInfo({
54
+ level: "warn",
55
+ message: "Staged but uncommitted changes will not be deployed.",
56
+ });
57
+ }
58
+ ensureRemote(root, (err) => {
59
+ if (err) {
60
+ cb(err);
61
+ return;
62
+ }
63
+ deployGit({ pre, preId, root }, { onInfo }, cb);
64
+ });
65
+ });
66
+ });
67
+ };
68
+
69
+ // [function]
70
+
71
+ const main = function ({ pre, preId, root }, { onBegin, ...handler }) {
72
+ onBegin({ root });
73
+ return new Promise((resolve, reject) => {
74
+ deploy({ pre, preId, root }, handler, (err, data) => {
75
+ if (err) {
76
+ reject(err);
77
+ return;
78
+ }
79
+ resolve(data);
80
+ });
81
+ });
82
+ };
83
+
84
+ // [export]
85
+
86
+ module.exports = main;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const path = require("node:path");
6
+
7
+ // [import]
8
+
9
+ const degit = require("degit");
10
+ const fs = require("fs-extra");
11
+
12
+ // [use]
13
+
14
+ const pathExists = fs.pathExists;
15
+ const remove = fs.remove;
16
+ const resolve = path.resolve;
17
+
18
+ // [function]
19
+
20
+ const init = function (src, dest, { onBegin, onInfo }) {
21
+ onBegin({ dest, src });
22
+ return degit(src, { cache: false, force: true, verbose: false })
23
+ .on("info", onInfo)
24
+ .clone(dest)
25
+ .then(() => remove(resolve(dest, "LICENSE")));
26
+ };
27
+
28
+ // [function]
29
+
30
+ const main = function ({ force, project, root, starter }, handler) {
31
+ const dest = resolve(root, project);
32
+ return pathExists(dest)
33
+ .then((exists) => {
34
+ if (exists && !force) {
35
+ throw new Error("Directory exists. Run with `--force` to overwrite.");
36
+ }
37
+ return init(starter, dest, handler);
38
+ })
39
+ .then(() => ({ path: dest }));
40
+ };
41
+
42
+ // [export]
43
+
44
+ module.exports = main;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const dotProp = require("dot-prop");
6
+
7
+ // [import]
8
+
9
+ const project = require("../../parser/project");
10
+
11
+ // [function]
12
+
13
+ const inspect = function (proj, key) {
14
+ return key ? dotProp.get(proj, key, null) : proj;
15
+ };
16
+
17
+ // [function]
18
+
19
+ const main = function ({ key, root }) {
20
+ return project.parse(root).then((proj) => inspect(proj, key));
21
+ };
22
+
23
+ // [export]
24
+
25
+ module.exports = main;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const crypto = require("node:crypto");
6
+
7
+ // [import]
8
+
9
+ const api = require("../../api");
10
+ const cfgurl = require("../../config/url");
11
+ const time = require("../../util/time");
12
+
13
+ // [use]
14
+
15
+ const randomUUID = crypto.randomUUID;
16
+
17
+ // [function]
18
+
19
+ const postFlow = function ({ expiresAt, token, type }) {
20
+ const form = new FormData();
21
+ form.append("expires_at", expiresAt.toISOString());
22
+ form.append("token", token);
23
+ form.append("type", type);
24
+ return api.postFlow(form);
25
+ };
26
+
27
+ // [function]
28
+
29
+ const getFlow = function ({ id, token }) {
30
+ return api.getFlow(id, { token });
31
+ };
32
+
33
+ // [function]
34
+
35
+ const createFlow = function ({ expiresAt, token, type }, onCreated) {
36
+ return postFlow({ expiresAt, token, type }).then(({ code, id }) => {
37
+ if (onCreated) {
38
+ onCreated({ code, url: cfgurl.LINK });
39
+ }
40
+ return { id };
41
+ });
42
+ };
43
+
44
+ // [function]
45
+
46
+ const pollFlow = function ({ id, token }, onPoll) {
47
+ return getFlow({ id, token }).then(({ data, status }) => {
48
+ if (onPoll) {
49
+ onPoll({ status });
50
+ }
51
+ switch (status) {
52
+ case "pending":
53
+ return null;
54
+ case "completed":
55
+ return data;
56
+ case "failed":
57
+ throw new Error("Login flow failed.");
58
+ default:
59
+ throw new Error("Login flow expired.");
60
+ }
61
+ });
62
+ };
63
+
64
+ // [function]
65
+
66
+ const main = function ({ onCreated, onPoll }) {
67
+ const expiresAt = new Date(Date.now() + time.m(5));
68
+ const token = randomUUID();
69
+ return createFlow(
70
+ {
71
+ expiresAt,
72
+ token,
73
+ type: "cli-login",
74
+ },
75
+ onCreated,
76
+ ).then(({ id }) => {
77
+ const timeout = Math.max(0, expiresAt.getTime() - Date.now() - time.s(15));
78
+ return time.poll(
79
+ (flow) => pollFlow(flow, onPoll),
80
+ { id, token },
81
+ {
82
+ delay: time.s(3),
83
+ factor: 2,
84
+ interval: time.s(30),
85
+ maxDelay: time.s(15),
86
+ timeout,
87
+ },
88
+ );
89
+ });
90
+ };
91
+
92
+ // [export]
93
+
94
+ module.exports = main;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const flow = require("./flow");
6
+ const user = require("../../user");
7
+
8
+ // [function]
9
+
10
+ const main = function (conf, handler) {
11
+ return flow(handler).then(user.save);
12
+ };
13
+
14
+ // [export]
15
+
16
+ module.exports = main;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const user = require("../../user");
6
+
7
+ // [function]
8
+
9
+ const main = function () {
10
+ return user.remove();
11
+ };
12
+
13
+ // [export]
14
+
15
+ module.exports = main;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const path = require("node:path");
6
+
7
+ // [import]
8
+
9
+ const fs = require("fs-extra");
10
+
11
+ // [import]
12
+
13
+ const project = require("../../parser/project");
14
+ const Zip = require("../../util/zip");
15
+
16
+ // [use]
17
+
18
+ const pathExists = fs.pathExists;
19
+ const pathParse = path.parse;
20
+ const resolve = path.resolve;
21
+
22
+ // [declare]
23
+
24
+ const MANIFEST = "arcadible.json";
25
+ const MEDIA = ".arcadible";
26
+
27
+ // [function]
28
+
29
+ const pack = function (name, game, { deployPath, mediaPath, zipPath }) {
30
+ const zip = new Zip(name);
31
+ return Promise.all([pathExists(deployPath), pathExists(mediaPath)])
32
+ .then(([existsDeploy, existsMedia]) => {
33
+ if (existsDeploy) {
34
+ zip.addDir(deployPath);
35
+ }
36
+ if (existsMedia) {
37
+ zip.addDir(mediaPath, MEDIA);
38
+ }
39
+ zip.addJson(MANIFEST, { game });
40
+ zip.write(zipPath);
41
+ return zip.stat();
42
+ })
43
+ .then((stat) => ({ path: zipPath, ...stat }));
44
+ };
45
+
46
+ // [function]
47
+
48
+ const main = function ({ output, root }) {
49
+ return project.parse(root).then(({ game, workflow }) =>
50
+ pack(pathParse(output).name, game, {
51
+ deployPath: resolve(root, workflow.deploy_dir),
52
+ mediaPath: resolve(root, MEDIA),
53
+ zipPath: resolve(root, output),
54
+ }),
55
+ );
56
+ };
57
+
58
+ // [export]
59
+
60
+ module.exports = main;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const game = require("../../schema/game");
6
+ const project = require("../../parser/project");
7
+ const schema = require("../../util/schema");
8
+ const workflow = require("../../schema/workflow");
9
+
10
+ // [use]
11
+
12
+ const validator = schema.validator;
13
+
14
+ // [define]
15
+
16
+ const gameValidator = validator("game", game);
17
+ const workflowValidator = validator("workflow", workflow);
18
+
19
+ // [function]
20
+
21
+ const validate = function (proj, { root }) {
22
+ const issues = [
23
+ gameValidator(proj.game, { root }),
24
+ workflowValidator(proj.workflow, { root }),
25
+ ]
26
+ .filter((result) => result.issues.length)
27
+ .flatMap((result) => result.issues);
28
+ return issues;
29
+ };
30
+
31
+ // [function]
32
+
33
+ const main = function ({ root }) {
34
+ return project.parse(root).then((proj) => validate(proj, { root }));
35
+ };
36
+
37
+ // [export]
38
+
39
+ module.exports = main;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const user = require("../../user");
6
+
7
+ // [function]
8
+
9
+ const main = function (conf, handler) {
10
+ return user.get(handler);
11
+ };
12
+
13
+ // [export]
14
+
15
+ module.exports = main;
package/src/api.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const cfguri = require("./config/uri");
6
+ const request = require("./util/request");
7
+
8
+ // [declare]
9
+
10
+ const API_HOST = cfguri.HOST_HTTP_API;
11
+ const API_VERSION = "v1";
12
+
13
+ // [function]
14
+
15
+ const endpoint = function (path) {
16
+ return `${API_HOST}/${API_VERSION}${path}`;
17
+ };
18
+
19
+ // [function]
20
+
21
+ const authRefresh = function (form, options) {
22
+ return request.post(endpoint("/auth/refresh"), form, options);
23
+ };
24
+
25
+ // [function]
26
+
27
+ const getFlow = function (id, options) {
28
+ return request.get(endpoint(`/flows/${id}`), options);
29
+ };
30
+
31
+ // [function]
32
+
33
+ const postFlow = function (form, options) {
34
+ return request.post(endpoint("/flows"), form, options);
35
+ };
36
+
37
+ // [export]
38
+
39
+ module.exports = { authRefresh, getFlow, postFlow };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const deployGitTool = require("../action/deploy-git/tool");
6
+ const deployTool = require("../action/deploy/tool");
7
+
8
+ // [function]
9
+
10
+ const main = function ({ direct, handler, ...conf }) {
11
+ const tool = direct ? deployTool : deployGitTool;
12
+ return tool(conf, handler);
13
+ };
14
+
15
+ // [export]
16
+
17
+ module.exports = main;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const deploy = require("./deploy");
6
+ const init = require("./init");
7
+ const inspect = require("./inspect");
8
+ const login = require("./login");
9
+ const logout = require("./logout");
10
+ const pack = require("./pack");
11
+ const validate = require("./validate");
12
+ const whoami = require("./whoami");
13
+
14
+ // [export]
15
+
16
+ module.exports = {
17
+ deploy,
18
+ init,
19
+ inspect,
20
+ login,
21
+ logout,
22
+ pack,
23
+ validate,
24
+ whoami,
25
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ // [import]
4
+
5
+ const initTool = require("../action/init/tool");
6
+
7
+ // [function]
8
+
9
+ const main = function ({ handler, ...conf }) {
10
+ return initTool(conf, handler);
11
+ };
12
+
13
+ // [export]
14
+
15
+ module.exports = main;