arcadible 1.0.0 → 1.0.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.
package/bin/arc-deploy.js CHANGED
@@ -19,6 +19,7 @@ const cfgpackage = require("../src/config/package");
19
19
  const cfgproduct = require("../src/config/product");
20
20
  const deploy = require("../src/cli/deploy");
21
21
  const error = require("../src/util/error");
22
+ const links = require("../src/util/links");
22
23
  const log = require("../src/util/log");
23
24
  const output = require("../src/util/output");
24
25
  const pack = require("../src/cli/pack");
@@ -250,6 +251,9 @@ const start = function (argv) {
250
251
  // the game's account, when Arcadible could say: a git deploy's owner waits
251
252
  // among their own releases.
252
253
  let owner = null;
254
+ // whether the handle rules held the handle back from this release, so the
255
+ // game's links are by id.
256
+ let held = false;
253
257
  // the project, parsed once and given to each step. A build can write files
254
258
  // the manifest reads, such as art, so it's parsed again after one runs.
255
259
  let parsed = null;
@@ -309,6 +313,7 @@ const start = function (argv) {
309
313
  .then(([current, predeployed]) => {
310
314
  sw.stop(true);
311
315
  owner = predeployed.owner ?? null;
316
+ held = predeployed.held ?? false;
312
317
  sw = new SpinnerWheel("Building... %s");
313
318
  sw.start(git || json || quiet);
314
319
  return Promise.all([
@@ -378,7 +383,12 @@ const start = function (argv) {
378
383
  pb.stop();
379
384
  }
380
385
  // the game and release are for waiting, not printing.
381
- const shown = { ...deployed };
386
+ const shown = {
387
+ ...deployed,
388
+ ...(held
389
+ ? links.published({ id: deployed.game, version: deployed.version.to })
390
+ : {}),
391
+ };
382
392
  delete shown.game;
383
393
  delete shown.release;
384
394
  const result = { ...(git ? shown : { built, ...shown }), warnings };
package/package.json CHANGED
@@ -65,5 +65,5 @@
65
65
  "scripts": {
66
66
  "test": "node --test \"test/**/*.test.js\""
67
67
  },
68
- "version": "1.0.0"
68
+ "version": "1.0.2"
69
69
  }
@@ -5,6 +5,7 @@
5
5
  const api = require("../../api");
6
6
  const cfgcode = require("../../config/code");
7
7
  const error = require("../../util/error");
8
+ const links = require("../../util/links");
8
9
  const phrase = require("../../phrase");
9
10
  const published = require("./published");
10
11
 
@@ -38,30 +39,58 @@ const ensureOwned = function (current, id) {
38
39
 
39
40
  // [function]
40
41
 
41
- // fails when the handle is another game's, whoever owns it. A game without a
42
- // handle has none to check.
43
- const ensureHandle = function ({ handle, id }) {
42
+ // fails when the handle is taken: another game's, held for another account,
43
+ // or reserved. When the handle rules keep it from this release (the limit on
44
+ // unreleased games' handles, or one that lapsed from this account), it warns
45
+ // and deploys anyway, as the game keeps the handle it has, or none, and
46
+ // resolves with true. A game without a handle has none to check.
47
+ const ensureHandle = function (current, { handle, id, version }, handler) {
44
48
  if ((handle ?? null) === null) {
45
49
  return Promise.resolve(null);
46
50
  }
47
- return api.discoverGame(handle).then((game) => {
48
- if (game.id !== id) {
49
- throw new ArcError(
50
- cfgcode.GAME_HANDLE_TAKEN,
51
- phrase.gameHandleTaken(handle),
52
- );
51
+ const warn = (code, message) => {
52
+ if (handler?.onWarning) {
53
+ handler.onWarning({ code, message });
53
54
  }
54
- }, ignoreMissing);
55
+ };
56
+ return api
57
+ .gameHandle(
58
+ id,
59
+ handle,
60
+ { channel: links.channel(version) },
61
+ api.auth(current?.session?.access_token),
62
+ )
63
+ .then(({ status }) => {
64
+ if (status === "taken") {
65
+ throw new ArcError(
66
+ cfgcode.GAME_HANDLE_TAKEN,
67
+ phrase.gameHandleTaken(handle),
68
+ );
69
+ }
70
+ if (status === "limit") {
71
+ warn(cfgcode.WARNING.GAME_HANDLE_LIMIT, phrase.gameHandleLimit(handle));
72
+ return true;
73
+ }
74
+ if (status === "lapsed") {
75
+ warn(
76
+ cfgcode.WARNING.GAME_HANDLE_LAPSED,
77
+ phrase.gameHandleLapsed(handle),
78
+ );
79
+ return true;
80
+ }
81
+ return false;
82
+ }, ignoreMissing);
55
83
  };
56
84
 
57
85
  // [function]
58
86
 
59
- // resolves with the game once its id, and its handle if it has one, are
60
- // free or already its own.
61
- const ensureId = function (current, game) {
87
+ // resolves with the game once its id is free or already its own, and its
88
+ // handle, if it has one, isn't taken; `held` when the rules hold the handle
89
+ // back from this release, so its links are by id.
90
+ const ensureId = function (current, game, handler) {
62
91
  return ensureOwned(current, game.id)
63
- .then(() => ensureHandle(game))
64
- .then(() => game);
92
+ .then(() => ensureHandle(current, game, handler))
93
+ .then((held) => ({ ...game, held: Boolean(held) }));
65
94
  };
66
95
 
67
96
  // [function]
@@ -12,14 +12,14 @@ const ensureUnpublished = ac.ensureUnpublished;
12
12
 
13
13
  // [function]
14
14
 
15
- const main = function (current, conf, { onPredeployBegin }) {
15
+ const main = function (current, conf, { onPredeployBegin, ...handler }) {
16
16
  if (onPredeployBegin) {
17
17
  onPredeployBegin({ root: conf.root });
18
18
  }
19
19
  return given(conf)
20
- .then(({ game }) => ensureId(current, game))
20
+ .then(({ game }) => ensureId(current, game, handler))
21
21
  .then((game) => ensureUnpublished(current, game))
22
- .then((game) => ({ to: game.version }));
22
+ .then((game) => ({ held: game.held, to: game.version }));
23
23
  };
24
24
 
25
25
  // [export]
package/src/api.js CHANGED
@@ -109,6 +109,17 @@ const gameBuild = function (id, version, params, headers) {
109
109
 
110
110
  // [function]
111
111
 
112
+ // whether the caller's game could take a handle on a deploy to `channel`:
113
+ // its status is available, taken, limit, or lapsed.
114
+ const gameHandle = function (id, handle, params, headers) {
115
+ return request.get(
116
+ endpoint(`/games/${id}/handles/${handle}`, params),
117
+ headers,
118
+ );
119
+ };
120
+
121
+ // [function]
122
+
112
123
  const release = function (id, params, headers) {
113
124
  return request.get(endpoint(`/releases/${id}`, params), headers);
114
125
  };
@@ -131,6 +142,7 @@ module.exports = {
131
142
  discoverGameRepo,
132
143
  flow,
133
144
  gameBuild,
145
+ gameHandle,
134
146
  postAuthRefresh,
135
147
  postFlow,
136
148
  postUpload,
@@ -104,6 +104,8 @@ const ISSUE = {
104
104
  const WARNING = {
105
105
  DEPLOY_DIR_NOT_BUILT: "deploy_dir_not_built",
106
106
  FIELD_UNKNOWN: "field_unknown",
107
+ GAME_HANDLE_LAPSED: "game_handle_lapsed",
108
+ GAME_HANDLE_LIMIT: "game_handle_limit",
107
109
  VERSION_UNCHECKED: "version_unchecked",
108
110
  };
109
111
  // every error code, for checking one exists.
package/src/phrase.js CHANGED
@@ -207,6 +207,18 @@ const gameHandleTaken = function (handle) {
207
207
 
208
208
  // [function]
209
209
 
210
+ const gameHandleLapsed = function (handle) {
211
+ return `Handle ${handle} lapsed: it comes back with a production release, so deploying without it.`;
212
+ };
213
+
214
+ // [function]
215
+
216
+ const gameHandleLimit = function (handle) {
217
+ return `Handle ${handle} not applied: your unreleased games already hold 5 handles, so deploying without it.`;
218
+ };
219
+
220
+ // [function]
221
+
210
222
  const gameNotDeployed = function (game) {
211
223
  return blocks(`${game} isn't on ${TITLE} yet.`, [
212
224
  `Deploy it once with ${cmdDeploy()}.`,
@@ -1020,6 +1032,8 @@ module.exports = {
1020
1032
  docMediaType,
1021
1033
  docTagUnallowed,
1022
1034
  errorCode,
1035
+ gameHandleLapsed,
1036
+ gameHandleLimit,
1023
1037
  gameHandleTaken,
1024
1038
  gameIdMissing,
1025
1039
  gameNotDeployed,
package/src/serve/page.js CHANGED
@@ -57,7 +57,7 @@ const html = function (game) {
57
57
  <html lang="en">
58
58
  <head>
59
59
  <meta charset="utf-8">
60
- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, viewport-fit=cover">
60
+ <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
61
61
  <title>${escapeHtml(game.title)}</title>
62
62
  <style>html,body{margin:0;height:100%;overflow:hidden;background:#000}iframe{display:block;width:100%;height:100%;border:0;visibility:hidden}</style>
63
63
  </head>