@jango-blockchained/hoox-cli 0.5.0 → 0.5.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/package.json +1 -1
- package/src/commands/check/check-command.ts +8 -65
- package/src/commands/check/prerequisites-command.ts +7 -6
- package/src/commands/clone/clone-command.test.ts +8 -10
- package/src/commands/config/config-command.test.ts +4 -4
- package/src/commands/config/config-command.ts +10 -11
- package/src/commands/config/env-command.test.ts +2 -2
- package/src/commands/config/env-command.ts +40 -43
- package/src/commands/config/kv-command.ts +60 -60
- package/src/commands/dashboard/dashboard-command.ts +32 -30
- package/src/commands/db/db-command.ts +79 -80
- package/src/commands/deploy/deploy-command.test.ts +54 -34
- package/src/commands/deploy/deploy-command.ts +3 -84
- package/src/commands/dev/dev-command.test.ts +84 -62
- package/src/commands/disclaimer/disclaimer-command.ts +21 -0
- package/src/commands/disclaimer/index.ts +1 -0
- package/src/commands/init/init-command.test.ts +69 -91
- package/src/commands/init/init-command.ts +19 -15
- package/src/commands/logs/logs-command.test.ts +0 -1
- package/src/commands/monitor/monitor-command.test.ts +37 -29
- package/src/commands/repair/repair-command.test.ts +60 -41
- package/src/commands/repair/repair-service.ts +26 -0
- package/src/commands/schema/index.ts +1 -0
- package/src/commands/schema/schema-command.ts +137 -0
- package/src/commands/test/test-command.test.ts +2 -3
- package/src/commands/update/update-command.ts +6 -65
- package/src/commands/waf/waf-command.ts +56 -59
- package/src/index.ts +5 -13
- package/src/services/config/config-service.ts +1 -6
- package/src/services/db/db-service.test.ts +13 -1
- package/src/services/env/env-service.test.ts +41 -18
- package/src/services/env/env-service.ts +45 -59
- package/src/services/kv/kv-sync-service.ts +14 -5
- package/src/services/schema/index.ts +1 -0
- package/src/services/schema/schema-service.ts +99 -0
- package/src/services/secrets/secrets-service.test.ts +42 -35
- package/src/services/secrets/types.ts +1 -1
- package/src/ui/menu.ts +1 -1
- package/src/utils/error-handler.ts +62 -0
- package/src/utils/errors.ts +1 -0
- package/src/utils/git.ts +134 -0
- package/src/utils/theme.ts +0 -2
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import { ConfigService } from "../../services/config/index.js";
|
|
3
3
|
import { CLIError, ExitCode } from "../../utils/errors.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
formatError,
|
|
7
|
-
formatTable,
|
|
8
|
-
} from "../../utils/formatters.js";
|
|
4
|
+
import { formatSuccess, formatTable } from "../../utils/formatters.js";
|
|
5
|
+
import { withErrorHandling } from "../../utils/error-handler.js";
|
|
9
6
|
import type { FormatOptions } from "../../utils/formatters.js";
|
|
10
|
-
import { theme
|
|
7
|
+
import { theme } from "../../utils/theme.js";
|
|
11
8
|
import * as jsonc from "jsonc-parser";
|
|
12
9
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
13
10
|
import { resolve } from "node:path";
|
|
@@ -101,28 +98,33 @@ export function registerDashboardCommand(program: Command): void {
|
|
|
101
98
|
.command("update-urls")
|
|
102
99
|
.description("Update dashboard wrangler.jsonc with current service URLs")
|
|
103
100
|
.option("--dry-run", "Show changes without applying")
|
|
104
|
-
.action(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
101
|
+
.action(
|
|
102
|
+
withErrorHandling(
|
|
103
|
+
async (options: { dryRun?: boolean }) => {
|
|
104
|
+
const opts: FormatOptions = {
|
|
105
|
+
json: program.opts<{ json?: boolean }>().json,
|
|
106
|
+
quiet: program.opts<{ quiet?: boolean }>().quiet,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const config = new ConfigService();
|
|
110
|
+
await config.load();
|
|
111
|
+
|
|
112
|
+
const urls = getServiceUrls(config);
|
|
113
|
+
const dashboardPath = resolve(
|
|
114
|
+
process.cwd(),
|
|
115
|
+
"pages",
|
|
116
|
+
"dashboard",
|
|
117
|
+
"wrangler.jsonc"
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
updateWranglerVars(
|
|
121
|
+
dashboardPath,
|
|
122
|
+
urls,
|
|
123
|
+
options.dryRun === true,
|
|
124
|
+
opts
|
|
125
|
+
);
|
|
126
|
+
},
|
|
127
|
+
{ service: "dashboard" }
|
|
128
|
+
)
|
|
129
|
+
);
|
|
128
130
|
}
|
|
@@ -15,12 +15,11 @@ import * as p from "@clack/prompts";
|
|
|
15
15
|
import { DbService } from "../../services/db/index.js";
|
|
16
16
|
import {
|
|
17
17
|
formatSuccess,
|
|
18
|
-
formatError,
|
|
19
18
|
formatTable,
|
|
20
19
|
formatJson,
|
|
21
20
|
getFormatOptions,
|
|
22
21
|
} from "../../utils/formatters.js";
|
|
23
|
-
import {
|
|
22
|
+
import { withErrorHandling } from "../../utils/error-handler.js";
|
|
24
23
|
import type { FormatOptions } from "../../utils/formatters.js";
|
|
25
24
|
|
|
26
25
|
/**
|
|
@@ -204,109 +203,109 @@ EXAMPLES:
|
|
|
204
203
|
.command("apply")
|
|
205
204
|
.description("Apply schema.sql to the database")
|
|
206
205
|
.option("--file <path>", "Path to schema.sql file")
|
|
207
|
-
.action(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
206
|
+
.action(
|
|
207
|
+
withErrorHandling(
|
|
208
|
+
async (options: { file?: string }, cmd: Command) => {
|
|
209
|
+
const opts = getFormatOptions(cmd);
|
|
210
|
+
const svc = new DbService();
|
|
211
|
+
const dbName = await resolveDb(cmd, svc);
|
|
212
|
+
const remote = Boolean(
|
|
213
|
+
cmd.optsWithGlobals<{ remote?: boolean }>().remote
|
|
214
|
+
);
|
|
215
|
+
await handleApply(opts, dbName, remote, options.file);
|
|
216
|
+
},
|
|
217
|
+
{ service: "db" }
|
|
218
|
+
)
|
|
219
|
+
);
|
|
221
220
|
|
|
222
221
|
// -- migrate
|
|
223
222
|
dbCmd
|
|
224
223
|
.command("migrate")
|
|
225
224
|
.description("Run tracking migrations")
|
|
226
|
-
.action(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
225
|
+
.action(
|
|
226
|
+
withErrorHandling(
|
|
227
|
+
async (_, cmd: Command) => {
|
|
228
|
+
const opts = getFormatOptions(cmd);
|
|
229
|
+
const svc = new DbService();
|
|
230
|
+
const dbName = await resolveDb(cmd, svc);
|
|
231
|
+
const remote = Boolean(
|
|
232
|
+
cmd.optsWithGlobals<{ remote?: boolean }>().remote
|
|
233
|
+
);
|
|
234
|
+
await handleMigrate(opts, dbName, remote);
|
|
235
|
+
},
|
|
236
|
+
{ service: "db" }
|
|
237
|
+
)
|
|
238
|
+
);
|
|
240
239
|
|
|
241
240
|
// -- list
|
|
242
241
|
dbCmd
|
|
243
242
|
.command("list")
|
|
244
243
|
.description("List database tables")
|
|
245
|
-
.action(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
244
|
+
.action(
|
|
245
|
+
withErrorHandling(
|
|
246
|
+
async (_, cmd: Command) => {
|
|
247
|
+
const opts = getFormatOptions(cmd);
|
|
248
|
+
const svc = new DbService();
|
|
249
|
+
const dbName = await resolveDb(cmd, svc);
|
|
250
|
+
const remote = Boolean(
|
|
251
|
+
cmd.optsWithGlobals<{ remote?: boolean }>().remote
|
|
252
|
+
);
|
|
253
|
+
await handleList(opts, dbName, remote);
|
|
254
|
+
},
|
|
255
|
+
{ service: "db" }
|
|
256
|
+
)
|
|
257
|
+
);
|
|
259
258
|
|
|
260
259
|
// -- query
|
|
261
260
|
dbCmd
|
|
262
261
|
.command("query <sql>")
|
|
263
262
|
.description("Execute a SQL query")
|
|
264
|
-
.action(
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
263
|
+
.action(
|
|
264
|
+
withErrorHandling(
|
|
265
|
+
async (sql: string, _, cmd: Command) => {
|
|
266
|
+
const opts = getFormatOptions(cmd);
|
|
267
|
+
const svc = new DbService();
|
|
268
|
+
const dbName = await resolveDb(cmd, svc);
|
|
269
|
+
const remote = Boolean(
|
|
270
|
+
cmd.optsWithGlobals<{ remote?: boolean }>().remote
|
|
271
|
+
);
|
|
272
|
+
await handleQuery(opts, dbName, sql, remote);
|
|
273
|
+
},
|
|
274
|
+
{ service: "db" }
|
|
275
|
+
)
|
|
276
|
+
);
|
|
278
277
|
|
|
279
278
|
// -- export
|
|
280
279
|
dbCmd
|
|
281
280
|
.command("export")
|
|
282
281
|
.description("Export database to .sql file")
|
|
283
282
|
.option("--output <path>", "Output file path")
|
|
284
|
-
.action(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
283
|
+
.action(
|
|
284
|
+
withErrorHandling(
|
|
285
|
+
async (options: { output?: string }, cmd: Command) => {
|
|
286
|
+
const opts = getFormatOptions(cmd);
|
|
287
|
+
const svc = new DbService();
|
|
288
|
+
const dbName = await resolveDb(cmd, svc);
|
|
289
|
+
await handleExport(opts, dbName, options.output);
|
|
290
|
+
},
|
|
291
|
+
{ service: "db" }
|
|
292
|
+
)
|
|
293
|
+
);
|
|
295
294
|
|
|
296
295
|
// -- reset
|
|
297
296
|
dbCmd
|
|
298
297
|
.command("reset")
|
|
299
298
|
.description("Drop and recreate the database (DESTRUCTIVE)")
|
|
300
299
|
.option("--confirm", "Skip confirmation prompt")
|
|
301
|
-
.action(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
300
|
+
.action(
|
|
301
|
+
withErrorHandling(
|
|
302
|
+
async (options: { confirm?: boolean }, cmd: Command) => {
|
|
303
|
+
const opts = getFormatOptions(cmd);
|
|
304
|
+
const svc = new DbService();
|
|
305
|
+
const dbName = await resolveDb(cmd, svc);
|
|
306
|
+
await handleReset(opts, dbName, Boolean(options.confirm));
|
|
307
|
+
},
|
|
308
|
+
{ service: "db" }
|
|
309
|
+
)
|
|
310
|
+
);
|
|
312
311
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
/**
|
|
3
2
|
* Unit tests for the deploy command.
|
|
4
3
|
*
|
|
@@ -43,17 +42,20 @@ beforeEach(() => {
|
|
|
43
42
|
process.exitCode = undefined;
|
|
44
43
|
|
|
45
44
|
// Reset prototypes to originals (in case a previous test didn't restore)
|
|
46
|
-
(ConfigService.prototype as Record<string, unknown>).load =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).load =
|
|
46
|
+
origLoad;
|
|
47
|
+
(
|
|
48
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
49
|
+
).listEnabledWorkers = origListEnabled;
|
|
50
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).getWorker =
|
|
50
51
|
origGetWorker;
|
|
51
|
-
(CloudflareService.prototype as Record<string, unknown>).deploy =
|
|
52
|
+
(CloudflareService.prototype as unknown as Record<string, unknown>).deploy =
|
|
53
|
+
origDeploy;
|
|
52
54
|
|
|
53
55
|
// Fresh mocks
|
|
54
56
|
deployMock = mock(async (_path: string, _env?: string) => ({
|
|
55
57
|
ok: true as const,
|
|
56
|
-
|
|
58
|
+
value: { url: "https://test-worker.cryptolinx.workers.dev", rawOutput: "" },
|
|
57
59
|
}));
|
|
58
60
|
|
|
59
61
|
loadMock = mock(async () => ({}));
|
|
@@ -64,24 +66,30 @@ beforeEach(() => {
|
|
|
64
66
|
}));
|
|
65
67
|
|
|
66
68
|
// Install mocks on prototypes
|
|
67
|
-
(ConfigService.prototype as Record<string, unknown>).load =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).load =
|
|
70
|
+
loadMock;
|
|
71
|
+
(
|
|
72
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
73
|
+
).listEnabledWorkers = listEnabledWorkersMock;
|
|
74
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).getWorker =
|
|
71
75
|
getWorkerMock;
|
|
72
|
-
(CloudflareService.prototype as Record<string, unknown>).deploy =
|
|
76
|
+
(CloudflareService.prototype as unknown as Record<string, unknown>).deploy =
|
|
77
|
+
deployMock;
|
|
73
78
|
});
|
|
74
79
|
|
|
75
80
|
afterEach(() => {
|
|
76
81
|
mock.restore();
|
|
77
82
|
|
|
78
83
|
// Restore originals
|
|
79
|
-
(ConfigService.prototype as Record<string, unknown>).load =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).load =
|
|
85
|
+
origLoad;
|
|
86
|
+
(
|
|
87
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
88
|
+
).listEnabledWorkers = origListEnabled;
|
|
89
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).getWorker =
|
|
83
90
|
origGetWorker;
|
|
84
|
-
(CloudflareService.prototype as Record<string, unknown>).deploy =
|
|
91
|
+
(CloudflareService.prototype as unknown as Record<string, unknown>).deploy =
|
|
92
|
+
origDeploy;
|
|
85
93
|
});
|
|
86
94
|
|
|
87
95
|
// ---------------------------------------------------------------------------
|
|
@@ -109,7 +117,8 @@ async function createProgram(): Promise<Command> {
|
|
|
109
117
|
/** Make deployMock return a failure for all subsequent calls. */
|
|
110
118
|
function makeDeployFail(error: string): void {
|
|
111
119
|
deployMock = mock(async () => ({ ok: false as const, error }));
|
|
112
|
-
(CloudflareService.prototype as Record<string, unknown>).deploy =
|
|
120
|
+
(CloudflareService.prototype as unknown as Record<string, unknown>).deploy =
|
|
121
|
+
deployMock;
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
// ---------------------------------------------------------------------------
|
|
@@ -169,8 +178,9 @@ describe("registerDeployCommand", () => {
|
|
|
169
178
|
"hoox",
|
|
170
179
|
"trade-worker",
|
|
171
180
|
]);
|
|
172
|
-
(
|
|
173
|
-
|
|
181
|
+
(
|
|
182
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
183
|
+
).listEnabledWorkers = listEnabledWorkersMock;
|
|
174
184
|
|
|
175
185
|
const program = await createProgram();
|
|
176
186
|
await program.parseAsync(["deploy", "workers"], { from: "user" });
|
|
@@ -181,8 +191,9 @@ describe("registerDeployCommand", () => {
|
|
|
181
191
|
|
|
182
192
|
it("handles no enabled workers gracefully", async () => {
|
|
183
193
|
listEnabledWorkersMock = mock(() => []);
|
|
184
|
-
(
|
|
185
|
-
|
|
194
|
+
(
|
|
195
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
196
|
+
).listEnabledWorkers = listEnabledWorkersMock;
|
|
186
197
|
|
|
187
198
|
const program = await createProgram();
|
|
188
199
|
await program.parseAsync(["deploy", "workers"], { from: "user" });
|
|
@@ -192,8 +203,9 @@ describe("registerDeployCommand", () => {
|
|
|
192
203
|
|
|
193
204
|
it("continues deploying remaining workers on partial failure", async () => {
|
|
194
205
|
listEnabledWorkersMock = mock(() => ["a", "b", "c"]);
|
|
195
|
-
(
|
|
196
|
-
|
|
206
|
+
(
|
|
207
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
208
|
+
).listEnabledWorkers = listEnabledWorkersMock;
|
|
197
209
|
|
|
198
210
|
let calls = 0;
|
|
199
211
|
deployMock = mock(async () => {
|
|
@@ -201,10 +213,14 @@ describe("registerDeployCommand", () => {
|
|
|
201
213
|
if (calls === 2) {
|
|
202
214
|
return { ok: false as const, error: "deploy error" };
|
|
203
215
|
}
|
|
204
|
-
return {
|
|
216
|
+
return {
|
|
217
|
+
ok: true as const,
|
|
218
|
+
value: { url: "https://x.workers.dev", rawOutput: "" },
|
|
219
|
+
};
|
|
205
220
|
});
|
|
206
|
-
(
|
|
207
|
-
|
|
221
|
+
(
|
|
222
|
+
CloudflareService.prototype as unknown as Record<string, unknown>
|
|
223
|
+
).deploy = deployMock;
|
|
208
224
|
|
|
209
225
|
const program = await createProgram();
|
|
210
226
|
await program.parseAsync(["deploy", "workers"], { from: "user" });
|
|
@@ -215,8 +231,9 @@ describe("registerDeployCommand", () => {
|
|
|
215
231
|
|
|
216
232
|
it("passes --env to deploy", async () => {
|
|
217
233
|
listEnabledWorkersMock = mock(() => ["single-worker"]);
|
|
218
|
-
(
|
|
219
|
-
|
|
234
|
+
(
|
|
235
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
236
|
+
).listEnabledWorkers = listEnabledWorkersMock;
|
|
220
237
|
|
|
221
238
|
const program = await createProgram();
|
|
222
239
|
await program.parseAsync(["deploy", "workers", "--env", "staging"], {
|
|
@@ -264,8 +281,9 @@ describe("registerDeployCommand", () => {
|
|
|
264
281
|
enabled: true,
|
|
265
282
|
path: "workers/hoox",
|
|
266
283
|
}));
|
|
267
|
-
(
|
|
268
|
-
|
|
284
|
+
(
|
|
285
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
286
|
+
).getWorker = getWorkerMock;
|
|
269
287
|
|
|
270
288
|
const program = await createProgram();
|
|
271
289
|
await program.parseAsync(["deploy", "worker", "hoox"], { from: "user" });
|
|
@@ -275,8 +293,9 @@ describe("registerDeployCommand", () => {
|
|
|
275
293
|
|
|
276
294
|
it("handles unknown worker name without calling deploy", async () => {
|
|
277
295
|
getWorkerMock = mock(() => undefined);
|
|
278
|
-
(
|
|
279
|
-
|
|
296
|
+
(
|
|
297
|
+
ConfigService.prototype as unknown as Record<string, unknown>
|
|
298
|
+
).getWorker = getWorkerMock;
|
|
280
299
|
|
|
281
300
|
const program = await createProgram();
|
|
282
301
|
await program.parseAsync(["deploy", "worker", "nonexistent"], {
|
|
@@ -294,7 +313,8 @@ describe("registerDeployCommand", () => {
|
|
|
294
313
|
loadMock = mock(async () => {
|
|
295
314
|
throw new Error("Config file not found");
|
|
296
315
|
});
|
|
297
|
-
(ConfigService.prototype as Record<string, unknown>).load =
|
|
316
|
+
(ConfigService.prototype as unknown as Record<string, unknown>).load =
|
|
317
|
+
loadMock;
|
|
298
318
|
|
|
299
319
|
const program = await createProgram();
|
|
300
320
|
await program.parseAsync(["deploy", "workers"], { from: "user" });
|
|
@@ -324,7 +324,7 @@ async function deployDashboard(
|
|
|
324
324
|
|
|
325
325
|
if (action === "rebuild") {
|
|
326
326
|
// Build + Deploy: bun run deploy (runs opennext:build && opennext:deploy)
|
|
327
|
-
const buildProc = Bun.spawn(["bun", "run", "
|
|
327
|
+
const buildProc = Bun.spawn(["bun", "run", "deploy"], {
|
|
328
328
|
cwd: dashboardPath,
|
|
329
329
|
stdout: "pipe",
|
|
330
330
|
stderr: "pipe",
|
|
@@ -440,87 +440,6 @@ async function deployDashboard(
|
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
-
/**
|
|
444
|
-
* Print a summary table of deploy results.
|
|
445
|
-
* Excluded in quiet mode; uses JSON or box-drawn table depending on --json.
|
|
446
|
-
*/
|
|
447
|
-
function printSummary(
|
|
448
|
-
results: DeployResult[],
|
|
449
|
-
opts: { json?: boolean; quiet?: boolean }
|
|
450
|
-
): void {
|
|
451
|
-
if (opts.quiet) return;
|
|
452
|
-
|
|
453
|
-
// Separate workers from dashboard for different formatting
|
|
454
|
-
const workerResults = results.filter((r) => r.worker !== "dashboard");
|
|
455
|
-
const dashboardResult = results.find((r) => r.worker === "dashboard");
|
|
456
|
-
|
|
457
|
-
// Print worker deployments with verbose info
|
|
458
|
-
if (workerResults.length > 0) {
|
|
459
|
-
process.stdout.write(`\n${theme.heading("Workers Deployed")}\n`);
|
|
460
|
-
for (const r of workerResults) {
|
|
461
|
-
const icon = r.success
|
|
462
|
-
? theme.success(icons.success)
|
|
463
|
-
: theme.error(icons.error);
|
|
464
|
-
const status = r.success ? "deployed" : "failed";
|
|
465
|
-
process.stdout.write(`${icon} ${r.worker}: ${status}\n`);
|
|
466
|
-
|
|
467
|
-
if (r.success && r.url) {
|
|
468
|
-
process.stdout.write(` ${theme.dim("URL:")} ${r.url}\n`);
|
|
469
|
-
}
|
|
470
|
-
if (r.success && r.size) {
|
|
471
|
-
process.stdout.write(` ${theme.dim("Size:")} ${r.size}\n`);
|
|
472
|
-
}
|
|
473
|
-
if (r.success && r.startupTime) {
|
|
474
|
-
process.stdout.write(` ${theme.dim("Startup:")} ${r.startupTime}\n`);
|
|
475
|
-
}
|
|
476
|
-
if (r.success && r.versionId) {
|
|
477
|
-
process.stdout.write(
|
|
478
|
-
` ${theme.dim("Version:")} ${r.versionId.slice(0, 8)}...\n`
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
if (!r.success && r.error) {
|
|
482
|
-
process.stdout.write(` ${theme.error("Error:")} ${r.error}\n`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Print dashboard deployment
|
|
488
|
-
if (dashboardResult) {
|
|
489
|
-
process.stdout.write(`\n${theme.heading("Dashboard Deployed")}\n`);
|
|
490
|
-
const icon = dashboardResult.success
|
|
491
|
-
? theme.success(icons.success)
|
|
492
|
-
: theme.error(icons.error);
|
|
493
|
-
const status = dashboardResult.success ? "deployed" : "failed";
|
|
494
|
-
process.stdout.write(`${icon} dashboard: ${status}\n`);
|
|
495
|
-
|
|
496
|
-
if (dashboardResult.success && dashboardResult.url) {
|
|
497
|
-
process.stdout.write(` ${theme.dim("URL:")} ${dashboardResult.url}\n`);
|
|
498
|
-
}
|
|
499
|
-
if (dashboardResult.success && dashboardResult.size) {
|
|
500
|
-
process.stdout.write(
|
|
501
|
-
` ${theme.dim("Size:")} ${dashboardResult.size}\n`
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
if (dashboardResult.success && dashboardResult.startupTime) {
|
|
505
|
-
process.stdout.write(
|
|
506
|
-
` ${theme.dim("Startup:")} ${dashboardResult.startupTime}\n`
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
if (!dashboardResult.success && dashboardResult.error) {
|
|
510
|
-
process.stdout.write(
|
|
511
|
-
` ${theme.error("Error:")} ${dashboardResult.error}\n`
|
|
512
|
-
);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Summary line
|
|
517
|
-
const succeeded = results.filter((r) => r.success).length;
|
|
518
|
-
const failed = results.filter((r) => !r.success).length;
|
|
519
|
-
process.stdout.write(
|
|
520
|
-
`\n${theme.heading("Summary:")} ${succeeded} succeeded, ${failed} failed\n`
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
443
|
// ---------------------------------------------------------------------------
|
|
525
444
|
// Telegram webhook handler
|
|
526
445
|
// ---------------------------------------------------------------------------
|
|
@@ -545,12 +464,12 @@ async function doTelegramWebhook(
|
|
|
545
464
|
let botToken = token;
|
|
546
465
|
if (!botToken) {
|
|
547
466
|
const envVars = await EnvService.loadDotEnvAsync(".env.local");
|
|
548
|
-
botToken = envVars["
|
|
467
|
+
botToken = envVars["TG_BOT_TOKEN_BINDING"];
|
|
549
468
|
}
|
|
550
469
|
if (!botToken) {
|
|
551
470
|
formatError(
|
|
552
471
|
new CLIError(
|
|
553
|
-
"Telegram bot token not found. Provide --token or set
|
|
472
|
+
"Telegram bot token not found. Provide --token or set TG_BOT_TOKEN_BINDING in .env.local",
|
|
554
473
|
ExitCode.ERROR
|
|
555
474
|
),
|
|
556
475
|
fmt
|