arcadible 0.1.32 → 0.1.34
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/README.md +4 -4
- package/bin/arc-build.js +23 -5
- package/bin/arc-deploy.js +78 -13
- package/bin/arc-init.js +6 -1
- package/bin/arc-inspect.js +1 -0
- package/bin/arc-login.js +4 -1
- package/bin/arc-open.js +4 -1
- package/bin/arc-pack.js +23 -3
- package/bin/arc-play.js +4 -1
- package/bin/arc-validate.js +1 -0
- package/bin/arc-whoami.js +1 -0
- package/package.json +3 -3
- package/src/account.js +7 -4
- package/src/action/build/tool.js +8 -4
- package/src/action/deploy/tool-git.js +49 -61
- package/src/action/deploy/tool.js +50 -44
- package/src/action/deploy/wait.js +37 -22
- package/src/action/init/manifest.js +23 -6
- package/src/action/init/tool-patch.js +1 -7
- package/src/action/init/tool.js +12 -9
- package/src/action/login/flow.js +7 -3
- package/src/action/pack/limits.js +13 -3
- package/src/action/pack/tool.js +19 -6
- package/src/action/play/tool.js +7 -1
- package/src/action/predeploy/ac.js +39 -22
- package/src/action/predeploy/git.js +69 -58
- package/src/action/predeploy/pm.js +24 -17
- package/src/action/predeploy/published.js +15 -2
- package/src/action/predeploy/tool-git.js +74 -86
- package/src/action/predeploy/tool.js +7 -33
- package/src/action/validate/tool.js +5 -4
- package/src/api.js +14 -1
- package/src/cli/predeploy.js +1 -1
- package/src/config/code.js +112 -0
- package/src/config/url.js +2 -1
- package/src/parser/env.js +19 -3
- package/src/parser/given.js +17 -0
- package/src/parser/manifest.js +8 -1
- package/src/parser/media.js +5 -9
- package/src/parser/project.js +4 -1
- package/src/parser/readme-file.js +8 -1
- package/src/phrase.js +75 -7
- package/src/schema/check/game.js +5 -26
- package/src/schema/game.js +117 -210
- package/src/schema/message.js +46 -7
- package/src/schema/readme.js +8 -3
- package/src/schema/workflow.js +35 -15
- package/src/util/argv.js +33 -1
- package/src/util/delay.js +4 -1
- package/src/util/error.js +49 -0
- package/src/util/image.js +4 -30
- package/src/util/log.js +8 -0
- package/src/util/media.js +40 -0
- package/src/util/output.js +34 -4
- package/src/util/request.js +11 -2
- package/src/util/s3.js +37 -20
- package/src/util/schema.js +93 -30
- package/src/util/video.js +4 -27
|
@@ -6,95 +6,83 @@ const semver = require("semver");
|
|
|
6
6
|
|
|
7
7
|
// [import]
|
|
8
8
|
|
|
9
|
+
const cfgcode = require("../../config/code");
|
|
10
|
+
const error = require("../../util/error");
|
|
11
|
+
const given = require("../../parser/given");
|
|
9
12
|
const links = require("../../util/links");
|
|
10
13
|
const phrase = require("../../phrase");
|
|
11
|
-
const project = require("../../parser/project");
|
|
12
14
|
const repo = require("../predeploy/git");
|
|
13
15
|
|
|
14
16
|
// [use]
|
|
15
17
|
|
|
18
|
+
const ArcError = error.ArcError;
|
|
19
|
+
const failWith = repo.failWith;
|
|
16
20
|
const git = repo.git;
|
|
17
21
|
const prereleaseSemver = semver.prerelease;
|
|
18
22
|
const tagOf = repo.tagOf;
|
|
19
23
|
|
|
20
24
|
// [function]
|
|
21
25
|
|
|
22
|
-
const createTag = function (root, version
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
prereleaseSemver(version) === null
|
|
31
|
-
? phrase.versionRelease(version)
|
|
32
|
-
: phrase.versionPrerelease(version),
|
|
33
|
-
],
|
|
34
|
-
(err) => {
|
|
35
|
-
if (err) {
|
|
36
|
-
cb(new Error(phrase.gitTagCreateFailed(version), { cause: err }));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
cb(null);
|
|
40
|
-
},
|
|
26
|
+
const createTag = function (root, version) {
|
|
27
|
+
const message =
|
|
28
|
+
prereleaseSemver(version) === null
|
|
29
|
+
? phrase.versionRelease(version)
|
|
30
|
+
: phrase.versionPrerelease(version);
|
|
31
|
+
return git(root, ["tag", "-a", tagOf(version), "-m", message]).then(
|
|
32
|
+
() => null,
|
|
33
|
+
failWith(cfgcode.GIT_TAG_CREATE_FAILED, phrase.gitTagCreateFailed(version)),
|
|
41
34
|
);
|
|
42
35
|
};
|
|
43
36
|
|
|
44
37
|
// [function]
|
|
45
38
|
|
|
46
|
-
// the local tag
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
cause: err,
|
|
53
|
-
});
|
|
54
|
-
git(root, ["tag", "-d", tagOf(version)], () => cb(failed));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
cb(null);
|
|
58
|
-
});
|
|
39
|
+
// deletes the local tag, then fails with `failed` whether or not it could.
|
|
40
|
+
const untag = function (root, version, failed) {
|
|
41
|
+
const fail = () => {
|
|
42
|
+
throw failed;
|
|
43
|
+
};
|
|
44
|
+
return git(root, ["tag", "-d", tagOf(version)]).then(fail, fail);
|
|
59
45
|
};
|
|
60
46
|
|
|
61
47
|
// [function]
|
|
62
48
|
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
49
|
+
// the local tag is deleted when the push fails, so trying again isn't
|
|
50
|
+
// blocked by a tag that was never released.
|
|
51
|
+
const pushTag = function (root, version) {
|
|
52
|
+
return git(root, ["push", "origin", tagOf(version)]).then(
|
|
53
|
+
() => null,
|
|
54
|
+
(err) =>
|
|
55
|
+
untag(
|
|
56
|
+
root,
|
|
57
|
+
version,
|
|
58
|
+
new ArcError(
|
|
59
|
+
cfgcode.GIT_TAG_PUSH_FAILED,
|
|
60
|
+
phrase.gitTagPushFailed(version),
|
|
61
|
+
{
|
|
62
|
+
cause: err,
|
|
63
|
+
},
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
);
|
|
73
67
|
};
|
|
74
68
|
|
|
75
69
|
// [function]
|
|
76
70
|
|
|
77
|
-
|
|
71
|
+
// tags the version and pushes the tag: the Arcadible GitHub App publishes
|
|
72
|
+
// the release that the workflow builds from it.
|
|
73
|
+
const main = function (conf, { onDeployBegin }) {
|
|
78
74
|
if (onDeployBegin) {
|
|
79
75
|
onDeployBegin();
|
|
80
76
|
}
|
|
81
|
-
return
|
|
82
|
-
({ game }) =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
...links.published(game),
|
|
91
|
-
game: game.id,
|
|
92
|
-
tag: tagOf(game.version),
|
|
93
|
-
version: { to: game.version },
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
}),
|
|
97
|
-
);
|
|
77
|
+
return given(conf)
|
|
78
|
+
.then(({ game }) => Promise.all([game, createTag(conf.root, game.version)]))
|
|
79
|
+
.then(([game]) => Promise.all([game, pushTag(conf.root, game.version)]))
|
|
80
|
+
.then(([game]) => ({
|
|
81
|
+
...links.published(game),
|
|
82
|
+
game: game.id,
|
|
83
|
+
tag: tagOf(game.version),
|
|
84
|
+
version: { to: game.version },
|
|
85
|
+
}));
|
|
98
86
|
};
|
|
99
87
|
|
|
100
88
|
// [export]
|
|
@@ -3,39 +3,55 @@
|
|
|
3
3
|
// [import]
|
|
4
4
|
|
|
5
5
|
const api = require("../../api");
|
|
6
|
+
const cfgcode = require("../../config/code");
|
|
7
|
+
const error = require("../../util/error");
|
|
8
|
+
const given = require("../../parser/given");
|
|
6
9
|
const links = require("../../util/links");
|
|
7
10
|
const phrase = require("../../phrase");
|
|
8
|
-
const project = require("../../parser/project");
|
|
9
11
|
const s3 = require("../../util/s3");
|
|
10
12
|
|
|
13
|
+
// [use]
|
|
14
|
+
|
|
15
|
+
const ArcError = error.ArcError;
|
|
16
|
+
|
|
11
17
|
// [function]
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{ id, version },
|
|
17
|
-
onUploadProgress,
|
|
18
|
-
cb,
|
|
19
|
-
) {
|
|
19
|
+
// asks the API for an upload link, then sends the zip to it, and resolves
|
|
20
|
+
// with the upload.
|
|
21
|
+
const uploadBuild = function (current, artifact, { id, version }, onProgress) {
|
|
20
22
|
const form = new FormData();
|
|
21
23
|
form.append("artifact", id);
|
|
22
24
|
form.append("version", version);
|
|
23
25
|
form.append("sha256", artifact.sha256);
|
|
24
26
|
form.append("size", artifact.size);
|
|
25
|
-
// api
|
|
26
27
|
return api
|
|
27
28
|
.postUpload(form, null, api.auth(current?.session?.access_token))
|
|
28
29
|
.then(
|
|
29
|
-
(upload) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
(upload) =>
|
|
31
|
+
Promise.all([
|
|
32
|
+
upload,
|
|
33
|
+
s3.upload(upload.upload_url, artifact, onProgress),
|
|
34
|
+
]),
|
|
34
35
|
(err) => {
|
|
35
|
-
// the API refuses a game that was deleted or is another account's
|
|
36
|
-
|
|
36
|
+
// the API refuses a game that was deleted or is another account's,
|
|
37
|
+
// and the same version uploaded again within 5 minutes.
|
|
38
|
+
if (err.status === 403) {
|
|
39
|
+
throw new ArcError(
|
|
40
|
+
cfgcode.GAME_UNAVAILABLE,
|
|
41
|
+
phrase.gameUnavailable(id),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (err.status === 429) {
|
|
45
|
+
throw new ArcError(
|
|
46
|
+
cfgcode.UPLOAD_RATE_LIMITED,
|
|
47
|
+
phrase.uploadRateLimited(version),
|
|
48
|
+
{ cause: err },
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
throw err;
|
|
37
52
|
},
|
|
38
|
-
)
|
|
53
|
+
)
|
|
54
|
+
.then(([upload]) => upload);
|
|
39
55
|
};
|
|
40
56
|
|
|
41
57
|
// [function]
|
|
@@ -43,37 +59,27 @@ const uploadBuild = function (
|
|
|
43
59
|
const main = function (
|
|
44
60
|
current,
|
|
45
61
|
artifact,
|
|
46
|
-
|
|
62
|
+
conf,
|
|
47
63
|
{ onDeployBegin, onUploadProgress },
|
|
48
64
|
) {
|
|
49
65
|
if (onDeployBegin) {
|
|
50
|
-
onDeployBegin({ root });
|
|
66
|
+
onDeployBegin({ root: conf.root });
|
|
51
67
|
}
|
|
52
|
-
return
|
|
53
|
-
({ game }) =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
resolve({
|
|
68
|
-
...links.published(game),
|
|
69
|
-
game: game.id,
|
|
70
|
-
release: upload.id,
|
|
71
|
-
version: { to: game.version },
|
|
72
|
-
});
|
|
73
|
-
},
|
|
74
|
-
);
|
|
75
|
-
}),
|
|
76
|
-
);
|
|
68
|
+
return given(conf)
|
|
69
|
+
.then(({ game }) =>
|
|
70
|
+
Promise.all([
|
|
71
|
+
game,
|
|
72
|
+
uploadBuild(current, artifact, game, onUploadProgress),
|
|
73
|
+
]),
|
|
74
|
+
)
|
|
75
|
+
.then(([game, upload]) => ({
|
|
76
|
+
...links.published(game),
|
|
77
|
+
game: game.id,
|
|
78
|
+
// a direct deploy's release shares its upload's id, which `--wait`
|
|
79
|
+
// follows.
|
|
80
|
+
release: upload.id,
|
|
81
|
+
version: { to: game.version },
|
|
82
|
+
}));
|
|
77
83
|
};
|
|
78
84
|
|
|
79
85
|
// [export]
|
|
@@ -19,7 +19,7 @@ const sleep = delay.sleep;
|
|
|
19
19
|
const INTERVAL = time.s(2);
|
|
20
20
|
const FINAL = new Set(["failed", "published"]);
|
|
21
21
|
const SELECT =
|
|
22
|
-
"id,status,reason,message,build,source,version,channel,created_at";
|
|
22
|
+
"id,game,status,reason,message,build,source,version,channel,created_at";
|
|
23
23
|
// a git release is found by version among the newest few; one from before
|
|
24
24
|
// this deploy (a tag deleted and pushed again) is left out, allowing for
|
|
25
25
|
// the machine's clock being off.
|
|
@@ -44,16 +44,17 @@ const studioUrl = function (game) {
|
|
|
44
44
|
// the repository's GitHub Actions page, from origin's URL, or null when
|
|
45
45
|
// origin isn't on GitHub.
|
|
46
46
|
const actionsUrl = function (root) {
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
const match =
|
|
50
|
-
|
|
51
|
-
: /github\.com[:/]([^/\s]+)\/([^/\s]+?)(?:\.git)?\s*$/u.exec(stdout);
|
|
52
|
-
resolve(
|
|
53
|
-
match ? `https://github.com/${match[1]}/${match[2]}/actions` : null,
|
|
47
|
+
return git(root, ["remote", "get-url", "origin"]).then(
|
|
48
|
+
(stdout) => {
|
|
49
|
+
const match = /github\.com[:/]([^/\s]+)\/([^/\s]+?)(?:\.git)?\s*$/u.exec(
|
|
50
|
+
stdout,
|
|
54
51
|
);
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
return match
|
|
53
|
+
? `https://github.com/${match[1]}/${match[2]}/actions`
|
|
54
|
+
: null;
|
|
55
|
+
},
|
|
56
|
+
() => null,
|
|
57
|
+
);
|
|
57
58
|
};
|
|
58
59
|
|
|
59
60
|
// [function]
|
|
@@ -66,18 +67,26 @@ const findDirect = function (id, headers) {
|
|
|
66
67
|
// [function]
|
|
67
68
|
|
|
68
69
|
// a git deploy's release: GitHub's, for this version, made since the tag was
|
|
69
|
-
// pushed. Null until GitHub Actions has built it.
|
|
70
|
-
|
|
70
|
+
// pushed. Null until GitHub Actions has built it. It's looked for among the
|
|
71
|
+
// account's releases, which include one with no game: a repository that
|
|
72
|
+
// isn't connected fails that way (repo_not_connected). A token's account
|
|
73
|
+
// isn't known, so it looks among the game's.
|
|
74
|
+
const findGit = function ({ account, game, headers, since, version }) {
|
|
75
|
+
const newest = account
|
|
76
|
+
? () => api.accountReleases(account, { limit: 20, select: SELECT }, headers)
|
|
77
|
+
: () =>
|
|
78
|
+
api.gameReleases(game, { limit: 10, select: SELECT, version }, headers);
|
|
71
79
|
return () =>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
newest().then(
|
|
81
|
+
(rows) =>
|
|
82
|
+
(rows ?? []).find(
|
|
83
|
+
(r) =>
|
|
84
|
+
r.source === "github" &&
|
|
85
|
+
r.version === version &&
|
|
86
|
+
(r.game === game || r.game === null) &&
|
|
87
|
+
Date.parse(r.created_at) >= since - SKEW,
|
|
88
|
+
) ?? null,
|
|
89
|
+
);
|
|
81
90
|
};
|
|
82
91
|
|
|
83
92
|
// [function]
|
|
@@ -127,7 +136,13 @@ const main = function (
|
|
|
127
136
|
const headers = api.auth(current?.session?.access_token);
|
|
128
137
|
const game = deployed.game;
|
|
129
138
|
const find = isGit
|
|
130
|
-
? findGit(
|
|
139
|
+
? findGit({
|
|
140
|
+
account: current?.user?.id ?? null,
|
|
141
|
+
game,
|
|
142
|
+
headers,
|
|
143
|
+
since,
|
|
144
|
+
version: deployed.version.to,
|
|
145
|
+
})
|
|
131
146
|
: findDirect(deployed.release, headers);
|
|
132
147
|
return Promise.all([
|
|
133
148
|
poll(find, timeout, onRelease),
|
|
@@ -11,12 +11,16 @@ const fs = require("fs-extra");
|
|
|
11
11
|
|
|
12
12
|
// [import]
|
|
13
13
|
|
|
14
|
+
const cfgcode = require("../../config/code");
|
|
14
15
|
const cfgproduct = require("../../config/product");
|
|
16
|
+
const env = require("../../parser/env");
|
|
17
|
+
const error = require("../../util/error");
|
|
15
18
|
const phrase = require("../../phrase");
|
|
16
19
|
const TOML = require("../../util/toml");
|
|
17
20
|
|
|
18
21
|
// [use]
|
|
19
22
|
|
|
23
|
+
const ArcError = error.ArcError;
|
|
20
24
|
const join = path.join;
|
|
21
25
|
const pathExists = fs.pathExists;
|
|
22
26
|
const randomUUID = crypto.randomUUID;
|
|
@@ -34,12 +38,23 @@ const parseToml = function (buf) {
|
|
|
34
38
|
try {
|
|
35
39
|
return TOML.parse(buf);
|
|
36
40
|
} catch (ex) {
|
|
37
|
-
throw new
|
|
41
|
+
throw new ArcError(
|
|
42
|
+
cfgcode.PARSE_FAILED,
|
|
43
|
+
phrase.unableToParse(MANIFEST, ex.message),
|
|
44
|
+
{ cause: ex },
|
|
45
|
+
);
|
|
38
46
|
}
|
|
39
47
|
};
|
|
40
48
|
|
|
41
49
|
// [function]
|
|
42
50
|
|
|
51
|
+
// the version the project's package.json gives, if any.
|
|
52
|
+
const detectVersion = function (dest) {
|
|
53
|
+
return env(dest).then(({ game }) => game?.version ?? null);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// [function]
|
|
57
|
+
|
|
43
58
|
const pickVersion = function (version, envVersion) {
|
|
44
59
|
if (version) {
|
|
45
60
|
return { version };
|
|
@@ -57,10 +72,12 @@ const readManifest = function (file) {
|
|
|
57
72
|
|
|
58
73
|
// [function]
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
// a new project always gets its own id: a template's, such as an existing
|
|
76
|
+
// game's, belongs to that game.
|
|
77
|
+
const patchGame = function (envVersion, game = {}, { fresh = false } = {}) {
|
|
61
78
|
const { id, version, ...rest } = game;
|
|
62
79
|
return {
|
|
63
|
-
id: id ?? randomUUID(),
|
|
80
|
+
id: fresh ? randomUUID() : (id ?? randomUUID()),
|
|
64
81
|
...pickVersion(version, envVersion),
|
|
65
82
|
...rest,
|
|
66
83
|
};
|
|
@@ -77,11 +94,11 @@ const shouldWrite = function (manifest, next) {
|
|
|
77
94
|
|
|
78
95
|
// [function]
|
|
79
96
|
|
|
80
|
-
const prepare = function (dest, envVersion) {
|
|
97
|
+
const prepare = function (dest, envVersion, opts) {
|
|
81
98
|
const file = join(dest, MANIFEST);
|
|
82
99
|
return readManifest(file).then((manifest) => {
|
|
83
100
|
const { game, ...rest } = manifest;
|
|
84
|
-
const next = { game: patchGame(envVersion, game), ...rest };
|
|
101
|
+
const next = { game: patchGame(envVersion, game, opts), ...rest };
|
|
85
102
|
if (shouldWrite(manifest, next)) {
|
|
86
103
|
return writeFile(file, TOML.stringify(next), "utf8");
|
|
87
104
|
}
|
|
@@ -91,4 +108,4 @@ const prepare = function (dest, envVersion) {
|
|
|
91
108
|
|
|
92
109
|
// [export]
|
|
93
110
|
|
|
94
|
-
module.exports = { prepare };
|
|
111
|
+
module.exports = { detectVersion, prepare };
|
|
@@ -6,22 +6,16 @@ const path = require("node:path");
|
|
|
6
6
|
|
|
7
7
|
// [import]
|
|
8
8
|
|
|
9
|
-
const env = require("../../parser/env");
|
|
10
9
|
const manifest = require("./manifest");
|
|
11
10
|
|
|
12
11
|
// [use]
|
|
13
12
|
|
|
13
|
+
const detectVersion = manifest.detectVersion;
|
|
14
14
|
const prepare = manifest.prepare;
|
|
15
15
|
const resolve = path.resolve;
|
|
16
16
|
|
|
17
17
|
// [function]
|
|
18
18
|
|
|
19
|
-
const detectVersion = function (dest) {
|
|
20
|
-
return env(dest).then(({ game }) => game?.version ?? null);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// [function]
|
|
24
|
-
|
|
25
19
|
// an existing project: add a manifest, and copy nothing from the template.
|
|
26
20
|
const main = function ({ project, root }, { onInitBegin }) {
|
|
27
21
|
const dest = resolve(root, project);
|
package/src/action/init/tool.js
CHANGED
|
@@ -11,12 +11,15 @@ const fs = require("fs-extra");
|
|
|
11
11
|
|
|
12
12
|
// [import]
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const cfgcode = require("../../config/code");
|
|
15
|
+
const error = require("../../util/error");
|
|
15
16
|
const manifest = require("./manifest");
|
|
16
17
|
const phrase = require("../../phrase");
|
|
17
18
|
|
|
18
19
|
// [use]
|
|
19
20
|
|
|
21
|
+
const ArcError = error.ArcError;
|
|
22
|
+
const detectVersion = manifest.detectVersion;
|
|
20
23
|
const join = path.join;
|
|
21
24
|
const prepare = manifest.prepare;
|
|
22
25
|
const remove = fs.remove;
|
|
@@ -34,12 +37,6 @@ const removeLicense = function (dest) {
|
|
|
34
37
|
|
|
35
38
|
// [function]
|
|
36
39
|
|
|
37
|
-
const detectVersion = function (dest) {
|
|
38
|
-
return env(dest).then(({ game }) => game?.version ?? null);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// [function]
|
|
42
|
-
|
|
43
40
|
const scaffold = function (src, dest, { onInitBegin }) {
|
|
44
41
|
if (onInitBegin) {
|
|
45
42
|
onInitBegin({ dest, src });
|
|
@@ -47,7 +44,13 @@ const scaffold = function (src, dest, { onInitBegin }) {
|
|
|
47
44
|
return degit(src, { cache: false, force: true, verbose: false })
|
|
48
45
|
.clone(dest)
|
|
49
46
|
.catch((ex) => {
|
|
50
|
-
throw new
|
|
47
|
+
throw new ArcError(
|
|
48
|
+
cfgcode.TEMPLATE_UNAVAILABLE,
|
|
49
|
+
phrase.templateUnavailable(src),
|
|
50
|
+
{
|
|
51
|
+
cause: ex,
|
|
52
|
+
},
|
|
53
|
+
);
|
|
51
54
|
});
|
|
52
55
|
};
|
|
53
56
|
|
|
@@ -59,7 +62,7 @@ const main = function ({ project, root, template }, handler) {
|
|
|
59
62
|
return scaffold(template, dest, handler)
|
|
60
63
|
.then(() => removeLicense(dest))
|
|
61
64
|
.then(() => detectVersion(dest))
|
|
62
|
-
.then((version) => prepare(dest, version))
|
|
65
|
+
.then((version) => prepare(dest, version, { fresh: true }))
|
|
63
66
|
.then(() => ({ path: dest, template }));
|
|
64
67
|
};
|
|
65
68
|
|
package/src/action/login/flow.js
CHANGED
|
@@ -7,13 +7,16 @@ const crypto = require("node:crypto");
|
|
|
7
7
|
// [import]
|
|
8
8
|
|
|
9
9
|
const api = require("../../api");
|
|
10
|
+
const cfgcode = require("../../config/code");
|
|
10
11
|
const cfgurl = require("../../config/url");
|
|
11
12
|
const delay = require("../../util/delay");
|
|
13
|
+
const error = require("../../util/error");
|
|
12
14
|
const phrase = require("../../phrase");
|
|
13
15
|
const time = require("../../util/time");
|
|
14
16
|
|
|
15
17
|
// [use]
|
|
16
18
|
|
|
19
|
+
const ArcError = error.ArcError;
|
|
17
20
|
const poll = delay.poll;
|
|
18
21
|
const randomUUID = crypto.randomUUID;
|
|
19
22
|
|
|
@@ -24,7 +27,8 @@ const POLL = {
|
|
|
24
27
|
factor: 1.5,
|
|
25
28
|
interval: time.s(15),
|
|
26
29
|
maxDelay: time.s(5),
|
|
27
|
-
timeoutError:
|
|
30
|
+
timeoutError: () =>
|
|
31
|
+
new ArcError(cfgcode.LOGIN_EXPIRED, phrase.loginExpired()),
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
// [function]
|
|
@@ -67,9 +71,9 @@ const pollFlow = function (value, onLoginPoll) {
|
|
|
67
71
|
case "completed":
|
|
68
72
|
return data;
|
|
69
73
|
case "failed":
|
|
70
|
-
throw new
|
|
74
|
+
throw new ArcError(cfgcode.LOGIN_FAILED, phrase.loginFailed());
|
|
71
75
|
default:
|
|
72
|
-
throw new
|
|
76
|
+
throw new ArcError(cfgcode.LOGIN_EXPIRED, phrase.loginExpired());
|
|
73
77
|
}
|
|
74
78
|
});
|
|
75
79
|
};
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// [import]
|
|
4
4
|
|
|
5
|
+
const cfgcode = require("../../config/code");
|
|
6
|
+
const error = require("../../util/error");
|
|
5
7
|
const phrase = require("../../phrase");
|
|
6
8
|
const size = require("../../util/size");
|
|
7
9
|
|
|
8
10
|
// [use]
|
|
9
11
|
|
|
12
|
+
const ArcError = error.ArcError;
|
|
10
13
|
const toMb = size.toMb;
|
|
11
14
|
|
|
12
15
|
// [declare]
|
|
@@ -25,16 +28,23 @@ const MAX_TOTAL_SIZE = size.mb(256);
|
|
|
25
28
|
const check = function (entries) {
|
|
26
29
|
const large = entries.find((entry) => entry.size > MAX_FILE_SIZE);
|
|
27
30
|
if (large) {
|
|
28
|
-
throw new
|
|
31
|
+
throw new ArcError(
|
|
32
|
+
cfgcode.PACKAGE_FILE_TOO_LARGE,
|
|
29
33
|
phrase.packageFileTooLarge(large.name, toMb(MAX_FILE_SIZE)),
|
|
30
34
|
);
|
|
31
35
|
}
|
|
32
36
|
if (entries.length > MAX_FILES) {
|
|
33
|
-
throw new
|
|
37
|
+
throw new ArcError(
|
|
38
|
+
cfgcode.PACKAGE_TOO_MANY_FILES,
|
|
39
|
+
phrase.packageTooManyFiles(MAX_FILES),
|
|
40
|
+
);
|
|
34
41
|
}
|
|
35
42
|
const total = entries.reduce((sum, entry) => sum + entry.size, 0);
|
|
36
43
|
if (total > MAX_TOTAL_SIZE) {
|
|
37
|
-
throw new
|
|
44
|
+
throw new ArcError(
|
|
45
|
+
cfgcode.PACKAGE_UNCOMPRESSED_TOO_LARGE,
|
|
46
|
+
phrase.packageUncompressedTooLarge(toMb(MAX_TOTAL_SIZE)),
|
|
47
|
+
);
|
|
38
48
|
}
|
|
39
49
|
};
|
|
40
50
|
|
package/src/action/pack/tool.js
CHANGED
|
@@ -10,15 +10,18 @@ const fs = require("fs-extra");
|
|
|
10
10
|
|
|
11
11
|
// [import]
|
|
12
12
|
|
|
13
|
+
const cfgcode = require("../../config/code");
|
|
13
14
|
const cfgproduct = require("../../config/product");
|
|
15
|
+
const error = require("../../util/error");
|
|
16
|
+
const given = require("../../parser/given");
|
|
14
17
|
const limits = require("./limits");
|
|
15
18
|
const phrase = require("../../phrase");
|
|
16
|
-
const project = require("../../parser/project");
|
|
17
19
|
const size = require("../../util/size");
|
|
18
20
|
const Zip = require("../../util/zip");
|
|
19
21
|
|
|
20
22
|
// [use]
|
|
21
23
|
|
|
24
|
+
const ArcError = error.ArcError;
|
|
22
25
|
const parse = path.parse;
|
|
23
26
|
const pathExists = fs.pathExists;
|
|
24
27
|
const resolve = path.resolve;
|
|
@@ -43,10 +46,16 @@ const SIZE_PARTIAL = size.mb(64);
|
|
|
43
46
|
|
|
44
47
|
const verifyPartial = function (zip) {
|
|
45
48
|
if (!zip.has(MAIN)) {
|
|
46
|
-
throw new
|
|
49
|
+
throw new ArcError(
|
|
50
|
+
cfgcode.PACKAGE_INDEX_MISSING,
|
|
51
|
+
phrase.packageFileMissing(MAIN),
|
|
52
|
+
);
|
|
47
53
|
}
|
|
48
54
|
if (zip.stat().size > SIZE_PARTIAL) {
|
|
49
|
-
throw new
|
|
55
|
+
throw new ArcError(
|
|
56
|
+
cfgcode.PACKAGE_TOO_LARGE,
|
|
57
|
+
phrase.packageTooLarge(size.toMb(SIZE_PARTIAL)),
|
|
58
|
+
);
|
|
50
59
|
}
|
|
51
60
|
return zip;
|
|
52
61
|
};
|
|
@@ -65,7 +74,10 @@ const pack = function (name, game, { inputPath, mediaPath, outputPath }) {
|
|
|
65
74
|
return pathExists(inputPath)
|
|
66
75
|
.then((existsInput) => {
|
|
67
76
|
if (!existsInput) {
|
|
68
|
-
throw new
|
|
77
|
+
throw new ArcError(
|
|
78
|
+
cfgcode.PATH_NOT_FOUND,
|
|
79
|
+
phrase.unableToFind(inputPath),
|
|
80
|
+
);
|
|
69
81
|
}
|
|
70
82
|
zip.addDir(inputPath);
|
|
71
83
|
return zip;
|
|
@@ -88,8 +100,9 @@ const pack = function (name, game, { inputPath, mediaPath, outputPath }) {
|
|
|
88
100
|
|
|
89
101
|
// [function]
|
|
90
102
|
|
|
91
|
-
const main = function ({ input, output,
|
|
92
|
-
|
|
103
|
+
const main = function ({ input, output, ...conf }) {
|
|
104
|
+
const root = conf.root;
|
|
105
|
+
return given(conf).then(({ game, workflow }) => {
|
|
93
106
|
const name = game.handle ?? game.id;
|
|
94
107
|
const file = output ?? `${OUTPUT}/${name}-v${game.version}.zip`;
|
|
95
108
|
return pack(parse(file).name, game, {
|