bdy 1.22.99-stage → 1.23.1-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.
- package/distTs/package.json +3 -2
- package/distTs/src/agent/agent.js +21 -0
- package/distTs/src/agent/manager.js +161 -16
- package/distTs/src/agent/system.js +230 -2
- package/distTs/src/agent/windows.js +1 -0
- package/distTs/src/command/agent/selftest.js +21 -0
- package/distTs/src/command/agent/update.js +5 -0
- package/distTs/src/command/agent.js +2 -0
- package/distTs/src/texts.js +36 -11
- package/distTs/src/types/tunnel.js +1 -0
- package/distTs/src/utils.js +12 -2
- package/package.json +3 -2
package/distTs/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bdy",
|
|
3
3
|
"preferGlobal": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.23.1-dev",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://buddy.works/docs/cli",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"e2e:pipeline": "vitest run --config e2e/vitest.config.ts e2e/modules/pipeline/",
|
|
27
27
|
"e2e:tunnel": "vitest run --config e2e/vitest.config.ts e2e/modules/tunnel/",
|
|
28
28
|
"e2e:agent": "vitest run --config e2e/vitest.config.ts e2e/modules/agent/",
|
|
29
|
-
"e2e:distro": "vitest run --config e2e/vitest.config.ts e2e/modules/distro/"
|
|
29
|
+
"e2e:distro": "vitest run --config e2e/vitest.config.ts e2e/modules/distro/",
|
|
30
|
+
"unit": "vitest run --config vitest.config.ts"
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"distTs"
|
|
@@ -243,6 +243,14 @@ class Agent extends events_1.default {
|
|
|
243
243
|
this.socket.update(!this.disabled, this.getTunnelsUpdate(), force);
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
+
// A pending action stays on the agent until an empty one is sent back, and it is
|
|
247
|
+
// re-read on every fetch - so an action that is refused rather than acked would be
|
|
248
|
+
// retried on each refresh instead of once.
|
|
249
|
+
ackAction() {
|
|
250
|
+
if (this.socket) {
|
|
251
|
+
this.socket.fetch(!this.disabled, '', null, false, this.getTunnelsUpdate(), true);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
246
254
|
async makeAction(action) {
|
|
247
255
|
if (action === tunnel_1.TUNNEL_AGENT_ACTION.DELETE) {
|
|
248
256
|
if (this.manager) {
|
|
@@ -250,6 +258,19 @@ class Agent extends events_1.default {
|
|
|
250
258
|
}
|
|
251
259
|
return this.delete();
|
|
252
260
|
}
|
|
261
|
+
if (action === tunnel_1.TUNNEL_AGENT_ACTION.UPDATE) {
|
|
262
|
+
// Without a manager this is a foreground tunnel, not an installed agent, so
|
|
263
|
+
// there is no binary of ours to replace - ack so it is not asked again.
|
|
264
|
+
if (!this.manager)
|
|
265
|
+
return this.ackAction();
|
|
266
|
+
// Deliberately not awaited. Callers use this promise to gate tunnel reconciliation
|
|
267
|
+
// (see _onSocketFetch), and the swap downloads a whole release - awaiting it would
|
|
268
|
+
// leave tunnels unreconciled for the duration, including when the update then
|
|
269
|
+
// fails. selfUpdate guards its own re-entry and reports its own failures, so there
|
|
270
|
+
// is nothing here worth waiting for.
|
|
271
|
+
this.manager.selfUpdate().catch((err) => logger_1.default.error(err));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
253
274
|
}
|
|
254
275
|
refreshTunnels(tunnels) {
|
|
255
276
|
if (this.tunnelsUpdating)
|
|
@@ -21,6 +21,10 @@ class AgentManagerClass {
|
|
|
21
21
|
host;
|
|
22
22
|
token;
|
|
23
23
|
port;
|
|
24
|
+
updating = false;
|
|
25
|
+
// shutdown() only schedules the exit, so it can be a moment before the process is
|
|
26
|
+
// actually gone. Anything that must not start in that window checks this.
|
|
27
|
+
exiting = false;
|
|
24
28
|
sshHostKey;
|
|
25
29
|
agent;
|
|
26
30
|
ws;
|
|
@@ -54,24 +58,134 @@ class AgentManagerClass {
|
|
|
54
58
|
start(id, host, token, port, onProcessExit = () => { }) {
|
|
55
59
|
const onExit = () => {
|
|
56
60
|
onProcessExit();
|
|
57
|
-
|
|
58
|
-
this.ws.clients.forEach((client) => client.terminate());
|
|
59
|
-
this.ws.close();
|
|
60
|
-
}
|
|
61
|
-
if (this.server) {
|
|
62
|
-
if (!(0, utils_1.isWindows)()) {
|
|
63
|
-
this.connections.forEach((socket) => socket.resetAndDestroy());
|
|
64
|
-
}
|
|
65
|
-
this.server.close(() => {
|
|
66
|
-
output_1.default.exitNormal();
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
setTimeout(() => output_1.default.exitNormal(), 1000);
|
|
61
|
+
this.shutdown();
|
|
70
62
|
};
|
|
71
63
|
process.on('SIGINT', onExit);
|
|
72
64
|
process.on('SIGTERM', onExit);
|
|
73
65
|
process.on('SIGQUIT', onExit);
|
|
74
|
-
|
|
66
|
+
// Anything load() throws would otherwise be an unhandled rejection: no entry in the
|
|
67
|
+
// agent log, just a stack on stderr that a service swallows. Exit non-zero so the
|
|
68
|
+
// supervisor still retries, but say why first.
|
|
69
|
+
this.load(id, host, token, port).catch((err) => {
|
|
70
|
+
try {
|
|
71
|
+
logger_1.default.error(err);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// best effort - a broken filesystem is a plausible reason for being here at all
|
|
75
|
+
}
|
|
76
|
+
output_1.default.exitError(err);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// Closes the listener before exiting. A self update depends on this: the supervisor
|
|
80
|
+
// starts the replacement as soon as we are gone, and a port still held by this
|
|
81
|
+
// process would meet it with EADDRINUSE.
|
|
82
|
+
shutdown() {
|
|
83
|
+
this.exiting = true;
|
|
84
|
+
if (this.ws) {
|
|
85
|
+
this.ws.clients.forEach((client) => client.terminate());
|
|
86
|
+
this.ws.close();
|
|
87
|
+
}
|
|
88
|
+
if (this.server) {
|
|
89
|
+
if (!(0, utils_1.isWindows)()) {
|
|
90
|
+
this.connections.forEach((socket) => socket.resetAndDestroy());
|
|
91
|
+
}
|
|
92
|
+
this.server.close(() => {
|
|
93
|
+
output_1.default.exitNormal();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
setTimeout(() => output_1.default.exitNormal(), 1000);
|
|
97
|
+
}
|
|
98
|
+
// Called on every start. If the previous process swapped the binary, this is the
|
|
99
|
+
// first look at whether the new one works. Rolling back is keyed on how many times
|
|
100
|
+
// we have been started since the swap, not on whether the api is reachable: a
|
|
101
|
+
// healthy binary does not restart, while an api outage would look the same from here
|
|
102
|
+
// and would revert the whole fleet at once.
|
|
103
|
+
//
|
|
104
|
+
// Returns false when it has rolled back and this process is on its way out, so the
|
|
105
|
+
// caller must not carry on starting up.
|
|
106
|
+
checkUpdateProbation() {
|
|
107
|
+
const state = this.system.loadUpdateProbation();
|
|
108
|
+
if (!state)
|
|
109
|
+
return true;
|
|
110
|
+
const attempts = this.system.registerUpdateAttempt();
|
|
111
|
+
// The deadline only matters when the count cannot be persisted, in which case it is
|
|
112
|
+
// the sole way out of a restart loop. Checked at startup like the count, so an agent
|
|
113
|
+
// that is up and merely cannot reach the api is never rolled back.
|
|
114
|
+
const expired = Date.now() - state.startedAt > utils_1.AGENT_UPDATE_PROBATION_MS;
|
|
115
|
+
if (attempts <= utils_1.AGENT_UPDATE_MAX_ATTEMPTS && !expired) {
|
|
116
|
+
logger_1.default.info((0, texts_1.LOG_AGENT_UPDATE_ATTEMPT)(attempts, utils_1.AGENT_UPDATE_MAX_ATTEMPTS));
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (!this.system.rollbackUpdate(state.to)) {
|
|
120
|
+
// Nothing to restore, so running the binary we have is the only option left
|
|
121
|
+
logger_1.default.error(texts_1.LOG_AGENT_UPDATE_ROLLBACK_MISSING);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
logger_1.default.error((0, texts_1.LOG_AGENT_UPDATE_ROLLED_BACK)(state.from, state.to));
|
|
125
|
+
// Exit rather than keep running: the restored binary only takes effect when the
|
|
126
|
+
// service starts it, and this process is still the new one.
|
|
127
|
+
this.shutdown();
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
// Triggered remotely through the agent's `action` field. Every path that does not
|
|
131
|
+
// end in a restart has to ack, or the flag stays set on the backend and the update
|
|
132
|
+
// is retried on every refresh.
|
|
133
|
+
async selfUpdate() {
|
|
134
|
+
// `updating` is released in the finally below, but after a swap this process is only
|
|
135
|
+
// scheduled to exit, not gone. A sync push arriving in that window would otherwise
|
|
136
|
+
// re-enter and swap again - and the second swap would move the binary we just
|
|
137
|
+
// installed into the rollback slot, leaving nothing good to roll back to.
|
|
138
|
+
if (this.updating || this.exiting)
|
|
139
|
+
return;
|
|
140
|
+
this.updating = true;
|
|
141
|
+
try {
|
|
142
|
+
if (this.system.isStandaloneInstall()) {
|
|
143
|
+
logger_1.default.error(texts_1.LOG_AGENT_UPDATE_STANDALONE);
|
|
144
|
+
return this.agent?.ackAction();
|
|
145
|
+
}
|
|
146
|
+
const hasAdminRights = await this.system.hasAdminRights();
|
|
147
|
+
if (!hasAdminRights) {
|
|
148
|
+
logger_1.default.error(texts_1.LOG_AGENT_UPDATE_NO_ADMIN);
|
|
149
|
+
return this.agent?.ackAction();
|
|
150
|
+
}
|
|
151
|
+
const current = (0, utils_1.getVersion)();
|
|
152
|
+
const latest = await (0, utils_1.getLatestVersion)();
|
|
153
|
+
if (!latest || latest === '0.0.0' || latest === current) {
|
|
154
|
+
logger_1.default.info((0, texts_1.LOG_AGENT_UPDATE_NOT_NEEDED)(current));
|
|
155
|
+
return this.agent?.ackAction();
|
|
156
|
+
}
|
|
157
|
+
logger_1.default.info((0, texts_1.LOG_AGENT_UPDATE_REQUESTED)(current, latest));
|
|
158
|
+
const target = latest.match(/^\d+\.\d+\.\d+/);
|
|
159
|
+
if (!target) {
|
|
160
|
+
logger_1.default.error(texts_1.LOG_AGENT_UPDATE_FAILED);
|
|
161
|
+
return this.agent?.ackAction();
|
|
162
|
+
}
|
|
163
|
+
const swapped = await this.system.swapBinaryToVersion(target[0]);
|
|
164
|
+
if (!swapped) {
|
|
165
|
+
logger_1.default.error((0, texts_1.LOG_AGENT_UPDATE_BINARY_INVALID)(latest));
|
|
166
|
+
return this.agent?.ackAction();
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
this.system.beginUpdateProbation(current, latest);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
// Losing the probation window costs us the rollback, not the update - the new
|
|
173
|
+
// binary is already in place, so carry on rather than restarting into limbo.
|
|
174
|
+
logger_1.default.error(err);
|
|
175
|
+
}
|
|
176
|
+
logger_1.default.info((0, texts_1.LOG_AGENT_UPDATE_SWAPPED)(latest));
|
|
177
|
+
// No ack here: the replacement acks on start, which also reports the new
|
|
178
|
+
// version. Acking now would clear the flag even if the restart never lands.
|
|
179
|
+
this.shutdown();
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
logger_1.default.error(texts_1.LOG_AGENT_UPDATE_FAILED);
|
|
183
|
+
logger_1.default.error(err);
|
|
184
|
+
this.agent?.ackAction();
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
this.updating = false;
|
|
188
|
+
}
|
|
75
189
|
}
|
|
76
190
|
async tryFetch() {
|
|
77
191
|
let delay = utils_1.AGENT_FETCH_RETRY_MIN;
|
|
@@ -87,6 +201,22 @@ class AgentManagerClass {
|
|
|
87
201
|
});
|
|
88
202
|
await this.agent.start();
|
|
89
203
|
this.status = tunnel_1.TUNNEL_AGENT_STATUS.ENABLED;
|
|
204
|
+
// Reaching the api is what makes an update stick: drop the previous binary and
|
|
205
|
+
// close the probation window so later restarts are not counted against it.
|
|
206
|
+
const probation = this.system.loadUpdateProbation();
|
|
207
|
+
if (probation) {
|
|
208
|
+
this.system.commitUpdate();
|
|
209
|
+
logger_1.default.info((0, texts_1.LOG_AGENT_UPDATE_COMMITTED)(probation.to));
|
|
210
|
+
}
|
|
211
|
+
// A rollback could not ack for itself: it happens before there is a socket. The
|
|
212
|
+
// action is still set, so without this the restored binary would start the same
|
|
213
|
+
// failing update again right here.
|
|
214
|
+
const pendingAck = this.system.loadPendingAck();
|
|
215
|
+
if (pendingAck) {
|
|
216
|
+
this.system.clearPendingAck();
|
|
217
|
+
this.agent.ackAction();
|
|
218
|
+
logger_1.default.error((0, texts_1.LOG_AGENT_UPDATE_ROLLBACK_ACKED)(pendingAck));
|
|
219
|
+
}
|
|
90
220
|
return;
|
|
91
221
|
}
|
|
92
222
|
catch (err) {
|
|
@@ -285,6 +415,9 @@ class AgentManagerClass {
|
|
|
285
415
|
id: this.id,
|
|
286
416
|
status: this.status,
|
|
287
417
|
version: (0, utils_1.getVersion)(),
|
|
418
|
+
// Lets `bdy agent update` bow out instead of stopping the service from under a
|
|
419
|
+
// swap. Liveness comes for free: if this process is gone, so is the answer.
|
|
420
|
+
updating: this.updating,
|
|
288
421
|
enabled: !this.agent?.disabled,
|
|
289
422
|
target: !!this.agent?.target,
|
|
290
423
|
tunneling: !!this.agent?.tunneling,
|
|
@@ -567,9 +700,16 @@ class AgentManagerClass {
|
|
|
567
700
|
this.ws = new WsServer({ noServer: true });
|
|
568
701
|
this.ws.on('connection', (con, id) => this.processWebsocketConnection(con, id));
|
|
569
702
|
this.server.on('upgrade', (req, socket, head) => this.processUpgrade(req, socket, head));
|
|
570
|
-
this.server.on('error',
|
|
703
|
+
this.server.on('error', (err) => {
|
|
571
704
|
if (err.code === 'EADDRINUSE') {
|
|
572
|
-
|
|
705
|
+
// Exit and let the supervisor retry (systemd Restart=always, launchd
|
|
706
|
+
// KeepAlive, nssm AppExit Restart). Tearing the agent down here would
|
|
707
|
+
// unregister a working agent server-side over a port that is busy for
|
|
708
|
+
// a moment - a restart racing its own predecessor is enough - and the
|
|
709
|
+
// machine would then need a manual reinstall with a new token.
|
|
710
|
+
const msg = (0, texts_1.LOG_ERROR_STARTING_AGENT_SERVER)(this.port || 0);
|
|
711
|
+
logger_1.default.error(msg);
|
|
712
|
+
output_1.default.exitError(msg);
|
|
573
713
|
}
|
|
574
714
|
else {
|
|
575
715
|
logger_1.default.error(err);
|
|
@@ -616,6 +756,11 @@ class AgentManagerClass {
|
|
|
616
756
|
await this.disableAgentAndExit(texts_1.ERR_SAVING_AGENT_CONFIG);
|
|
617
757
|
return;
|
|
618
758
|
}
|
|
759
|
+
// A rolled back update leaves this process exiting: binding the port and opening
|
|
760
|
+
// tunnels on the binary we just replaced would be pointless at best, and a fetch
|
|
761
|
+
// that came back 'agent not found' in that window would unregister us for good.
|
|
762
|
+
if (!this.checkUpdateProbation())
|
|
763
|
+
return;
|
|
619
764
|
this.createServer();
|
|
620
765
|
await this.tryFetch();
|
|
621
766
|
logger_1.default.info(texts_1.LOG_AGENT_STARTED);
|
|
@@ -90,7 +90,12 @@ class AgentSystem {
|
|
|
90
90
|
.catch(reject);
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
|
+
// The install/`bdy agent update` path, which replaces the binary in place. Any pending
|
|
94
|
+
// self-update probation is void afterwards - it would otherwise judge this binary and
|
|
95
|
+
// could roll back to one two versions old. `swapBinaryToVersion` does not come through
|
|
96
|
+
// here, so its own probation is not affected.
|
|
93
97
|
extractBinaryArchive() {
|
|
98
|
+
this.clearUpdateFiles();
|
|
94
99
|
(0, node_fs_1.rmSync)(this.getSystemBinaryPath(), { force: true });
|
|
95
100
|
return this.extractArchive(this.getBinaryArchivePath(), this.getSystemConfigDir());
|
|
96
101
|
}
|
|
@@ -123,9 +128,18 @@ class AgentSystem {
|
|
|
123
128
|
const str = (0, node_fs_1.readFileSync)(this.getNewAgentConfigPath(), 'utf-8');
|
|
124
129
|
return JSON.parse(str);
|
|
125
130
|
}
|
|
131
|
+
// Left behind by a self update. They have to go with the rest of the install: a stale
|
|
132
|
+
// probation file would make the next install count restarts against an update that
|
|
133
|
+
// never happened and then 'roll back' to a binary from before the uninstall.
|
|
134
|
+
clearUpdateFiles() {
|
|
135
|
+
(0, node_fs_1.rmSync)(this.getUpdateStatePath(), { force: true });
|
|
136
|
+
(0, node_fs_1.rmSync)(this.getSystemBinaryBackupPath(), { force: true });
|
|
137
|
+
(0, node_fs_1.rmSync)(this.getUpdateTempDir(), { recursive: true, force: true });
|
|
138
|
+
}
|
|
126
139
|
clearSystemFiles() {
|
|
127
140
|
(0, node_fs_1.rmSync)(this.getSystemBinaryPath(), { force: true });
|
|
128
141
|
(0, node_fs_1.rmSync)(this.getSystemConfigPath(), { force: true });
|
|
142
|
+
this.clearUpdateFiles();
|
|
129
143
|
}
|
|
130
144
|
clearAgentFiles() {
|
|
131
145
|
(0, node_fs_1.rmSync)(this.getAgentConfigPath(), { force: true });
|
|
@@ -193,15 +207,229 @@ class AgentSystem {
|
|
|
193
207
|
});
|
|
194
208
|
});
|
|
195
209
|
}
|
|
196
|
-
|
|
210
|
+
// `version` is the bare `x.y.z` of the release to fetch. It defaults to the running
|
|
211
|
+
// one because `bdy agent update` is run by an already-updated cli pushing its own
|
|
212
|
+
// version down; a remotely triggered update runs inside the old agent and has to ask
|
|
213
|
+
// for the target explicitly, or it would re-download what it is already running.
|
|
214
|
+
downloadBinaryArchive(version = (0, utils_1.getCurrentVersionWithoutEnv)()) {
|
|
197
215
|
const archivePath = this.getBinaryArchivePath();
|
|
198
216
|
const env = (0, utils_1.getVersionEnv)();
|
|
199
|
-
const version = (0, utils_1.getCurrentVersionWithoutEnv)();
|
|
200
217
|
const archive = this.getBinaryArchive();
|
|
201
218
|
const url = `https://es.buddy.works/bdy/${env}/${version}/${archive}`;
|
|
202
219
|
logger_1.default.info(url);
|
|
203
220
|
return this.downloadFile(url, archivePath);
|
|
204
221
|
}
|
|
222
|
+
isStandaloneInstall() {
|
|
223
|
+
try {
|
|
224
|
+
// `standalone` is not always stored as a bool, see command/pre.ts
|
|
225
|
+
return !!this.loadSystemConfig().standalone;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// An unreadable config is not a service install we can prove, and swapping the
|
|
229
|
+
// binary of an install we cannot identify is worse than not updating it.
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
getSystemBinaryBackupPath() {
|
|
234
|
+
return `${this.getSystemBinaryPath()}.old`;
|
|
235
|
+
}
|
|
236
|
+
getUpdateTempDir() {
|
|
237
|
+
return path_1.default.join(this.getSystemConfigDir(), 'update');
|
|
238
|
+
}
|
|
239
|
+
getUpdateStatePath() {
|
|
240
|
+
return path_1.default.join(this.getSystemConfigDir(), 'update.json');
|
|
241
|
+
}
|
|
242
|
+
// Runs the downloaded binary before committing to it. Catches the whole class of
|
|
243
|
+
// failures a checksum would not - wrong architecture, missing shared libraries, a
|
|
244
|
+
// truncated archive - while the working binary is still in place. A binary that
|
|
245
|
+
// cannot run at all could never roll itself back afterwards.
|
|
246
|
+
// `agent selftest` rather than `--version`: it is hermetic, so it cannot be slowed
|
|
247
|
+
// down or confused by an unreachable es.buddy.works, and the version it prints is a
|
|
248
|
+
// contract we own. Comparing that against the release we asked for is the only check
|
|
249
|
+
// there is on the archive actually holding it - nothing is published to verify against.
|
|
250
|
+
verifyBinary(binaryPath, expectedVersion) {
|
|
251
|
+
return new Promise((resolve) => {
|
|
252
|
+
try {
|
|
253
|
+
const { execFile } = require('node:child_process');
|
|
254
|
+
execFile(binaryPath, ['agent', 'selftest'], { timeout: 60000 }, (err, stdout) => {
|
|
255
|
+
if (err)
|
|
256
|
+
return resolve(false);
|
|
257
|
+
// Compare on the bare x.y.z: the channel suffix is derived from the running
|
|
258
|
+
// binary, so it is not something the archive can get wrong.
|
|
259
|
+
const reported = String(stdout || '').match(/\d+\.\d+\.\d+/);
|
|
260
|
+
const wanted = expectedVersion.match(/\d+\.\d+\.\d+/);
|
|
261
|
+
if (!reported || !wanted || reported[0] !== wanted[0]) {
|
|
262
|
+
logger_1.default.error((0, texts_1.LOG_AGENT_UPDATE_VERSION_MISMATCH)(wanted ? wanted[0] : expectedVersion, reported ? reported[0] : String(stdout || '').trim()));
|
|
263
|
+
return resolve(false);
|
|
264
|
+
}
|
|
265
|
+
resolve(true);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// execFile throws synchronously rather than calling back when the file cannot be
|
|
270
|
+
// executed at all - ENOEXEC on a wrong-architecture or truncated download, which
|
|
271
|
+
// is the case this check exists for.
|
|
272
|
+
resolve(false);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
// Written after the swap and read by the process the service starts next, so the
|
|
277
|
+
// attempt count survives a restart loop - each failed start is a new process and
|
|
278
|
+
// could not otherwise know how many came before it.
|
|
279
|
+
beginUpdateProbation(from, to) {
|
|
280
|
+
this.writeUpdateState({ from, to, attempts: 0, startedAt: Date.now() });
|
|
281
|
+
}
|
|
282
|
+
writeUpdateState(state) {
|
|
283
|
+
(0, node_fs_1.writeFileSync)(this.getUpdateStatePath(), JSON.stringify(state), {
|
|
284
|
+
encoding: 'utf-8',
|
|
285
|
+
});
|
|
286
|
+
try {
|
|
287
|
+
(0, node_fs_1.chmodSync)(this.getUpdateStatePath(), 0o666);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// do nothing
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
readUpdateState() {
|
|
294
|
+
try {
|
|
295
|
+
return JSON.parse((0, node_fs_1.readFileSync)(this.getUpdateStatePath(), 'utf-8'));
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
loadUpdateProbation() {
|
|
302
|
+
const json = this.readUpdateState();
|
|
303
|
+
if (!json || typeof json.attempts !== 'number')
|
|
304
|
+
return null;
|
|
305
|
+
return {
|
|
306
|
+
...json,
|
|
307
|
+
// A file written before startedAt existed must not read as long expired
|
|
308
|
+
startedAt: typeof json.startedAt === 'number' ? json.startedAt : Date.now(),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
registerUpdateAttempt() {
|
|
312
|
+
const state = this.loadUpdateProbation();
|
|
313
|
+
if (!state)
|
|
314
|
+
return 0;
|
|
315
|
+
const next = state.attempts + 1;
|
|
316
|
+
try {
|
|
317
|
+
this.writeUpdateState({ ...state, attempts: next });
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
// Report what is actually stored rather than forcing a rollback: an unwritable
|
|
321
|
+
// state file says nothing about the new binary, and the probation deadline is the
|
|
322
|
+
// backstop for a count that can never advance.
|
|
323
|
+
return state.attempts;
|
|
324
|
+
}
|
|
325
|
+
return next;
|
|
326
|
+
}
|
|
327
|
+
// Left by a rollback so the restored agent can clear the action that caused it. Without
|
|
328
|
+
// it the flag is still set when the old binary comes up, and it would start the same
|
|
329
|
+
// failing update again on its first fetch.
|
|
330
|
+
loadPendingAck() {
|
|
331
|
+
const json = this.readUpdateState();
|
|
332
|
+
if (!json || typeof json.ackPending !== 'string')
|
|
333
|
+
return null;
|
|
334
|
+
return json.ackPending;
|
|
335
|
+
}
|
|
336
|
+
clearPendingAck() {
|
|
337
|
+
(0, node_fs_1.rmSync)(this.getUpdateStatePath(), { force: true });
|
|
338
|
+
}
|
|
339
|
+
commitUpdate() {
|
|
340
|
+
(0, node_fs_1.rmSync)(this.getUpdateStatePath(), { force: true });
|
|
341
|
+
(0, node_fs_1.rmSync)(this.getSystemBinaryBackupPath(), { force: true });
|
|
342
|
+
}
|
|
343
|
+
tryClearUpdateState() {
|
|
344
|
+
try {
|
|
345
|
+
(0, node_fs_1.rmSync)(this.getUpdateStatePath(), { force: true });
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
logger_1.default.error(err);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Nothing in here may throw. It runs from load(), where an exception would surface as
|
|
352
|
+
// an unhandled rejection and take the process down - and the probation file would still
|
|
353
|
+
// be in place, so every restart would reach the same throw. That is a permanent crash
|
|
354
|
+
// loop in the code whose whole job is getting out of one.
|
|
355
|
+
rollbackUpdate(to) {
|
|
356
|
+
const backup = this.getSystemBinaryBackupPath();
|
|
357
|
+
if (!(0, node_fs_1.existsSync)(backup)) {
|
|
358
|
+
// Nothing to restore, so the probation is over either way - leaving it would count
|
|
359
|
+
// attempts against an update that cannot be undone. No ack is needed here: the
|
|
360
|
+
// agent keeps running the new binary, so its version now matches the target and
|
|
361
|
+
// the next update request resolves itself as 'already current'.
|
|
362
|
+
this.tryClearUpdateState();
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
(0, node_fs_1.renameSync)(backup, this.getSystemBinaryPath());
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
// The filesystem is refusing writes, so there is no way back to the old binary.
|
|
370
|
+
// Give the probation up rather than meet this again on every start; the caller
|
|
371
|
+
// keeps running the binary that is installed, which is the only option left.
|
|
372
|
+
logger_1.default.error(err);
|
|
373
|
+
this.tryClearUpdateState();
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
this.writeUpdateState({ ackPending: to });
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
// Better to lose the ack than the rollback - the binary is already restored
|
|
381
|
+
logger_1.default.error(texts_1.LOG_ERROR_SAVING_AGENT_SYSTEM_CONFIG);
|
|
382
|
+
}
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
// Unlike extractBinaryArchive this never deletes the live binary: it stages the new
|
|
386
|
+
// one next to it and swaps by rename. POSIX keeps the running process on its old
|
|
387
|
+
// inode, and Windows allows renaming a running exe even though it forbids deleting
|
|
388
|
+
// one - so the swap works while the agent is still up, and a crash mid-download
|
|
389
|
+
// leaves a working install behind instead of an empty path the service restarts into.
|
|
390
|
+
async swapBinaryToVersion(version) {
|
|
391
|
+
const tmp = this.getUpdateTempDir();
|
|
392
|
+
const target = this.getSystemBinaryPath();
|
|
393
|
+
const backup = this.getSystemBinaryBackupPath();
|
|
394
|
+
(0, node_fs_1.rmSync)(tmp, { recursive: true, force: true });
|
|
395
|
+
(0, node_fs_1.mkdirSync)(tmp, { recursive: true });
|
|
396
|
+
try {
|
|
397
|
+
await this.downloadBinaryArchive(version);
|
|
398
|
+
await this.extractArchive(this.getBinaryArchivePath(), tmp);
|
|
399
|
+
const staged = path_1.default.join(tmp, path_1.default.basename(target));
|
|
400
|
+
if (!(0, node_fs_1.existsSync)(staged)) {
|
|
401
|
+
throw new Error(`Archive did not contain '${path_1.default.basename(target)}'`);
|
|
402
|
+
}
|
|
403
|
+
(0, node_fs_1.chmodSync)(staged, 0o777);
|
|
404
|
+
const runs = await this.verifyBinary(staged, version);
|
|
405
|
+
if (!runs)
|
|
406
|
+
return false;
|
|
407
|
+
// Last check before touching the live binary. The download and the smoke test take
|
|
408
|
+
// long enough for an uninstall to have run in the meantime, and finishing the swap
|
|
409
|
+
// then would put a binary back for an agent that is deliberately gone.
|
|
410
|
+
if (!(0, node_fs_1.existsSync)(this.getSystemConfigPath())) {
|
|
411
|
+
throw new Error(texts_1.LOG_AGENT_UPDATE_UNINSTALLED);
|
|
412
|
+
}
|
|
413
|
+
(0, node_fs_1.rmSync)(backup, { force: true });
|
|
414
|
+
if ((0, node_fs_1.existsSync)(target))
|
|
415
|
+
(0, node_fs_1.renameSync)(target, backup);
|
|
416
|
+
try {
|
|
417
|
+
(0, node_fs_1.renameSync)(staged, target);
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
// Put the old binary back rather than leaving the service with no target
|
|
421
|
+
if ((0, node_fs_1.existsSync)(backup))
|
|
422
|
+
(0, node_fs_1.renameSync)(backup, target);
|
|
423
|
+
throw err;
|
|
424
|
+
}
|
|
425
|
+
await this.fixBinaryRights();
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
finally {
|
|
429
|
+
(0, node_fs_1.rmSync)(tmp, { recursive: true, force: true });
|
|
430
|
+
(0, node_fs_1.rmSync)(this.getBinaryArchivePath(), { force: true });
|
|
431
|
+
}
|
|
432
|
+
}
|
|
205
433
|
killStandaloneProc() {
|
|
206
434
|
return new Promise((resolve) => {
|
|
207
435
|
let pid = 0;
|
|
@@ -56,6 +56,7 @@ class AgentWindows extends system_1.default {
|
|
|
56
56
|
clearSystemFiles() {
|
|
57
57
|
(0, fs_1.rmSync)(this.getSystemBinaryPath(), { force: true });
|
|
58
58
|
(0, fs_1.rmSync)(this.getSystemConfigPath(), { force: true });
|
|
59
|
+
this.clearUpdateFiles();
|
|
59
60
|
(0, fs_1.rmSync)(path_1.default.join(this.getSystemConfigDir(), 'nssm'), {
|
|
60
61
|
force: true,
|
|
61
62
|
recursive: true,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const output_1 = __importDefault(require("../../output"));
|
|
7
|
+
const utils_1 = require("../../utils");
|
|
8
|
+
// Machine-invoked and hidden, like `agent run`. A freshly downloaded binary is executed
|
|
9
|
+
// with this before it is allowed to replace the installed one (AgentSystem.verifyBinary),
|
|
10
|
+
// so it has to stay hermetic: skipPre keeps out the latest-version fetch and the probe of
|
|
11
|
+
// the running agent, leaving exit 0 to mean exactly one thing - this binary runs here.
|
|
12
|
+
// The version it prints is what tells the caller the archive held the release it asked
|
|
13
|
+
// for; nothing else may be written to stdout.
|
|
14
|
+
const commandAgentSelftest = (0, utils_1.newCommand)('selftest');
|
|
15
|
+
commandAgentSelftest.skipPre = true;
|
|
16
|
+
commandAgentSelftest.action(async () => {
|
|
17
|
+
// Not exitNormal(): that exits the moment the write is queued, and stdout is a pipe
|
|
18
|
+
// here, so the version could be lost before it is flushed.
|
|
19
|
+
output_1.default.normal((0, utils_1.getVersion)());
|
|
20
|
+
});
|
|
21
|
+
exports.default = commandAgentSelftest;
|
|
@@ -19,6 +19,11 @@ commandAgentUpdate.action(async () => {
|
|
|
19
19
|
if (!commandAgentUpdate.agentInstalled) {
|
|
20
20
|
output_1.default.exitError(texts_1.ERR_AGENT_NOT_INSTALLED);
|
|
21
21
|
}
|
|
22
|
+
// A remote update is already swapping the binary. Carrying on would stop the service
|
|
23
|
+
// from under it, so bow out instead - the running agent finishes and restarts itself.
|
|
24
|
+
if (commandAgentUpdate.agentStatus?.updating) {
|
|
25
|
+
output_1.default.exitError(texts_1.ERR_AGENT_UPDATE_IN_PROGRESS);
|
|
26
|
+
}
|
|
22
27
|
output_1.default.normal(texts_1.TXT_UPDATING_AGENT);
|
|
23
28
|
if (commandAgentUpdate.agentStandalone) {
|
|
24
29
|
// app
|
|
@@ -14,6 +14,7 @@ const uninstall_1 = __importDefault(require("./agent/uninstall"));
|
|
|
14
14
|
const version_1 = __importDefault(require("./agent/version"));
|
|
15
15
|
const texts_1 = require("../texts");
|
|
16
16
|
const run_1 = __importDefault(require("./agent/run"));
|
|
17
|
+
const selftest_1 = __importDefault(require("./agent/selftest"));
|
|
17
18
|
const utils_1 = require("../utils");
|
|
18
19
|
const target_1 = __importDefault(require("./agent/target"));
|
|
19
20
|
const enable_1 = __importDefault(require("./agent/enable"));
|
|
@@ -40,4 +41,5 @@ commandAgent.addCommand(user_1.default);
|
|
|
40
41
|
commandAgent.addCommand(version_1.default);
|
|
41
42
|
commandAgent.addCommand(debug_1.default);
|
|
42
43
|
commandAgent.addCommand(run_1.default, { hidden: true });
|
|
44
|
+
commandAgent.addCommand(selftest_1.default, { hidden: true });
|
|
43
45
|
exports.default = commandAgent;
|
package/distTs/src/texts.js
CHANGED
|
@@ -9,16 +9,16 @@ exports.OPTION_PIPELINE_RUN_TAG = exports.OPTION_PIPELINE_RUN_BRANCH = exports.O
|
|
|
9
9
|
exports.OPTION_WHITELIST = exports.OPTION_REST_API_PER_PAGE = exports.OPTION_REST_API_PAGE = exports.OPTION_REST_API_PROJECT = exports.OPTION_REST_API_WORKSPACE = exports.OPTION_FORMAT_JSONL = exports.OPTION_FORMAT = exports.OPTION_VERSION = exports.OPTION_PIPELINE_RUN_NO_FOLLOW = exports.OPTION_PIPELINE_RUN_NO_WAIT = exports.OPTION_PIPELINE_RUN_ACTION = exports.OPTION_REST_API_TOKEN = exports.OPTION_ARTIFACT_DOWNLOAD_REPLACE = exports.OPTION_ARTIFACT_DOWNLOAD_MERGE = exports.OPTION_ARTIFACT_PUBLISH_OVERWRITE_VERSION = exports.OPTION_ARTIFACT_VERSION_AGENT_NOTE = exports.OPTION_ARTIFACT_VERSION_NOTE = exports.OPTION_ARTIFACT_VERSION_FROM = exports.OPTION_ARTIFACT_PUBLISH_CREATE = exports.OPTION_ARTIFACT_ID = exports.OPTION_ARTIFACT_DOWNLOAD_PATH = exports.OPTION_ARTIFACT_PUBLISH_PATH = exports.OPTION_PIPELINE_RUN_ACTION_ID = exports.OPTION_PIPELINE_RUN_ID = exports.OPTION_PIPELINE_YAML = exports.TXT_PIPELINE_DELETED = exports.TXT_PIPELINE_DELETE_CONFIRM = exports.TXT_PIPELINE_UPDATED = exports.TXT_PIPELINE_CREATED = exports.OPTION_PIPELINE_NAME = exports.OPTION_PIPELINE_IDENTIFIER = exports.OPTION_PIPELINE_RUN_ARTIFACT = exports.OPTION_PIPELINE_RUN_ENVIRONMENT = exports.OPTION_PIPELINE_RUN_DELAY = exports.OPTION_PIPELINE_RUN_PAYLOAD = exports.ERR_RUN_PAYLOAD_TOO_MANY_FILES = exports.ERR_RUN_PAYLOAD_NOT_UPLOADED = exports.ERR_RUN_PAYLOAD_TOO_LARGE = exports.ERR_RUN_PAYLOAD_NO_ENTRIES = exports.ERR_RUN_VAR_FILE_INVALID = exports.ERR_RUN_VAR_FILE_NOT_FOUND = exports.OPTION_RUN_SINGLE_VAR_FILE = exports.OPTION_RUN_VAR_FILE = exports.OPTION_RUN_VAR = exports.OPTION_PIPELINE_RUN_PRIORITY = exports.OPTION_PIPELINE_RUN_CLEAR_CACHE = exports.OPTION_PIPELINE_RUN_REFRESH = exports.OPTION_PIPELINE_RUN_COMMENT = exports.OPTION_PIPELINE_RUN_PULL_REQUEST = exports.OPTION_PIPELINE_RUN_REVISION = void 0;
|
|
10
10
|
exports.OPTION_COMPARE_COOKIE = exports.OPTION_COMPARE_IGNORE = exports.OPTION_COMPARE_IGNORE_URLS = exports.OPTION_COMPARE_DRY_RUN = exports.OPTION_COMPARE_URLS_FILE = exports.OPTION_COMPARE_SITEMAP = exports.OPTION_COMPARE_URLS = exports.OPTION_COMPARE_RESPECT_ROBOTS = exports.OPTION_COMPARE_FOLLOW = exports.OPTION_EXEC_PARALLEL = exports.OPTION_EXEC_ONE_BY_ONE = exports.OPTION_EXEC_SKIP_DISCOVERY = exports.OPTION_EXEC_COMMAND = exports.OPTION_AGENT_DEBUG = exports.OPTION_AGENT_PORT = exports.OPTION_AGENT_TAG = exports.OPTION_AGENT_TUNNELING = exports.OPTION_AGENT_PROXY = exports.OPTION_AGENT_TARGET = exports.OPTION_PASS = exports.OPTION_APP = exports.OPTION_USER = exports.OPTION_AGENT_TOKEN = exports.OPTION_AGENT_START = exports.OPTION_AGENT_ID = exports.OPTION_ID = exports.OPTION_NAME = exports.OPTION_TARGET = exports.OPTION_TLS_TERMINATE = exports.OPTION_TLS_CA = exports.OPTION_TLS_CERT = exports.OPTION_TLS_KEY = exports.OPTION_HTTP_CIRCUIT_BREAKER = exports.OPTION_HTTP_COMPRESSION = exports.OPTION_HTTP_2 = exports.OPTION_HTTP_VERIFY = exports.OPTION_HTTP_LOG = exports.OPTION_HTTP_AUTH_BUDDY = exports.OPTION_HTTP_AUTH = exports.OPTION_HTTP_HOST = exports.OPTION_CONFIRM_DOMAIN_BUY = exports.OPTION_CONFIRM_FORCE = exports.OPTION_FORCE = exports.OPTION_TOKEN = exports.OPTION_TIMEOUT = exports.OPTION_FOLLOW = exports.OPTION_SERVE = exports.OPTION_HEADER_USER_AGENT = exports.OPTION_RESPONSE_HEADER = exports.OPTION_HEADER = void 0;
|
|
11
11
|
exports.LOG_DISABLING_AGENT_TUNNELING = exports.LOG_DISABLING_AGENT_PROXY = exports.LOG_DISABLING_AGENT_TARGET = exports.LOG_REMOVING_TUNNEL = exports.LOG_TUNNEL_REGISTERED = exports.LOG_ERROR_WHILE_REFRESHING_AGENT = exports.LOG_REGISTERING_TUNNEL = exports.LOG_GETTING_AGENT = exports.LOG_UNREGISTERING_AGENT = exports.LOG_REGION_DETECTED = exports.LOG_AGENT_REGISTERED = exports.LOG_SOCKET_DISCONNECTED = exports.LOG_SOCKET_CONNECTED = exports.LOG_AGENT_NSSM_CLEARING = exports.LOG_AGENT_NSSM_EXTRACTING = exports.LOG_AGENT_NSSM_DOWNLOADING = exports.LOG_AGENT_ENABLED = exports.LOG_AGENT_STARTING_SYSTEM = exports.LOG_AGENT_STOPPING_SYSTEM = exports.LOG_AGENT_ENABLING_SYSTEM = exports.LOG_AGENT_SYSTEM_SERVICE_CONFIG = exports.LOG_AGENT_EXTRACTING_ARCHIVE = exports.LOG_AGENT_DOWNLOADING_ARCHIVE = exports.LOG_AGENT_SYSTEM_DIR = exports.LOG_ERROR_SAVING_AGENT_LOCAL_CONFIG = exports.LOG_ERROR_REMOVING_AGENT_STANDALONE_LOCK_FILE = exports.LOG_ERROR_SAVING_AGENT_STANDALONE_CONFIG = exports.LOG_ERROR_SAVING_AGENT_SYSTEM_CONFIG = exports.LOG_SAVING_AGENT_LOCAL_CONFIG = exports.LOG_REMOVING_AGENT_PROC_ID = exports.LOG_SAVING_AGENT_PROC_ID = exports.LOG_SAVING_AGENT_SYSTEM_CONFIG = exports.LOG_REGISTERING_AGENT = exports.OPTION_CRAWL_OUTPUT_TYPES = exports.OPTION_CRAWL_OUTPUT_DIR = exports.OPTION_CRAWL_DELAY = exports.OPTION_CRAWL_LOCAL_STORAGE = exports.OPTION_CRAWL_DEVICES = exports.OPTION_CRAWL_BROWSERS = exports.OPTION_CRAWL_COLOR_SCHEME = exports.OPTION_CRAWL_XPATH_SELECTOR = exports.OPTION_CRAWL_CSS_SELECTOR = exports.OPTION_CRAWL_FULL_PAGE = exports.OPTION_CRAWL_QUALITY = exports.OPTION_CRAWL_OUTPUT_TYPE = exports.OPTION_CRAWL_FOLLOW = exports.OPTION_CRAWL_URL = exports.OPTION_COMPARE_WAIT_FOR = exports.OPTION_COMPARE_DELAY = exports.OPTION_COMPARE_HEADER = void 0;
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
15
|
-
exports.
|
|
16
|
-
exports.
|
|
17
|
-
exports.
|
|
18
|
-
exports.
|
|
19
|
-
exports.
|
|
20
|
-
exports.
|
|
21
|
-
exports.EXAMPLE_CRAWL_LINK = exports.EXAMPLE_CRAWL_RUN = exports.EXAMPLE_TESTS_CAPTURE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CLOSE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CREATE = exports.EXAMPLE_TESTS_VISUAL_LINK = exports.EXAMPLE_TESTS_VISUAL_UPLOAD = exports.EXAMPLE_TESTS_VISUAL_SETUP = exports.EXAMPLE_TESTS_UNIT_LINK = exports.EXAMPLE_TESTS_UNIT_UPLOAD = exports.EXAMPLE_ARTIFACT_VERSION_DELETE = exports.EXAMPLE_ARTIFACT_VERSION_GET = exports.EXAMPLE_ARTIFACT_VERSION_LIST = exports.EXAMPLE_ARTIFACT_CREATE = exports.EXAMPLE_ARTIFACT_DELETE = exports.EXAMPLE_ARTIFACT_DOWNLOAD = exports.EXAMPLE_ARTIFACT_PUBLISH = void 0;
|
|
12
|
+
exports.LOG_TUNNEL_SSH_STREAM = exports.LOG_TUNNEL_TLS_AGENT_STREAM = exports.LOG_TUNNEL_TLS_REGION_STREAM = exports.LOG_TUNNEL_TLS_TARGET_STREAM = exports.LOG_TUNNEL_HTTP2_STREAM = exports.LOG_TUNNEL_HTTP1_STREAM = exports.LOG_TUNNEL_TCP_STREAM = exports.LOG_TUNNEL_HTTP_WRONG_USER_AGENTS = exports.LOG_TUNNEL_HTTP_CIRCUIT_BREAKER_OPEN = exports.LOG_TUNNEL_HTTP_MAX_INFLIGHT = exports.LOG_TUNNEL_HTTP_RATE_LIMIT = exports.LOG_TUNNEL_HTTP_WRON_AUTH = exports.LOG_TUNNEL_IDENTIFIED = exports.LOG_TUNNEL_DISCONNECTED = exports.LOG_TUNNEL_FAILED = exports.LOG_TUNNEL_CONNECTED = exports.LOG_AGENT_STARTED = exports.LOG_AGENT_UPDATE_ROLLBACK_MISSING = exports.LOG_AGENT_UPDATE_ROLLBACK_ACKED = exports.LOG_AGENT_UPDATE_ROLLED_BACK = exports.LOG_AGENT_UPDATE_ATTEMPT = exports.LOG_AGENT_UPDATE_COMMITTED = exports.LOG_AGENT_UPDATE_BINARY_INVALID = exports.ERR_AGENT_UPDATE_IN_PROGRESS = exports.LOG_AGENT_UPDATE_UNINSTALLED = exports.LOG_AGENT_UPDATE_VERSION_MISMATCH = exports.LOG_AGENT_UPDATE_FAILED = exports.LOG_AGENT_UPDATE_SWAPPED = exports.LOG_AGENT_UPDATE_NOT_NEEDED = exports.LOG_AGENT_UPDATE_NO_ADMIN = exports.LOG_AGENT_UPDATE_STANDALONE = exports.LOG_AGENT_UPDATE_REQUESTED = exports.LOG_AGENT_SERVER_STARTED = exports.LOG_ERROR_STARTING_AGENT_SERVER = exports.LOG_SSH_CONNECTION = exports.LOG_LATE_TARGET_ERROR = exports.LOG_LATE_CHANNEL_ERROR = exports.LOG_HANDSHAKE_TIMEOUT = exports.LOG_WRONG_STREAM = exports.LOG_DETECTED_STREAM = exports.LOG_HTTP2_REQUEST = exports.LOG_HTTP2_CONNECTION = exports.LOG_HTTP1_REQUEST = exports.LOG_HTTP1_CONNECTION = exports.LOG_ERROR = exports.LOG_STOPPING_TUNNEL = exports.LOG_STARTING_TUNNEL = exports.LOG_ENABLING_AGENT_TUNNELING = exports.LOG_ENABLING_AGENT_PROXY = exports.LOG_ENABLING_AGENT_TARGET = void 0;
|
|
13
|
+
exports.ERR_SANDBOX_NOT_FOUND = exports.OPTION_SANDBOX_SSH_PRINT = exports.OPTION_SANDBOX_SSH_IDENTITY = exports.OPTION_SANDBOX_SSH_ARGS = exports.OPTION_SANDBOX_RUNTIME = exports.OPTION_SANDBOX_TIMEOUT = exports.OPTION_SANDBOX_FETCH = exports.OPTION_SANDBOX_APP_DIR = exports.OPTION_SANDBOX_APP_COMMAND = exports.OPTION_SANDBOX_YAML = exports.OPTION_SANDBOX_TAGS = exports.OPTION_SANDBOX_INSTALL_SCRIPT = exports.OPTION_SANDBOX_INSTALL_COMMANDS = exports.OPTION_SANDBOX_RESOURCES = exports.OPTION_SANDBOX_OS = exports.OPTION_SANDBOX_AGENT_NOTE = exports.OPTION_SANDBOX_NOTE = exports.OPTION_SANDBOX_NAME = exports.OPTION_SANDBOX_IDENTIFIER = exports.DESC_COMMAND_SANDBOX_SSH = exports.DESC_COMMAND_SANDBOX_APP = exports.DESC_COMMAND_SANDBOX_EXEC = exports.DESC_COMMAND_SANDBOX_STATUS = exports.DESC_COMMAND_SANDBOX_LOGS = exports.DESC_COMMAND_SANDBOX_RESTART = exports.DESC_COMMAND_SANDBOX_STOP = exports.DESC_COMMAND_SANDBOX_START = exports.DESC_COMMAND_SANDBOX_DESTROY = exports.DESC_COMMAND_SANDBOX_GET = exports.DESC_COMMAND_SANDBOX_LIST = exports.DESC_COMMAND_SANDBOX_UPDATE = exports.DESC_COMMAND_SANDBOX_GET_YAML = exports.DESC_COMMAND_SANDBOX_CREATE = exports.DESC_COMMAND_SANDBOX = exports.DEBUG_WAIT_FOR_IDLE_TIMEOUT = exports.DEBUG_WAIT_FOR_IDLE = exports.DEBUG_RESOURCE_DISCOVERY_TIMEOUT = exports.DEBUG_AUTO_WIDTH = exports.DEBUG_AUTO_SCROLL = exports.DEBUG_RESOURCE_CRAWLING_URL = exports.DEBUG_SNAPSHOT_PROCESSING = exports.DEBUG_SNAPSHOTS_PROCESSING = exports.DEBUG_EXEC_COMMAND = exports.DEBUG_EXEC_TEST_COMMAND = exports.LOG_INSTALLED_BROWSER = exports.LOG_SESSION_LINK = exports.LOG_SENDING_DATA = exports.LOG_SENDING_REQUEST = exports.LOG_PROCESSING_SNAPSHOTS = exports.LOG_RUNNING_EXEC_COMMAND = void 0;
|
|
14
|
+
exports.DESC_COMMAND_SANDBOX_SNAPSHOT = exports.TXT_SANDBOX_COMMAND_KILLED = exports.OPTION_SANDBOX_COMMAND_KILL_CONFIRM = exports.OPTION_SANDBOX_LOGS_LIMIT = exports.OPTION_SANDBOX_APP_ID = exports.OPTION_SANDBOX_COMMAND_ID = exports.DESC_COMMAND_SANDBOX_EXEC_KILL = exports.DESC_COMMAND_SANDBOX_EXEC_LOGS = exports.DESC_COMMAND_SANDBOX_APP_START = exports.DESC_COMMAND_SANDBOX_APP_STOP = exports.DESC_COMMAND_SANDBOX_APP_STATUS = exports.DESC_COMMAND_SANDBOX_APP_LOGS = exports.DESC_COMMAND_SANDBOX_EXEC_STATUS = exports.DESC_COMMAND_SANDBOX_EXEC_LIST = exports.DESC_COMMAND_SANDBOX_APP_REMOVE = exports.DESC_COMMAND_SANDBOX_APP_ADD = exports.DESC_COMMAND_SANDBOX_APP_LIST = exports.TXT_SANDBOX_WAITING_START = exports.TXT_SANDBOX_WAITING_STOP = exports.TXT_SANDBOX_WAITING_APPS = exports.TXT_SANDBOX_WAITING_SETUP = exports.TXT_SANDBOX_WAITING_RUNNING = exports.TXT_SANDBOX_STOPPED = exports.TXT_SANDBOX_STARTED = exports.TXT_SANDBOX_DESTROYED = exports.TXT_SANDBOX_DESTROY_CONFIRM = exports.TXT_SANDBOX_UPDATED = exports.TXT_SANDBOX_CREATED = exports.TXT_SANDBOX_CREATING = exports.TXT_SANDBOX_APP_STARTED = exports.TXT_SANDBOX_APP_STOPPED = exports.OPTION_SANDBOX_WAIT = exports.OPTION_SANDBOX_WAIT_APPS = exports.OPTION_SANDBOX_WAIT_CONFIGURED = exports.OPTION_SANDBOX_WAIT_RUNNING = exports.ERR_SANDBOX_STOP_FAILED = exports.ERR_SANDBOX_SSH_MISSING = exports.ERR_SANDBOX_SSH_NO_ACCESS = exports.ERR_SANDBOX_NOT_RUNNING = exports.ERR_SANDBOX_NO_COMMANDS = exports.ERR_SANDBOX_RUNNING_FAILED = exports.ERR_SANDBOX_STOP_TIMEOUT = exports.ERR_SANDBOX_SNAPSHOT_TIMEOUT = exports.ERR_SANDBOX_RUNNING_TIMEOUT = exports.ERR_SANDBOX_APPS_TIMEOUT = exports.ERR_SANDBOX_SETUP_TIMEOUT = exports.ERR_SANDBOX_APP_FAILED = exports.ERR_SANDBOX_SETUP_FAILED = exports.ERR_SANDBOX_INVALID_RESOURCES = exports.ERR_SANDBOX_APP_NOT_FOUND = void 0;
|
|
15
|
+
exports.ERR_SANDBOX_CP_PATH_EXISTS = exports.ERR_SANDBOX_CP_NOT_EMPTY_DIR = exports.ERR_SANDBOX_CP_READDIR = exports.ERR_SANDBOX_CP_DEST_NOT_FOLDER = exports.ERR_SANDBOX_CP_SOURCE_NOT_FOUND = exports.TXT_SANDBOX_CP_DONE = exports.TXT_SANDBOX_CP_PROGRESS = exports.TXT_SANDBOX_UNZIPPING_COUNT = exports.TXT_SANDBOX_UNZIP_DONE = exports.TXT_SANDBOX_UNZIP = exports.TXT_SANDBOX_CP_DOWNLOAD_DONE = exports.TXT_SANDBOX_CP_DOWNLOAD = exports.OPTION_SANDBOX_CP_IGNORE = exports.OPTION_SANDBOX_CP_USER = exports.OPTION_SANDBOX_CP_DOWNLOAD_REPLACE = exports.OPTION_SANDBOX_CP_DOWNLOAD_MERGE = exports.OPTION_SANDBOX_CP_DEST = exports.OPTION_SANDBOX_CP_SOURCE = exports.DESC_COMMAND_SANDBOX_CP = exports.ERR_SANDBOX_ENDPOINTS_NOT_FOUND = exports.ERR_SANDBOX_ENDPOINT_NOT_FOUND = exports.ERR_SANDBOX_ENDPOINT_EXISTS = exports.TXT_SANDBOX_ENDPOINT_DELETED = exports.TXT_SANDBOX_ENDPOINT_DELETE_CONFIRM = exports.TXT_SANDBOX_ENDPOINT_ADDED = exports.TXT_SANDBOX_APP_REMOVED = exports.TXT_SANDBOX_APP_ADDED = exports.OPTION_SANDBOX_ENDPOINT_TYPE = exports.OPTION_SANDBOX_ENDPOINT_PORT = exports.OPTION_SANDBOX_ENDPOINT_NAME_ARG = exports.OPTION_SANDBOX_ENDPOINT_NAME = exports.DESC_COMMAND_SANDBOX_ENDPOINT_DELETE = exports.DESC_COMMAND_SANDBOX_ENDPOINT_ADD = exports.DESC_COMMAND_SANDBOX_ENDPOINT_GET = exports.DESC_COMMAND_SANDBOX_ENDPOINT_LIST = exports.DESC_COMMAND_SANDBOX_ENDPOINT = exports.ERR_SANDBOX_SNAPSHOTS_NOT_FOUND = exports.ERR_SANDBOX_SNAPSHOT_NOT_FOUND = exports.ERR_SANDBOX_SNAPSHOT_FAILED = exports.TXT_SANDBOX_SNAPSHOT_WAITING = exports.TXT_SANDBOX_SNAPSHOT_DELETE_CONFIRM = exports.TXT_SANDBOX_SNAPSHOT_DELETED = exports.TXT_SANDBOX_SNAPSHOT_CREATED = exports.OPTION_SANDBOX_FROM_SNAPSHOT = exports.OPTION_SANDBOX_SNAPSHOT_NAME_ARG = exports.OPTION_SANDBOX_SNAPSHOT_NAME = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_DELETE = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_GET = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_CREATE = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_LIST = void 0;
|
|
16
|
+
exports.ERR_MCP_TOOLS_CATEGORY = exports.OPT_COMMAND_MCP_TOOLS = exports.ERR_MCP_REFRESH_FAILED = exports.ERR_MCP_URL_INVALID = exports.ERR_MCP_ENDPOINT = exports.DESC_COMMAND_MCP = exports.ERR_API_MEDIA_TYPE_NOT_IMPLEMENTED = exports.ERR_API_PARAMETER_NOT_REPLACED = exports.TXT_API_ENDPOINT_REQUIRED_SCOPES = exports.ERR_API_ENDPOINT_NOT_FOUND = exports.ERR_API_WRONG_METHOD = exports.ERR_SCHEMA_FETCH_FAILED = exports.OPT_COMMAND_API_INFO_URL = exports.OPT_COMMAND_API_INFO_SCHEMA = exports.OPT_COMMAND_API_INFO_METHOD = exports.OPT_COMMAND_API_LIST_SEARCH = exports.OPT_COMMAND_API_LIST_METHOD = exports.ERR_API_REQUEST_BODY_VALUE = exports.ERR_API_REQUEST_QUERY_VALUE = exports.ERR_API_REQUEST_INVALID_JSON = exports.ERR_API_REQUEST_FILE_ERROR = exports.ERR_API_REQUEST_OUTPUT_EXISTS = exports.DESC_COMMAND_API_INFO = exports.DESC_COMMAND_API_FORM = exports.DESC_COMMAND_API_JSON = exports.DESC_COMMAND_API_DATA = exports.DESC_COMMAND_API_OUTPUT = exports.DESC_COMMAND_API_REQUEST_QUERY = exports.DESC_COMMAND_API_PROJECT = exports.DESC_COMMAND_API_WORKSPACE = exports.DESC_COMMAND_API_REQUEST_URL = exports.DESC_COMMAND_API_GET = exports.DESC_COMMAND_API_PATCH = exports.DESC_COMMAND_API_DELETE = exports.DESC_COMMAND_API_PUT = exports.DESC_COMMAND_API_POST = exports.DESC_COMMAND_API_LIST = exports.DESC_COMMAND_API = exports.ERR_WHOAMI_LOGOUT = exports.TXT_WHOAMI_NO_WORKSPACE = exports.DESC_COMMAND_WHOAMI = exports.TXT_SANDBOX_EXEC_FAILED = exports.TXT_SANDBOX_EXEC_INPROGRESS = exports.TXT_SANDBOX_EXEC_SUCCESS = exports.TXT_SANDBOX_EXEC_BACKGROUND = exports.TXT_SANDBOX_EXEC_ID = exports.ERR_SANDBOX_CP_INVALID_SOURCE = exports.ERR_SANDBOX_CP_INVALID_DEST = exports.ERR_SANDBOX_CP_REPLACE = exports.ERR_SANDBOX_CP_MKDIR = void 0;
|
|
17
|
+
exports.DESC_COMMAND_ROUTE_UPDATE = exports.DESC_COMMAND_ROUTE_DELETE = exports.DESC_COMMAND_ROUTE_GET = exports.DESC_COMMAND_DISTRO_UPDATE = exports.DESC_COMMAND_DISTRO_GET = exports.DESC_COMMAND_ROUTE_LIST = exports.DESC_COMMAND_DISTRO_LIST = exports.DESC_COMMAND_DISTRO_DELETE = exports.DESC_COMMAND_ROUTE_CREATE = exports.DESC_COMMAND_DISTRO_CREATE = exports.DESC_COMMAND_DISTRO = exports.ERR_API_MESSAGE_REPLACER = exports.ERR_LOGIN_INVALID_BASE_URL = exports.ERR_LOGIN_NO_WORKSPACE_FOUND = exports.ERR_LOGIN_NO_WORKSPACES = exports.ERR_REGISTER_HTTP_CANCEL = exports.ERR_LOGIN_HTTP_CANCEL = exports.ERR_LOGIN_HTTP_FAILED = exports.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN = exports.TXT_REGISTER_SUCCESS = exports.TXT_LOGIN_SUCCESS = exports.TXT_LOGIN_SELECT_WORKSPACE = exports.TXT_LOGIN_ENTER_BASE_URL = exports.TXT_LOGIN_PROVIDE_CODE = exports.TXT_REGISTER_OPEN_URL = exports.TXT_LOGIN_OPEN_URL = exports.TXT_REGISTER_OPENING_STAR = exports.TXT_LOGIN_OPENING_STAR = exports.TXT_REGISTER_OPENING = exports.TXT_LOGIN_OPENING = exports.TXT_LOGIN_SELECT_REGION = exports.TXT_WORKSPACE_NONE = exports.TXT_WORKSPACE_SET_SUCCESS = exports.ARG_COMMAND_WORKSPACE = exports.DESC_COMMAND_WORKSPACE_GET = exports.DESC_COMMAND_WORKSPACE_SET = exports.DESC_COMMAND_WORKSPACE_LIST = exports.DESC_COMMAND_WORKSPACE = exports.TXT_COMMAND_REGISTER_PROVIDE_NAME = exports.TXT_COMMAND_REGISTER_PROVIDE_EMAIL = exports.ERR_COMMAND_REGISTER_INVALID_NAME = exports.ERR_COMMAND_REGISTER_INVALID_EMAIL = exports.OPT_COMMAND_REGISTER_NAME = exports.OPT_COMMAND_REGISTER_EMAIL = exports.DESC_COMMAND_REGISTER = exports.TXT_LOGOUT_SUCCESS = exports.DESC_COMMAND_LOGOUT = exports.DESC_COMMAND_LOGIN = exports.HELP_COMMAND_MCP = exports.ERR_MCP_TOOL_FILTERED = void 0;
|
|
18
|
+
exports.ERR_COMMAND_DOMAIN_NOT_FOUND = exports.OPT_COMMAND_DOMAIN_ONLY_AVAILABLE = exports.OPT_COMMAND_DOMAIN_SORT = exports.OPT_COMMAND_DOMAIN_PHRASE = exports.OPT_COMMAND_DOMAIN_BUY_OWNER = exports.OPT_COMMAND_DOMAIN_BUY_TLD = exports.DESC_COMMAND_DOMAIN_GET = exports.DESC_COMMAND_DOMAIN_LIST = exports.DESC_COMMAND_DOMAIN_SEARCH = exports.DESC_COMMAND_DOMAIN_BUY = exports.DESC_COMMAND_DOMAIN = exports.ERR_ROUTE_NO_DEFAULT = exports.ERR_WRONG_ROUTE_TARGET = exports.ERR_COMMAND_ROUTE_NO_TARGET = exports.ERR_COMMAND_ROUTE_TYPE = exports.TXT_COMMAND_ROUTES_NOT_FOUND = exports.TXT_COMMAND_DISTROS_NOT_FOUND = exports.TXT_COMMAND_ROUTE_DELETED = exports.TXT_COMMAND_DISTRO_DELETED = exports.TXT_COMMAND_ROUTE_DELETE_CONFIRM = exports.TXT_COMMAND_DISTRO_DELETE_CONFIRM = exports.ERR_COMMAND_DISTRO_ENABLE_DISABLE = exports.ERR_COMMAND_DISTRO_NO_UPDATE = exports.ERR_COMMAND_ROUTE_NO_UPDATE = exports.ERR_COMMAND_DISTRO_NOT_FOUND = exports.ERR_COMMAND_SCOPE = exports.TXT_COMMAND_DISTRO_UPDATED = exports.TXT_COMMAND_ROUTE_UPDATED = exports.TXT_ROUTE_SERVE = exports.TXT_COMMAND_ROUTE_CREATED = exports.TXT_COMMAND_DISTRO_CREATED = exports.ERR_COMMAND_SCOPE_NO_PROJECT = exports.OPT_COMMAND_DISTRO_DISABLE = exports.OPT_COMMAND_DISTRO_ENABLE = exports.OPT_COMMAND_DISTRO_AGENT_NOTE = exports.OPT_COMMAND_DISTRO_NOTE = exports.OPT_COMMAND_DISTRO_NAME = exports.OPT_COMMAND_ROUTE_TARGET = exports.OPT_COMMAND_ROUTE_AGENT_NOTE = exports.OPT_COMMAND_ROUTE_NOTE = exports.OPT_COMMAND_ROUTE_PATH = exports.OPT_COMMAND_ROUTE_DOMAIN = exports.OPT_COMMAND_ROUTE_SUBDOMAIN = exports.OPT_COMMAND_ROUTE_TYPE = exports.OPT_COMMAND_ROUTE_ID = exports.OPT_COMMAND_DISTRO_IDENTIFIER = exports.OPT_COMMAND_SCOPE = exports.OPT_COMMAND_AGENT_NOTE = exports.OPT_COMMAND_NOTE = exports.DESC_COMMAND_ROUTE = void 0;
|
|
19
|
+
exports.TXT_COMMAND_PROJECT_LINK_CREATE_NEW_DESC = exports.TXT_COMMAND_PROJECT_LINK_CREATE_NEW = exports.ERR_COMMAND_PROJECT_LINK_DIR_NOT_DIR = exports.TXT_COMMAND_PROJECT_LINK_GIT_REPO_INITIALIZED = exports.TXT_COMMAND_PROJECT_LINK_GIT_REPO = exports.TXT_COMMAND_PROJECT_LINK_DIR_CONFIRM = exports.TXT_COMMAND_PROJECT_LINK_DIR_LINKED = exports.ERR_COMMAND_PROJECT_LINK_DIR_CREATE = exports.OPT_COMMAND_PROJECT_LINK_TRY_NOW = exports.OPT_COMMAND_PROJECT_LINK_SET_GIT_REMOTE = exports.OPT_COMMAND_PROJECT_LINK_HAS_REMOTE = exports.OPT_COMMAND_PROJECT_LINK_DIRECTORY = exports.OPT_COMMAND_PROJECT_LINK_GIT = exports.OPT_COMMAND_PROJECT_LINK_RELINK = exports.DESC_COMMAND_PROJECT_LINK = exports.DESC_COMMAND_PROJECT_LIST = exports.DESC_COMMAND_PROJECT_GIT = exports.DESC_COMMAND_PROJECT_GIT_CREDENTIAL = exports.DESC_COMMAND_PROJECT = exports.TXT_ARTIFACT_VERSION_DOWNLOAD = exports.TXT_ARTIFACT_PUBLISH = exports.TXT_ARTIFACT_CREATED = exports.TXT_ARTIFACT_VERSION_DELETED = exports.TXT_ARTIFACT_DELETED = exports.ERR_COMMAND_ARTIFACT_TYPE = exports.OPT_COMMAND_ARTIFACT_VERSION = exports.OPT_COMMAND_ARTIFACT_IDENTIFIER = exports.OPT_COMMAND_ARTIFACT_CREATE_IDENTIFIER = exports.OPT_COMMAND_ARTIFACT_NAME = exports.OPT_COMMAND_ARTIFACT_TYPE = exports.DESC_COMMAND_ARTIFACT_CREATE = exports.DESC_COMMAND_ARTIFACT_GET = exports.TXT_ARTIFACT_DOCKER_LOGIN_FAILED = exports.TXT_ARTIFACT_DOCKER_LOGIN_SUCCESS = exports.TXT_ARTIFACT_VERSION_DELETE_CONFIRM = exports.TXT_ARTIFACT_DELETE_CONFIRM = exports.DESC_COMMAND_ARTIFACT_DELETE = exports.ERR_COMMAND_ARTIFACT_NO_PROJECTS = exports.DESC_COMMAND_ARTIFACT_VERSION_GET = exports.DESC_COMMAND_ARTIFACT_VERSION_LIST = exports.DESC_COMMAND_ARTIFACT_VERSION_DELETE = exports.DESC_COMMAND_ARTIFACT_DOCKER_LOGIN = exports.DESC_COMMAND_ARTIFACT_LIST = exports.DESC_COMMAND_ARTIFACT_VERSION = exports.ERR_COMMAND_DOMAIN_UNAVAILABLE = exports.OPTION_COMMAND_DOMAIN_IDENTIFIER = exports.ERR_COMMAND_DOMAIN_NO_DOMAINS = exports.TXT_COMMAND_DOMAIN_PROMPT_REQUIRED = exports.TXT_COMMAND_DOMAIN_BUY_SELECT_DOMAIN = exports.TXT_COMMAND_DOMAIN_PROVIDE_PROMPT = void 0;
|
|
20
|
+
exports.EXAMPLE_SANDBOX_ENDPOINT_LIST = exports.EXAMPLE_SANDBOX_ENDPOINT_GET = exports.EXAMPLE_SANDBOX_ENDPOINT_DELETE = exports.EXAMPLE_SANDBOX_ENDPOINT_CREATE = exports.EXAMPLE_SANDBOX_SNAPSHOT_LIST = exports.EXAMPLE_SANDBOX_SNAPSHOT_GET = exports.EXAMPLE_SANDBOX_SNAPSHOT_DELETE = exports.EXAMPLE_SANDBOX_SNAPSHOT_CREATE = exports.EXAMPLE_SANDBOX_EXEC_STATUS = exports.EXAMPLE_SANDBOX_EXEC_LOGS = exports.EXAMPLE_SANDBOX_APP_STATUS = exports.EXAMPLE_SANDBOX_APP_STOP = exports.EXAMPLE_SANDBOX_APP_REMOVE = exports.EXAMPLE_SANDBOX_APP_ADD = exports.EXAMPLE_SANDBOX_APP_START = exports.EXAMPLE_SANDBOX_APP_LOGS = exports.EXAMPLE_SANDBOX_EXEC_LIST = exports.EXAMPLE_SANDBOX_APP_LIST = exports.EXAMPLE_SANDBOX_EXEC_KILL = exports.EXAMPLE_SANDBOX_SSH = exports.EXAMPLE_SANDBOX_EXEC_COMMAND = exports.EXAMPLE_TUNNEL_START = exports.EXAMPLE_TUNNEL_TCP = exports.EXAMPLE_TUNNEL_TLS = exports.EXAMPLE_AGENT_TUNNEL_START = exports.EXAMPLE_AGENT_TUNNEL_STATUS = exports.EXAMPLE_AGENT_TUNNEL_REMOVE = exports.EXAMPLE_AGENT_TUNNEL_LIST = exports.EXAMPLE_TUNNEL_HTTP = exports.EXAMPLE_SANDBOX_CREATE = exports.EXAMPLE_DISTRO_CREATE = exports.EXAMPLE_ROUTE_CREATE = exports.EXAMPLE_ROUTE_LIST = exports.EXAMPLE_ROUTE_UPDATE = exports.EXAMPLE_ROUTE_DELETE = exports.EXAMPLE_DISTRO_DELETE = exports.EXAMPLE_ROUTE_GET = exports.EXAMPLE_DISTRO_UPDATE = exports.EXAMPLE_DISTRO_GET = exports.EXAMPLE_DISTRO_LIST = exports.EXAMPLE_SANDBOX_CP = exports.ERR_PROJECT_NO_PROJECTS = exports.TXT_LOGIN_SELECT_PROJECT = exports.TXT_COMMAND_PROJECT_CREATED = exports.TXT_COMMAND_PROJECT_LINK_NOT_FOUND = exports.TXT_COMMAND_PROJECT_LINK_NAME = exports.TXT_COMMAND_PROJECT_LINK_SELECT_PROJECT = exports.TXT_COMMAND_PROJECT_LINK_TO = exports.TXT_COMMAND_PROJECT_LINK_EXISTING_DESC = exports.TXT_COMMAND_PROJECT_LINK_EXISTING = void 0;
|
|
21
|
+
exports.EXAMPLE_CRAWL_LINK = exports.EXAMPLE_CRAWL_RUN = exports.EXAMPLE_TESTS_CAPTURE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CLOSE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CREATE = exports.EXAMPLE_TESTS_VISUAL_LINK = exports.EXAMPLE_TESTS_VISUAL_UPLOAD = exports.EXAMPLE_TESTS_VISUAL_SETUP = exports.EXAMPLE_TESTS_UNIT_LINK = exports.EXAMPLE_TESTS_UNIT_UPLOAD = exports.EXAMPLE_ARTIFACT_VERSION_DELETE = exports.EXAMPLE_ARTIFACT_VERSION_GET = exports.EXAMPLE_ARTIFACT_VERSION_LIST = exports.EXAMPLE_ARTIFACT_CREATE = exports.EXAMPLE_ARTIFACT_DELETE = exports.EXAMPLE_ARTIFACT_DOWNLOAD = exports.EXAMPLE_ARTIFACT_PUBLISH = exports.EXAMPLE_ARTIFACT_VERSION_CREATE = exports.EXAMPLE_PIPELINE_RUN_RETRY = exports.EXAMPLE_PIPELINE_RUN_LIST = exports.EXAMPLE_PIPELINE_LIST = exports.EXAMPLE_PIPELINE_YML = exports.EXAMPLE_PIPELINE_GET = exports.EXAMPLE_PIPELINE_UPDATE = exports.EXAMPLE_PIPELINE_DELETE = exports.EXAMPLE_PIPELINE_CREATE = exports.EXAMPLE_PIPELINE_RUN_CANCEL = exports.EXAMPLE_PIPELINE_RUN_APPLY = exports.EXAMPLE_PIPELINE_RUN_LOGS = exports.EXAMPLE_PIPELINE_RUN_JSONL = exports.EXAMPLE_PIPELINE_RUN_STATUS = exports.EXAMPLE_PIPELINE_RUN_START = void 0;
|
|
22
22
|
const utils_1 = require("./utils");
|
|
23
23
|
exports.ERR_CANCELLED = 'Cancelled';
|
|
24
24
|
exports.ERR_REST_API_GENERAL_ERROR = 'Something went wrong';
|
|
@@ -554,8 +554,33 @@ exports.LOG_HANDSHAKE_TIMEOUT = 'Stream handshake timed out';
|
|
|
554
554
|
exports.LOG_LATE_CHANNEL_ERROR = 'Late error on an already closed channel, ignored';
|
|
555
555
|
exports.LOG_LATE_TARGET_ERROR = 'Late error on a torn down target request, ignored';
|
|
556
556
|
exports.LOG_SSH_CONNECTION = 'New SSH TCP connection';
|
|
557
|
-
|
|
557
|
+
const LOG_ERROR_STARTING_AGENT_SERVER = (port) => `Error while starting agent API server: port ${port} is already in use`;
|
|
558
|
+
exports.LOG_ERROR_STARTING_AGENT_SERVER = LOG_ERROR_STARTING_AGENT_SERVER;
|
|
558
559
|
exports.LOG_AGENT_SERVER_STARTED = 'Agent server started';
|
|
560
|
+
const LOG_AGENT_UPDATE_REQUESTED = (from, to) => `Remote update requested, updating agent from '${from}' to '${to}'`;
|
|
561
|
+
exports.LOG_AGENT_UPDATE_REQUESTED = LOG_AGENT_UPDATE_REQUESTED;
|
|
562
|
+
exports.LOG_AGENT_UPDATE_STANDALONE = 'Remote update is not supported for a standalone agent: nothing supervises the process, so it would not come back after exiting. Update the cli and run `bdy agent update`';
|
|
563
|
+
exports.LOG_AGENT_UPDATE_NO_ADMIN = 'Remote update needs admin rights, the agent is running without them';
|
|
564
|
+
const LOG_AGENT_UPDATE_NOT_NEEDED = (version) => `Remote update skipped, agent already runs the latest version '${version}'`;
|
|
565
|
+
exports.LOG_AGENT_UPDATE_NOT_NEEDED = LOG_AGENT_UPDATE_NOT_NEEDED;
|
|
566
|
+
const LOG_AGENT_UPDATE_SWAPPED = (version) => `Agent binary replaced with '${version}', exiting so the service starts it`;
|
|
567
|
+
exports.LOG_AGENT_UPDATE_SWAPPED = LOG_AGENT_UPDATE_SWAPPED;
|
|
568
|
+
exports.LOG_AGENT_UPDATE_FAILED = 'Remote update of the agent failed';
|
|
569
|
+
const LOG_AGENT_UPDATE_VERSION_MISMATCH = (wanted, got) => `Downloaded archive reports version '${got}' but '${wanted}' was requested, keeping the current binary`;
|
|
570
|
+
exports.LOG_AGENT_UPDATE_VERSION_MISMATCH = LOG_AGENT_UPDATE_VERSION_MISMATCH;
|
|
571
|
+
exports.LOG_AGENT_UPDATE_UNINSTALLED = 'Agent was uninstalled while the update was downloading, leaving the binary alone';
|
|
572
|
+
exports.ERR_AGENT_UPDATE_IN_PROGRESS = 'The agent is already updating itself after a remote request. Wait for it to finish and check `bdy agent status`';
|
|
573
|
+
const LOG_AGENT_UPDATE_BINARY_INVALID = (version) => `Downloaded binary '${version}' does not run on this machine, keeping the current one`;
|
|
574
|
+
exports.LOG_AGENT_UPDATE_BINARY_INVALID = LOG_AGENT_UPDATE_BINARY_INVALID;
|
|
575
|
+
const LOG_AGENT_UPDATE_COMMITTED = (version) => `Updated agent '${version}' connected, previous binary removed`;
|
|
576
|
+
exports.LOG_AGENT_UPDATE_COMMITTED = LOG_AGENT_UPDATE_COMMITTED;
|
|
577
|
+
const LOG_AGENT_UPDATE_ATTEMPT = (attempt, max) => `Updated agent did not connect yet, start ${attempt} of ${max} after the update`;
|
|
578
|
+
exports.LOG_AGENT_UPDATE_ATTEMPT = LOG_AGENT_UPDATE_ATTEMPT;
|
|
579
|
+
const LOG_AGENT_UPDATE_ROLLED_BACK = (from, to) => `Updated agent '${to}' kept restarting, rolled back to '${from}' and exiting so the service starts it`;
|
|
580
|
+
exports.LOG_AGENT_UPDATE_ROLLED_BACK = LOG_AGENT_UPDATE_ROLLED_BACK;
|
|
581
|
+
const LOG_AGENT_UPDATE_ROLLBACK_ACKED = (version) => `Update to '${version}' was rolled back, clearing the request so it is not retried`;
|
|
582
|
+
exports.LOG_AGENT_UPDATE_ROLLBACK_ACKED = LOG_AGENT_UPDATE_ROLLBACK_ACKED;
|
|
583
|
+
exports.LOG_AGENT_UPDATE_ROLLBACK_MISSING = 'Updated agent kept restarting but the previous binary is gone, nothing to roll back to';
|
|
559
584
|
exports.LOG_AGENT_STARTED = 'Agent started';
|
|
560
585
|
const LOG_TUNNEL_CONNECTED = (id, port) => `Tunnel '${id}' connected. Forwarding port '${port}'`;
|
|
561
586
|
exports.LOG_TUNNEL_CONNECTED = LOG_TUNNEL_CONNECTED;
|
|
@@ -136,4 +136,5 @@ var TUNNEL_AGENT_STATUS;
|
|
|
136
136
|
var TUNNEL_AGENT_ACTION;
|
|
137
137
|
(function (TUNNEL_AGENT_ACTION) {
|
|
138
138
|
TUNNEL_AGENT_ACTION["DELETE"] = "DELETE";
|
|
139
|
+
TUNNEL_AGENT_ACTION["UPDATE"] = "UPDATE";
|
|
139
140
|
})(TUNNEL_AGENT_ACTION || (exports.TUNNEL_AGENT_ACTION = TUNNEL_AGENT_ACTION = {}));
|
package/distTs/src/utils.js
CHANGED
|
@@ -36,8 +36,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
40
|
-
exports.getGitName = exports.getGitEmail = exports.MCP_TOOL_CATEGORIES = exports.getBasicCommandTls = exports.getBasicCommandHttp = exports.getBasicCommandSandboxEndpoint = exports.getBasicCommandTcp = exports.getCurrentUser = exports.getServiceUser = exports.getRealTargetHost = exports.isWindows = exports.isLinux = exports.isOsx = exports.isDocker = exports.sleep = exports.getLatestVersion = exports.getVersionEnv = exports.getCurrentVersionWithoutEnv = exports.getVersionWithoutEnv = exports.getVersion = exports.isInstalledByChoco = exports.isInstalledByApt = exports.isInstalledByBrew = exports.isInstalledByNpm = void 0;
|
|
39
|
+
exports.getHomeDirectory = exports.isDomainAvailable = exports.newCommand = exports.formatBytes = exports.formatHelp = exports.getPlatform = exports.getHostname = exports.isStringRegExp = exports.getWorkingDir = exports.getRootDir = exports.TARGET_ONLY_PORT_REGEX = exports.TARGET_HTTP_REGEX = exports.TARGET_TCP_TLS_REGEX = exports.ApiErrorTunnelsDisabled = exports.ApiErrorWorkspaceFlagged = exports.ApiErrorTunnelLimitReached = exports.ApiErrorAgentLimitReached = exports.ApiErrorDomainRestricted = exports.ApiErrorTargetInvalid = exports.ApiErrorWrongToken = exports.ApiErrorFailedToConnect = exports.ApiErrorAgentNotFound = exports.ARTIFACT_AUTH_TYPE = exports.ARTIFACT_TYPE = exports.SANDBOX_SNAPSHOT_STATUS = exports.SANDBOX_APP_STATUS = exports.SANDBOX_SETUP_STATUS = exports.SANDBOX_EXEC_STATUS = exports.SANDBOX_EXEC_RUNTIME = exports.SANDBOX_STATUS = exports.REST_API_ENDPOINT = exports.REST_API_REGION = exports.DEFAULT_SANDBOX_CP_USER = exports.ARTIFACT_DEFAULT_VERSION = exports.SUGGESTED_BROWSER_VERSION = exports.AGENT_UPDATE_PROBATION_MS = exports.AGENT_UPDATE_MAX_ATTEMPTS = exports.AGENT_FETCH_RETRY_MAX = exports.AGENT_FETCH_RETRY_MIN = exports.SSH_HANDSHAKE_TIMEOUT = exports.DEFAULT_TIMEOUT = exports.TUNNEL_HTTP_RETRY_AFTER = exports.TUNNEL_HTTP_MAX_INFLIGHT = exports.TUNNEL_HTTP_CB_MIN_REQUESTS = exports.TUNNEL_HTTP_CB_WINDOW = exports.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC = exports.TUNNEL_HTTP_LOG_MAX_REQUESTS = exports.TUNNEL_HTTP_LOG_MAX_BODY = exports.TUNNEL_HTTP_RATE_WINDOW = exports.TUNNEL_HTTP_RATE_LIMIT = void 0;
|
|
40
|
+
exports.getGitName = exports.getGitEmail = exports.MCP_TOOL_CATEGORIES = exports.getBasicCommandTls = exports.getBasicCommandHttp = exports.getBasicCommandSandboxEndpoint = exports.getBasicCommandTcp = exports.getCurrentUser = exports.getServiceUser = exports.getRealTargetHost = exports.isWindows = exports.isLinux = exports.isOsx = exports.isDocker = exports.sleep = exports.getLatestVersion = exports.getVersionEnv = exports.getCurrentVersionWithoutEnv = exports.getVersionWithoutEnv = exports.getVersion = exports.isInstalledByChoco = exports.isInstalledByApt = exports.isInstalledByBrew = exports.isInstalledByNpm = exports.tryGetEmail = exports.execLocally = void 0;
|
|
41
41
|
exports.apiErrorCodeToClass = apiErrorCodeToClass;
|
|
42
42
|
exports.isFile = isFile;
|
|
43
43
|
exports.getAppWorkspaceUrl = getAppWorkspaceUrl;
|
|
@@ -82,6 +82,16 @@ exports.DEFAULT_TIMEOUT = 30;
|
|
|
82
82
|
exports.SSH_HANDSHAKE_TIMEOUT = 10000;
|
|
83
83
|
exports.AGENT_FETCH_RETRY_MIN = 3000;
|
|
84
84
|
exports.AGENT_FETCH_RETRY_MAX = 60000;
|
|
85
|
+
// How many times a freshly updated agent may be started before the update is treated as
|
|
86
|
+
// broken and rolled back. Counted per process start rather than per failed fetch: a
|
|
87
|
+
// healthy binary does not restart, while an api outage would otherwise look identical to
|
|
88
|
+
// a bad binary and revert every agent in the fleet at once.
|
|
89
|
+
exports.AGENT_UPDATE_MAX_ATTEMPTS = 3;
|
|
90
|
+
// Backstop for the attempt counter above. The counter needs a write on every start, and a
|
|
91
|
+
// filesystem that has gone read-only would keep the count at zero forever - a deadline
|
|
92
|
+
// only has to be read. Generous on purpose: it is only ever reached when the counter
|
|
93
|
+
// cannot be persisted, so it must not fire on an agent that is merely slow to come up.
|
|
94
|
+
exports.AGENT_UPDATE_PROBATION_MS = 30 * 60 * 1000;
|
|
85
95
|
exports.SUGGESTED_BROWSER_VERSION = '130.0.6723.69';
|
|
86
96
|
exports.ARTIFACT_DEFAULT_VERSION = 'latest';
|
|
87
97
|
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.
|
|
4
|
+
"version": "1.23.1-dev",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://buddy.works/docs/cli",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"e2e:pipeline": "vitest run --config e2e/vitest.config.ts e2e/modules/pipeline/",
|
|
27
27
|
"e2e:tunnel": "vitest run --config e2e/vitest.config.ts e2e/modules/tunnel/",
|
|
28
28
|
"e2e:agent": "vitest run --config e2e/vitest.config.ts e2e/modules/agent/",
|
|
29
|
-
"e2e:distro": "vitest run --config e2e/vitest.config.ts e2e/modules/distro/"
|
|
29
|
+
"e2e:distro": "vitest run --config e2e/vitest.config.ts e2e/modules/distro/",
|
|
30
|
+
"unit": "vitest run --config vitest.config.ts"
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"distTs"
|