arcadible 1.0.10 → 1.0.12
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 +7 -22
- package/package.json +1 -1
- package/src/action/deploy/wait.js +24 -36
- package/src/action/predeploy/pm.js +3 -14
- package/src/action/predeploy/tool-git.js +22 -10
- package/src/action/predeploy/tool.js +2 -0
- package/src/api.js +0 -10
- package/src/config/code.js +3 -2
- package/src/parser/env.js +15 -9
- package/src/phrase.js +16 -10
- package/src/util/lockfile.js +35 -0
- package/src/util/video.js +11 -1
package/bin/arc-deploy.js
CHANGED
|
@@ -136,14 +136,6 @@ const report = function (
|
|
|
136
136
|
|
|
137
137
|
// [function]
|
|
138
138
|
|
|
139
|
-
// the account, or null when there's none or it can't be refreshed: for a git
|
|
140
|
-
// deploy, which needs none.
|
|
141
|
-
const whoamiIfAny = function (opts) {
|
|
142
|
-
return whoami(opts).catch(() => null);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// [function]
|
|
146
|
-
|
|
147
139
|
// the release, as `--json` prints it.
|
|
148
140
|
const releaseJson = function (row) {
|
|
149
141
|
if (!row) {
|
|
@@ -168,7 +160,7 @@ const waitAndReport = async function (
|
|
|
168
160
|
current,
|
|
169
161
|
deployed,
|
|
170
162
|
result,
|
|
171
|
-
{ git, json,
|
|
163
|
+
{ git, json, quiet, root, since, timeout },
|
|
172
164
|
) {
|
|
173
165
|
let sw = new SpinnerWheel(phrase.releaseWaiting(git));
|
|
174
166
|
sw.start(json || quiet);
|
|
@@ -178,7 +170,7 @@ const waitAndReport = async function (
|
|
|
178
170
|
waited = await wait(
|
|
179
171
|
current,
|
|
180
172
|
deployed,
|
|
181
|
-
{ git,
|
|
173
|
+
{ git, root, since, timeout },
|
|
182
174
|
{
|
|
183
175
|
onRelease() {
|
|
184
176
|
// found: GitHub Actions is done, and Arcadible publishes it now.
|
|
@@ -253,9 +245,6 @@ const start = function (argv) {
|
|
|
253
245
|
const timeout = Number(argv.timeout ?? TIMEOUT[git ? "git" : "direct"]);
|
|
254
246
|
const root = resolve(process.cwd(), argv.cwd);
|
|
255
247
|
let pb = null;
|
|
256
|
-
// the game's account, when Arcadible could say: a git deploy's owner waits
|
|
257
|
-
// among their own releases.
|
|
258
|
-
let owner = null;
|
|
259
248
|
// whether the handle rules held the handle back from this release, so the
|
|
260
249
|
// game's links are by id.
|
|
261
250
|
let held = false;
|
|
@@ -277,14 +266,12 @@ const start = function (argv) {
|
|
|
277
266
|
sw.stop(true);
|
|
278
267
|
warn(warnings, { json, quiet });
|
|
279
268
|
sw = new SpinnerWheel("Checking… %s");
|
|
280
|
-
// git deploys need no login: anyone who can push to
|
|
281
|
-
// release, and the Arcadible GitHub App publishes
|
|
282
|
-
//
|
|
283
|
-
//
|
|
269
|
+
// git deploys need no login, and never use one: anyone who can push to
|
|
270
|
+
// the repository can release, and the Arcadible GitHub App publishes
|
|
271
|
+
// the release. Every call is public, so it's the same for whoever runs
|
|
272
|
+
// it, and the saved session isn't read, or refreshed.
|
|
284
273
|
if (git) {
|
|
285
|
-
return
|
|
286
|
-
handler: handler({ json, pb, quiet, sw, warnings }),
|
|
287
|
-
});
|
|
274
|
+
return null;
|
|
288
275
|
}
|
|
289
276
|
return whoami({ handler: handler({ json, pb, quiet, sw, warnings }) });
|
|
290
277
|
})
|
|
@@ -309,7 +296,6 @@ const start = function (argv) {
|
|
|
309
296
|
})
|
|
310
297
|
.then(([current, predeployed]) => {
|
|
311
298
|
sw.stop(true);
|
|
312
|
-
owner = predeployed.owner ?? null;
|
|
313
299
|
held = predeployed.held ?? false;
|
|
314
300
|
sw = new SpinnerWheel("Building… %s");
|
|
315
301
|
sw.start(git || json || quiet);
|
|
@@ -394,7 +380,6 @@ const start = function (argv) {
|
|
|
394
380
|
return waitAndReport(current, deployed, result, {
|
|
395
381
|
git,
|
|
396
382
|
json,
|
|
397
|
-
owner,
|
|
398
383
|
quiet,
|
|
399
384
|
root,
|
|
400
385
|
since,
|
package/package.json
CHANGED
|
@@ -63,27 +63,24 @@ const findDirect = function (id, headers) {
|
|
|
63
63
|
// [function]
|
|
64
64
|
|
|
65
65
|
// a git deploy's release: GitHub's, for this version, made since the tag was
|
|
66
|
-
// pushed. Null until GitHub Actions has built it.
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
const findGit = function ({ account, game, headers, since, version }) {
|
|
72
|
-
const newest = account
|
|
73
|
-
? () => api.accountReleases(account, { limit: 20, select: SELECT }, headers)
|
|
74
|
-
: () =>
|
|
75
|
-
api.discoverGameReleases(game, { limit: 10, select: SELECT, version });
|
|
66
|
+
// pushed. Null until GitHub Actions has built it. Looked for among the
|
|
67
|
+
// game's releases, which anyone can read, with no token: a git deploy asks
|
|
68
|
+
// what's true for whoever runs it. A release with no game (a repository that
|
|
69
|
+
// isn't connected, which the predeploy refuses first) isn't among them.
|
|
70
|
+
const findGit = function ({ game, since, version }) {
|
|
76
71
|
return () =>
|
|
77
|
-
|
|
78
|
-
(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
r
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
72
|
+
api
|
|
73
|
+
.discoverGameReleases(game, { limit: 10, select: SELECT, version })
|
|
74
|
+
.then(
|
|
75
|
+
(rows) =>
|
|
76
|
+
(rows ?? []).find(
|
|
77
|
+
(r) =>
|
|
78
|
+
r.source === "github" &&
|
|
79
|
+
r.version === version &&
|
|
80
|
+
r.game === game &&
|
|
81
|
+
Date.parse(r.created_at) >= since - SKEW,
|
|
82
|
+
) ?? null,
|
|
83
|
+
);
|
|
87
84
|
};
|
|
88
85
|
|
|
89
86
|
// [function]
|
|
@@ -123,28 +120,19 @@ const pollRelease = function (find, timeout, onRelease) {
|
|
|
123
120
|
// [function]
|
|
124
121
|
|
|
125
122
|
// waits on a deploy's release. `deployed` is what the deploy resolved: a
|
|
126
|
-
// direct deploy's has the release's id, and a git deploy's its game.
|
|
127
|
-
//
|
|
128
|
-
//
|
|
123
|
+
// direct deploy's has the release's id, and a git deploy's its game. A git
|
|
124
|
+
// deploy has no `current`: it never uses a login. Studio's link is for
|
|
125
|
+
// everyone, since Studio asks whoever opens it to log in.
|
|
129
126
|
const main = function (
|
|
130
127
|
current,
|
|
131
128
|
deployed,
|
|
132
|
-
{ git: isGit,
|
|
129
|
+
{ git: isGit, root, since, timeout },
|
|
133
130
|
{ onRelease } = {},
|
|
134
131
|
) {
|
|
135
|
-
const headers = api.auth(current?.session?.access_token);
|
|
136
132
|
const game = deployed.game;
|
|
137
|
-
const account = current?.token ? null : (current?.user?.id ?? null);
|
|
138
|
-
const owns = !isGit || (account !== null && account === owner);
|
|
139
133
|
const find = isGit
|
|
140
|
-
? findGit({
|
|
141
|
-
|
|
142
|
-
game,
|
|
143
|
-
headers,
|
|
144
|
-
since,
|
|
145
|
-
version: deployed.version.to,
|
|
146
|
-
})
|
|
147
|
-
: findDirect(deployed.release, headers);
|
|
134
|
+
? findGit({ game, since, version: deployed.version.to })
|
|
135
|
+
: findDirect(deployed.release, api.auth(current?.session?.access_token));
|
|
148
136
|
return Promise.all([
|
|
149
137
|
pollRelease(find, timeout, onRelease),
|
|
150
138
|
isGit ? actionsUrl(root) : null,
|
|
@@ -152,7 +140,7 @@ const main = function (
|
|
|
152
140
|
.then(([{ release, timedOut }, actions]) => ({
|
|
153
141
|
actions,
|
|
154
142
|
release,
|
|
155
|
-
studio:
|
|
143
|
+
studio: studioUrl(game, "builds"),
|
|
156
144
|
timedOut,
|
|
157
145
|
}))
|
|
158
146
|
.catch(ended(current));
|
|
@@ -9,33 +9,22 @@ const path = require("node:path");
|
|
|
9
9
|
|
|
10
10
|
const cfgcode = require("../../config/code");
|
|
11
11
|
const error = require("../../util/error");
|
|
12
|
+
const lockfile = require("../../util/lockfile");
|
|
12
13
|
const phrase = require("../../phrase");
|
|
13
14
|
|
|
14
15
|
// [use]
|
|
15
16
|
|
|
16
17
|
const ArcError = error.ArcError;
|
|
18
|
+
const detect = lockfile.detect;
|
|
17
19
|
const existsSync = fs.existsSync; // eslint-disable-line no-sync
|
|
18
20
|
const join = path.join;
|
|
19
21
|
|
|
20
|
-
// [declare]
|
|
21
|
-
|
|
22
|
-
const LOCK_FILES = [
|
|
23
|
-
// npm
|
|
24
|
-
"package-lock.json",
|
|
25
|
-
"npm-shrinkwrap.json",
|
|
26
|
-
// pnpm
|
|
27
|
-
"pnpm-lock.yaml",
|
|
28
|
-
// yarn
|
|
29
|
-
"yarn.lock",
|
|
30
|
-
];
|
|
31
|
-
|
|
32
22
|
// [function]
|
|
33
23
|
|
|
34
24
|
// fails when there's a package.json without a lockfile: the release workflow
|
|
35
25
|
// installs exactly what the lockfile pins.
|
|
36
26
|
const ensureLockFile = function (root) {
|
|
37
|
-
|
|
38
|
-
if (has("package.json") && !LOCK_FILES.some(has)) {
|
|
27
|
+
if (existsSync(join(root, "package.json")) && !detect(root)) {
|
|
39
28
|
return Promise.reject(
|
|
40
29
|
new ArcError(cfgcode.LOCKFILE_MISSING, phrase.lockfileMissing()),
|
|
41
30
|
);
|
|
@@ -39,11 +39,12 @@ const answerOf = function (request) {
|
|
|
39
39
|
// [function]
|
|
40
40
|
|
|
41
41
|
// what Arcadible would refuse in the release, refused before the tag is pushed: a
|
|
42
|
-
// game that was never deployed (a release can't create one),
|
|
43
|
-
// that's already published
|
|
42
|
+
// game that was never deployed (a release can't create one), a version
|
|
43
|
+
// that's already published, and a handle that isn't the game's (only a
|
|
44
|
+
// direct deploy changes one, so a collaborator's push can't). The lookups
|
|
45
|
+
// are public, so this needs no login.
|
|
44
46
|
// when Arcadible can't be reached, it warns and pushes anyway: a release
|
|
45
47
|
// shouldn't depend on the API, and Arcadible still checks.
|
|
46
|
-
// resolves with the game's owner, or null when Arcadible can't be reached.
|
|
47
48
|
const ensurePublishable = function ({ handle, id, version }, handler) {
|
|
48
49
|
return Promise.all([
|
|
49
50
|
answerOf(api.discoverGame(id)),
|
|
@@ -64,9 +65,17 @@ const ensurePublishable = function ({ handle, id, version }, handler) {
|
|
|
64
65
|
}
|
|
65
66
|
return null;
|
|
66
67
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
if (build.status === 200) {
|
|
69
|
+
return published.refuse(id, version);
|
|
70
|
+
}
|
|
71
|
+
const current = game.data?.handle ?? null;
|
|
72
|
+
if ((handle ?? null) !== current) {
|
|
73
|
+
throw new ArcError(
|
|
74
|
+
cfgcode.GAME_HANDLE_CHANGED,
|
|
75
|
+
phrase.gameHandleChanged(handle, current),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
70
79
|
});
|
|
71
80
|
};
|
|
72
81
|
|
|
@@ -116,17 +125,20 @@ const ensureConnected = function (root, { handle, id }) {
|
|
|
116
125
|
// [function]
|
|
117
126
|
|
|
118
127
|
// the release's checks: its tag is free, Arcadible would publish it, and
|
|
119
|
-
// origin is its connected repository. resolves with the version
|
|
120
|
-
// game's owner, who waits on the release among their own.
|
|
128
|
+
// origin is its connected repository. resolves with the version.
|
|
121
129
|
const ensureRelease = function (root, game, handler) {
|
|
122
130
|
return ensureTagFree(root, game.version)
|
|
123
131
|
.then(() => ensurePublishable(game, handler))
|
|
124
|
-
.then((
|
|
125
|
-
.then((
|
|
132
|
+
.then(() => ensureConnected(root, game))
|
|
133
|
+
.then(() => ({ to: game.version }));
|
|
126
134
|
};
|
|
127
135
|
|
|
128
136
|
// [function]
|
|
129
137
|
|
|
138
|
+
// a git deploy needs no login, and never uses one: anyone who can push can
|
|
139
|
+
// release, and so can tools other than arc. Every lookup is public, so its
|
|
140
|
+
// answer is the same whoever runs it, and true when it's asked; the release
|
|
141
|
+
// pipeline has the final word.
|
|
130
142
|
const main = function (conf, { onPredeployBegin, ...handler }) {
|
|
131
143
|
const root = conf.root;
|
|
132
144
|
if (onPredeployBegin) {
|
|
@@ -12,6 +12,8 @@ const ensureUnpublished = ac.ensureUnpublished;
|
|
|
12
12
|
|
|
13
13
|
// [function]
|
|
14
14
|
|
|
15
|
+
// a direct deploy needs a login. Each lookup uses its token or not, as it
|
|
16
|
+
// needs, and its answer is true when it's asked.
|
|
15
17
|
const main = function (current, conf, { onPredeployBegin, ...handler }) {
|
|
16
18
|
if (onPredeployBegin) {
|
|
17
19
|
onPredeployBegin({ root: conf.root });
|
package/src/api.js
CHANGED
|
@@ -136,19 +136,9 @@ const release = function (id, params, headers) {
|
|
|
136
136
|
return request.get(endpoint(pathOf`/releases/${id}`, params), headers);
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
-
// [function]
|
|
140
|
-
|
|
141
|
-
const accountReleases = function (id, params, headers) {
|
|
142
|
-
return request.get(
|
|
143
|
-
endpoint(pathOf`/accounts/${id}/releases`, params),
|
|
144
|
-
headers,
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
139
|
// [export]
|
|
149
140
|
|
|
150
141
|
module.exports = {
|
|
151
|
-
accountReleases,
|
|
152
142
|
auth,
|
|
153
143
|
discoverGame,
|
|
154
144
|
discoverGameBuild,
|
package/src/config/code.js
CHANGED
|
@@ -49,10 +49,11 @@ const CLI = {
|
|
|
49
49
|
};
|
|
50
50
|
// a release's reasons, from the pipeline (the API's
|
|
51
51
|
// db/type/release_reason.sql). The CLI shares them, so a name means the same
|
|
52
|
-
// thing wherever it appears: GAME_UNAVAILABLE, INTERNAL,
|
|
53
|
-
// and VERSION_EXISTS are the CLI's too.
|
|
52
|
+
// thing wherever it appears: GAME_HANDLE_CHANGED, GAME_UNAVAILABLE, INTERNAL,
|
|
53
|
+
// as well as REPO_NOT_CONNECTED and VERSION_EXISTS, are the CLI's too.
|
|
54
54
|
const RELEASE = {
|
|
55
55
|
BUILD_RATE_LIMITED: "build_rate_limited",
|
|
56
|
+
GAME_HANDLE_CHANGED: "game_handle_changed",
|
|
56
57
|
GAME_LIMIT_REACHED: "game_limit_reached",
|
|
57
58
|
GAME_MISMATCH: "game_mismatch",
|
|
58
59
|
GAME_UNAVAILABLE: "game_unavailable",
|
package/src/parser/env.js
CHANGED
|
@@ -12,6 +12,7 @@ const fs = require("fs-extra");
|
|
|
12
12
|
|
|
13
13
|
const cfgcode = require("../config/code");
|
|
14
14
|
const error = require("../util/error");
|
|
15
|
+
const lockfile = require("../util/lockfile");
|
|
15
16
|
const objs = require("../util/objs");
|
|
16
17
|
const phrase = require("../phrase");
|
|
17
18
|
|
|
@@ -19,14 +20,13 @@ const phrase = require("../phrase");
|
|
|
19
20
|
|
|
20
21
|
const ArcError = error.ArcError;
|
|
21
22
|
const deepCompact = objs.deepCompact;
|
|
23
|
+
const detect = lockfile.detect;
|
|
22
24
|
const join = path.join;
|
|
23
25
|
const pathExists = fs.pathExists;
|
|
24
26
|
const readFile = fs.readFile;
|
|
25
27
|
|
|
26
28
|
// [declare]
|
|
27
29
|
|
|
28
|
-
// the build a package.json build script stands for.
|
|
29
|
-
const NPM_RUN_BUILD = "npm run build";
|
|
30
30
|
const PACKAGE = "package.json";
|
|
31
31
|
|
|
32
32
|
// [function]
|
|
@@ -53,13 +53,19 @@ const parseJson = function (buf) {
|
|
|
53
53
|
|
|
54
54
|
// [function]
|
|
55
55
|
|
|
56
|
-
// package.json's version, and its build script as
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
// locally.
|
|
60
|
-
|
|
56
|
+
// package.json's version, and its build script as `<manager> run build`, run
|
|
57
|
+
// with the package manager its lockfile names (npm without one): the script
|
|
58
|
+
// finds the project's own tools, and its prebuild and postbuild run, as they do
|
|
59
|
+
// locally. A Yarn project on Plug'n'Play has no node_modules, so only Yarn
|
|
60
|
+
// finds its tools.
|
|
61
|
+
const extract = function (conf, manager) {
|
|
62
|
+
if (!Object.keys(conf).length) {
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
61
65
|
const game = { version: conf.version };
|
|
62
|
-
const workflow = conf.scripts?.build
|
|
66
|
+
const workflow = conf.scripts?.build
|
|
67
|
+
? { build: `${manager || "npm"} run build` }
|
|
68
|
+
: {};
|
|
63
69
|
return deepCompact({ game, workflow }) ?? {};
|
|
64
70
|
};
|
|
65
71
|
|
|
@@ -70,7 +76,7 @@ const main = function (root) {
|
|
|
70
76
|
return pathExists(file)
|
|
71
77
|
.then((exists) => (exists ? readFile(file, "utf8") : null))
|
|
72
78
|
.then((buf) => (buf === null ? {} : parseJson(buf)))
|
|
73
|
-
.then((conf) => (
|
|
79
|
+
.then((conf) => extract(conf, detect(root)));
|
|
74
80
|
};
|
|
75
81
|
|
|
76
82
|
// [export]
|
package/src/phrase.js
CHANGED
|
@@ -225,6 +225,17 @@ const gameHandleTaken = function (handle) {
|
|
|
225
225
|
|
|
226
226
|
// [function]
|
|
227
227
|
|
|
228
|
+
// a git release that would change the game's handle, which only a direct
|
|
229
|
+
// deploy does.
|
|
230
|
+
const gameHandleChanged = function (handle, current) {
|
|
231
|
+
return blocks(
|
|
232
|
+
`The handle in arcadible.toml (${handle ?? "none"}) isn't the game's on ${TITLE} (${current ?? "none"}).`,
|
|
233
|
+
`Only ${cmdDeploy()} changes a handle: deploy with it, or set the handle back.`,
|
|
234
|
+
);
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// [function]
|
|
238
|
+
|
|
228
239
|
const gameHandleLapsed = function (handle) {
|
|
229
240
|
return `Handle ${handle} lapsed, so deploying without it.\nA production release takes it back.`;
|
|
230
241
|
};
|
|
@@ -764,12 +775,12 @@ const packageUncompressedTooLarge = function (size) {
|
|
|
764
775
|
|
|
765
776
|
// a failed release's message, a sentence to a line, then its reason code
|
|
766
777
|
// and where to see it.
|
|
767
|
-
// `studio` is the game's builds in Studio,
|
|
768
|
-
//
|
|
778
|
+
// `studio` is the game's builds in Studio, which asks whoever opens it to
|
|
779
|
+
// log in.
|
|
769
780
|
const releaseFailed = function ({ message }, studio) {
|
|
770
781
|
return blocks(
|
|
771
782
|
(message ?? "No reason given.").split(/(?<=\.)\s+/u).join("\n"),
|
|
772
|
-
|
|
783
|
+
[`${TITLE} Studio:`, studio],
|
|
773
784
|
);
|
|
774
785
|
};
|
|
775
786
|
|
|
@@ -791,18 +802,12 @@ const releaseTimedOut = function (
|
|
|
791
802
|
{ actions, found, git, studio },
|
|
792
803
|
) {
|
|
793
804
|
const head = `Waited ${waited(seconds)} for v${version}.`;
|
|
794
|
-
if (
|
|
805
|
+
if (found || !git) {
|
|
795
806
|
return blocks(head, [
|
|
796
807
|
`It may still finish. See it in ${TITLE} Studio:`,
|
|
797
808
|
studio,
|
|
798
809
|
]);
|
|
799
810
|
}
|
|
800
|
-
if (found) {
|
|
801
|
-
return blocks(head, [
|
|
802
|
-
"It may still finish.",
|
|
803
|
-
`The ${TITLE} check on the tagged commit says how it went.`,
|
|
804
|
-
]);
|
|
805
|
-
}
|
|
806
811
|
return blocks(
|
|
807
812
|
head,
|
|
808
813
|
[
|
|
@@ -1092,6 +1097,7 @@ module.exports = {
|
|
|
1092
1097
|
docMediaType,
|
|
1093
1098
|
docTagUnallowed,
|
|
1094
1099
|
errorCode,
|
|
1100
|
+
gameHandleChanged,
|
|
1095
1101
|
gameHandleLapsed,
|
|
1096
1102
|
gameHandleLimit,
|
|
1097
1103
|
gameHandleTaken,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// [import]
|
|
4
|
+
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
|
|
8
|
+
// [use]
|
|
9
|
+
|
|
10
|
+
const existsSync = fs.existsSync; // eslint-disable-line no-sync
|
|
11
|
+
const join = path.join;
|
|
12
|
+
|
|
13
|
+
// [declare]
|
|
14
|
+
|
|
15
|
+
// each package manager, and the lockfiles that mean a project uses it, in the
|
|
16
|
+
// order they're checked, as the release tools' install checks them.
|
|
17
|
+
const LOCKFILES = [
|
|
18
|
+
["npm", ["package-lock.json", "npm-shrinkwrap.json"]],
|
|
19
|
+
["pnpm", ["pnpm-lock.yaml"]],
|
|
20
|
+
["yarn", ["yarn.lock"]],
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// [function]
|
|
24
|
+
|
|
25
|
+
// the package manager a project's lockfile names, or "" when it has none.
|
|
26
|
+
const detect = function (root) {
|
|
27
|
+
const found = LOCKFILES.find(([, names]) =>
|
|
28
|
+
names.some((name) => existsSync(join(root, name))),
|
|
29
|
+
);
|
|
30
|
+
return found ? found[0] : "";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// [export]
|
|
34
|
+
|
|
35
|
+
module.exports = { detect };
|
package/src/util/video.js
CHANGED
|
@@ -6,8 +6,8 @@ const path = require("node:path");
|
|
|
6
6
|
|
|
7
7
|
// [import]
|
|
8
8
|
|
|
9
|
-
const createFile = require("mp4box").createFile;
|
|
10
9
|
const fs = require("fs-extra");
|
|
10
|
+
const mp4box = require("mp4box");
|
|
11
11
|
|
|
12
12
|
// [import]
|
|
13
13
|
|
|
@@ -18,6 +18,7 @@ const phrase = require("../phrase");
|
|
|
18
18
|
|
|
19
19
|
// [use]
|
|
20
20
|
|
|
21
|
+
const createFile = mp4box.createFile;
|
|
21
22
|
const checkAspect = media.checkAspect;
|
|
22
23
|
const checkSize = media.checkSize;
|
|
23
24
|
const extname = path.extname;
|
|
@@ -30,6 +31,15 @@ const statSync = fs.statSync; // eslint-disable-line no-sync
|
|
|
30
31
|
|
|
31
32
|
const NO_TRACK = "no-video-track";
|
|
32
33
|
|
|
34
|
+
// [configure]
|
|
35
|
+
|
|
36
|
+
// mp4box prints what it recovers from at its error level, which setLogLevel
|
|
37
|
+
// can't turn down: its colr parser misreads an ICC profile by the box's
|
|
38
|
+
// header, and says so for a video it reads correctly. arc reports a bad video
|
|
39
|
+
// itself, so mp4box only passes on the errors it sends to the file's onError.
|
|
40
|
+
mp4box.Log.error = (mod, msg, isofile) => isofile?.onError?.(mod, msg);
|
|
41
|
+
mp4box.Log.warn = () => {};
|
|
42
|
+
|
|
33
43
|
// [function]
|
|
34
44
|
|
|
35
45
|
const readMp4 = function (file) {
|