bdy 1.23.9-stage → 1.23.11-dev

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.23.9-stage",
4
+ "version": "1.23.11-dev",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",
@@ -139,6 +139,7 @@ class Agent extends events_1.default {
139
139
  try {
140
140
  if (data.agent.action)
141
141
  await this.makeAction(data.agent.action);
142
+ this.reclearLostUpdateStatus(data.agent.action);
142
143
  const filtered = (data.tunnels || []).filter((t) => !!t.domain);
143
144
  this.refreshTunnels(filtered);
144
145
  }
@@ -290,12 +291,50 @@ class Agent extends events_1.default {
290
291
  return;
291
292
  this.updateStatusExpiry = setTimeout(() => {
292
293
  this.updateStatusExpiry = null;
293
- this.ackAction();
294
+ this.queueUpdateStatusClear();
294
295
  }, utils_1.AGENT_UPDATE_STATUS_TTL_MS);
295
296
  // A foreground tunnel reporting UNSUPPORTED exits as soon as it has acked, and must
296
297
  // not be held open for the rest of the window just to tidy up after itself
297
298
  this.updateStatusExpiry.unref();
298
299
  }
300
+ // Queued rather than sent, because a fetch of our own here would go out within
301
+ // milliseconds of refreshIn15's tick: this expiry and that interval are both armed when
302
+ // the process starts, and the ttl is a multiple of the interval. The backend writes the
303
+ // whole agent row per request, so the tick - which carries no action at all - rewrites
304
+ // the field this clear just emptied, and the outcome is back with nobody left to remove
305
+ // it. Riding the next scheduled fetch keeps it to one write per tick.
306
+ queueUpdateStatusClear() {
307
+ if (!this.socket)
308
+ return;
309
+ // An outcome reported in the meantime is the newer truth and has a window of its own
310
+ if (this.socket.pendingAction !== null)
311
+ return;
312
+ this.socket.setPendingAction('');
313
+ }
314
+ // An outcome still on the record after its window is one whose clear did not survive -
315
+ // see queueUpdateStatusClear for how that happens, and note it can equally be a status
316
+ // left behind by a process that died before its expiry ever fired. Either way nothing
317
+ // dates the value, so it would sit there until the next update request: queue the clear
318
+ // again and let the fetch after this one carry it.
319
+ reclearLostUpdateStatus(action) {
320
+ if (typeof action !== 'string')
321
+ return;
322
+ const statuses = Object.values(tunnel_1.TUNNEL_AGENT_UPDATE_STATUS);
323
+ if (!statuses.includes(action))
324
+ return;
325
+ // Never an outcome, and the one value the front reads as an unknown result
326
+ if (action === tunnel_1.TUNNEL_AGENT_UPDATE_STATUS.STARTED)
327
+ return;
328
+ // Still inside the window this status is being shown for
329
+ if (this.updateStatusExpiry)
330
+ return;
331
+ this.queueUpdateStatusClear();
332
+ // Sent from here rather than left for the next scheduled fetch, unlike the expiry above:
333
+ // this runs on a fetch response, which is as far from the next refresh tick as the
334
+ // schedule ever gets, so there is nothing to collide with. Waiting for two more fetches
335
+ // would leave a confirmation standing for a minute and a half.
336
+ this.ackAction();
337
+ }
299
338
  // For a status with no ack to ride on - STARTED, reported while the download is still
300
339
  // running. Passes null so that if the status has somehow already gone out, this does
301
340
  // not overwrite it with an empty action.
@@ -178,6 +178,8 @@ commandSandboxCreate.action(async (options) => {
178
178
  output_1.default.cyan(result.identifier);
179
179
  output_1.default.dim('SSH: ', false);
180
180
  output_1.default.cyan(`ssh ${result.ssh_host} -p ${result.ssh_port}`);
181
+ output_1.default.dim('SSH via CLI: ', false);
182
+ output_1.default.cyan(`bdy sb ssh ${result.identifier}`);
181
183
  output_1.default.dim('Web terminal: ', false);
182
184
  output_1.default.cyan(result.html_url);
183
185
  output_1.default.green(texts_1.TXT_SANDBOX_CREATED);
@@ -44,6 +44,7 @@ commandSandboxGet.action(async (identifier, options) => {
44
44
  ? `ssh ${sandbox.ssh_host} -p ${sandbox.ssh_port}`
45
45
  : '-',
46
46
  ],
47
+ ['SSH via CLI', sandbox.identifier ? `bdy sb ssh ${sandbox.identifier}` : '-']
47
48
  ];
48
49
  if (sandbox.endpoints && sandbox.endpoints.length > 0) {
49
50
  data.push([
@@ -121,11 +121,17 @@ exports.AGENT_UPDATE_MAX_ATTEMPTS = 3;
121
121
  // only has to be read. Generous on purpose: it is only ever reached when the counter
122
122
  // cannot be persisted, so it must not fire on an agent that is merely slow to come up.
123
123
  exports.AGENT_UPDATE_PROBATION_MS = 30 * 60 * 1000;
124
- // How long a reported update outcome stays on the agent record before the agent clears it
125
- // again. An outcome is a confirmation for whoever is watching the update, not a property of
124
+ // How long a reported update outcome stays on the agent record before the agent queues its
125
+ // clear. An outcome is a confirmation for whoever is watching the update, not a property of
126
126
  // the agent: nothing re-evaluates it, so one left in place would still claim a machine is
127
127
  // missing admin rights long after that was fixed. The agent log keeps the durable record.
128
- exports.AGENT_UPDATE_STATUS_TTL_MS = 30 * 1000;
128
+ //
129
+ // Shorter than the refresh interval on purpose. The clear does not go out on this timer - it
130
+ // rides the next scheduled fetch (see queueUpdateStatusClear) - and those are 15s apart at
131
+ // first and 45s apart after that. Expiring inside the first interval catches the fetch at
132
+ // 15s; anything past it waits for the one at 60s, so a longer ttl here shows the outcome for
133
+ // four times as long as it says.
134
+ exports.AGENT_UPDATE_STATUS_TTL_MS = 10 * 1000;
129
135
  exports.SUGGESTED_BROWSER_VERSION = '130.0.6723.69';
130
136
  exports.ARTIFACT_DEFAULT_VERSION = 'latest';
131
137
  exports.DEFAULT_SANDBOX_CP_USER = 'buddy';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.23.9-stage",
4
+ "version": "1.23.11-dev",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",