teleton 0.6.0 → 0.7.1
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/README.md +34 -31
- package/dist/{chunk-6L6KGATM.js → chunk-3YM57ZAV.js} +1638 -1749
- package/dist/{chunk-D5I7GBV7.js → chunk-FNV5FF35.js} +22 -13
- package/dist/{chunk-4IPJ25HE.js → chunk-HZNZT4TG.js} +1106 -711
- package/dist/chunk-LRCPA7SC.js +149 -0
- package/dist/chunk-ND2X5FWB.js +368 -0
- package/dist/chunk-NERLQY2H.js +421 -0
- package/dist/{chunk-YBA6IBGT.js → chunk-OCLG5GKI.js} +24 -24
- package/dist/{chunk-ADCMUNYU.js → chunk-RBU6JXD3.js} +60 -55
- package/dist/chunk-RCMD3U65.js +141 -0
- package/dist/{chunk-ECSCVEQQ.js → chunk-UCN6TI25.js} +7 -3
- package/dist/{chunk-WL2Q3VRD.js → chunk-UDD7FYOU.js} +12 -4
- package/dist/chunk-VAUJSSD3.js +20 -0
- package/dist/chunk-XBE4JB7C.js +8 -0
- package/dist/{chunk-GDCODBNO.js → chunk-XBKSS6DM.js} +2 -16
- package/dist/cli/index.js +878 -433
- package/dist/client-3VWE7NC4.js +29 -0
- package/dist/{get-my-gifts-KVULMBJ3.js → get-my-gifts-RI7FAXAL.js} +3 -1
- package/dist/index.js +17 -11
- package/dist/{memory-TVDOGQXS.js → memory-5SS3Q5EA.js} +7 -5
- package/dist/{migrate-QIEMPOMT.js → migrate-M7SJMDOL.js} +14 -9
- package/dist/{server-RSWVCVY3.js → server-DS5OARW6.js} +174 -85
- package/dist/setup-server-C7ZTPHD5.js +934 -0
- package/dist/{task-dependency-resolver-72DLY2HV.js → task-dependency-resolver-WKZWJLLM.js} +19 -15
- package/dist/{task-executor-VXB6DAV2.js → task-executor-PD3H4MLO.js} +4 -1
- package/dist/tool-adapter-Y3TCEQOC.js +145 -0
- package/dist/{tool-index-DKI2ZNOU.js → tool-index-MIVK3D7H.js} +14 -9
- package/dist/{transcript-7V4UNID4.js → transcript-UDJZP6NK.js} +2 -1
- package/dist/web/assets/complete-fZLnb5Ot.js +1 -0
- package/dist/web/assets/index-BqwoDycr.js +72 -0
- package/dist/web/assets/index-CRDIf07k.css +1 -0
- package/dist/web/assets/index.es-D81xLR29.js +11 -0
- package/dist/web/assets/login-telegram-BP7CJDmx.js +1 -0
- package/dist/web/assets/run-DOrDowjK.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +7 -3
- package/dist/chunk-2QUJLHCZ.js +0 -362
- package/dist/web/assets/index-BNhrx9S1.js +0 -67
- package/dist/web/assets/index-CqrrRLOh.css +0 -1
|
@@ -0,0 +1,934 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConfigSchema,
|
|
3
|
+
DealsConfigSchema,
|
|
4
|
+
ensureWorkspace,
|
|
5
|
+
generateWallet,
|
|
6
|
+
getWalletAddress,
|
|
7
|
+
importWallet,
|
|
8
|
+
isNewWorkspace,
|
|
9
|
+
saveWallet,
|
|
10
|
+
walletExists
|
|
11
|
+
} from "./chunk-NERLQY2H.js";
|
|
12
|
+
import "./chunk-QUAPFI2N.js";
|
|
13
|
+
import {
|
|
14
|
+
getProviderMetadata,
|
|
15
|
+
getSupportedProviders,
|
|
16
|
+
validateApiKeyFormat
|
|
17
|
+
} from "./chunk-LRCPA7SC.js";
|
|
18
|
+
import "./chunk-XBKSS6DM.js";
|
|
19
|
+
import {
|
|
20
|
+
TELEGRAM_MAX_MESSAGE_LENGTH
|
|
21
|
+
} from "./chunk-RO62LO6Z.js";
|
|
22
|
+
import {
|
|
23
|
+
fetchWithTimeout
|
|
24
|
+
} from "./chunk-VAUJSSD3.js";
|
|
25
|
+
import "./chunk-4DU3C27M.js";
|
|
26
|
+
import {
|
|
27
|
+
TELETON_ROOT
|
|
28
|
+
} from "./chunk-EYWNOHMJ.js";
|
|
29
|
+
import {
|
|
30
|
+
createLogger
|
|
31
|
+
} from "./chunk-RCMD3U65.js";
|
|
32
|
+
import "./chunk-QGM4M3NI.js";
|
|
33
|
+
|
|
34
|
+
// src/webui/setup-server.ts
|
|
35
|
+
import { Hono as Hono2 } from "hono";
|
|
36
|
+
import { serve } from "@hono/node-server";
|
|
37
|
+
import { cors } from "hono/cors";
|
|
38
|
+
import { bodyLimit } from "hono/body-limit";
|
|
39
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
40
|
+
import { join as join3, dirname as dirname2, resolve, relative } from "path";
|
|
41
|
+
import { fileURLToPath } from "url";
|
|
42
|
+
import { exec } from "child_process";
|
|
43
|
+
import { platform } from "os";
|
|
44
|
+
|
|
45
|
+
// src/webui/routes/setup.ts
|
|
46
|
+
import { Hono } from "hono";
|
|
47
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
48
|
+
import { join as join2 } from "path";
|
|
49
|
+
import YAML from "yaml";
|
|
50
|
+
|
|
51
|
+
// src/webui/setup-auth.ts
|
|
52
|
+
import { TelegramClient, Api } from "telegram";
|
|
53
|
+
import { StringSession } from "telegram/sessions/index.js";
|
|
54
|
+
import { computeCheck } from "telegram/Password.js";
|
|
55
|
+
import { Logger, LogLevel } from "telegram/extensions/Logger.js";
|
|
56
|
+
import { writeFileSync, mkdirSync, existsSync } from "fs";
|
|
57
|
+
import { dirname, join } from "path";
|
|
58
|
+
import { randomBytes } from "crypto";
|
|
59
|
+
var log = createLogger("Setup");
|
|
60
|
+
var SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
61
|
+
var MAX_CODE_ATTEMPTS = 5;
|
|
62
|
+
var MAX_PASSWORD_ATTEMPTS = 3;
|
|
63
|
+
var TelegramAuthManager = class {
|
|
64
|
+
session = null;
|
|
65
|
+
/**
|
|
66
|
+
* Send verification code to phone number
|
|
67
|
+
*/
|
|
68
|
+
async sendCode(apiId, apiHash, phone) {
|
|
69
|
+
await this.cleanup();
|
|
70
|
+
const gramLogger = new Logger(LogLevel.NONE);
|
|
71
|
+
const client = new TelegramClient(new StringSession(""), apiId, apiHash, {
|
|
72
|
+
connectionRetries: 3,
|
|
73
|
+
floodSleepThreshold: 0,
|
|
74
|
+
baseLogger: gramLogger
|
|
75
|
+
});
|
|
76
|
+
await client.connect();
|
|
77
|
+
const result = await client.sendCode({ apiId, apiHash }, phone);
|
|
78
|
+
const id = randomBytes(16).toString("hex");
|
|
79
|
+
const expiresAt = Date.now() + SESSION_TTL_MS;
|
|
80
|
+
this.session = {
|
|
81
|
+
id,
|
|
82
|
+
client,
|
|
83
|
+
phone,
|
|
84
|
+
phoneCodeHash: result.phoneCodeHash,
|
|
85
|
+
state: "code_sent",
|
|
86
|
+
codeAttempts: 0,
|
|
87
|
+
passwordAttempts: 0,
|
|
88
|
+
createdAt: Date.now(),
|
|
89
|
+
apiId,
|
|
90
|
+
apiHash,
|
|
91
|
+
timer: setTimeout(() => this.cleanup(), SESSION_TTL_MS)
|
|
92
|
+
};
|
|
93
|
+
log.info("Telegram verification code sent");
|
|
94
|
+
return { authSessionId: id, codeViaApp: result.isCodeViaApp, expiresAt };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Verify the code entered by the user
|
|
98
|
+
*/
|
|
99
|
+
async verifyCode(authSessionId, code) {
|
|
100
|
+
const session = this.getSession(authSessionId);
|
|
101
|
+
if (!session) return { status: "expired" };
|
|
102
|
+
if (session.codeAttempts >= MAX_CODE_ATTEMPTS) {
|
|
103
|
+
return { status: "too_many_attempts" };
|
|
104
|
+
}
|
|
105
|
+
session.codeAttempts++;
|
|
106
|
+
try {
|
|
107
|
+
const result = await session.client.invoke(
|
|
108
|
+
new Api.auth.SignIn({
|
|
109
|
+
phoneNumber: session.phone,
|
|
110
|
+
phoneCodeHash: session.phoneCodeHash,
|
|
111
|
+
phoneCode: code
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
session.state = "authenticated";
|
|
115
|
+
const user = this.extractUser(result);
|
|
116
|
+
await this.saveSession(session);
|
|
117
|
+
log.info("Telegram authentication successful");
|
|
118
|
+
return { status: "authenticated", user };
|
|
119
|
+
} catch (err) {
|
|
120
|
+
const error = err;
|
|
121
|
+
if (error.errorMessage === "SESSION_PASSWORD_NEEDED") {
|
|
122
|
+
session.state = "2fa_required";
|
|
123
|
+
try {
|
|
124
|
+
const passwordResult = await session.client.invoke(new Api.account.GetPassword());
|
|
125
|
+
session.passwordHint = passwordResult.hint ?? void 0;
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
return { status: "2fa_required", passwordHint: session.passwordHint };
|
|
129
|
+
}
|
|
130
|
+
if (error.errorMessage === "PHONE_CODE_INVALID") {
|
|
131
|
+
return { status: "invalid_code" };
|
|
132
|
+
}
|
|
133
|
+
if (error.errorMessage === "PHONE_CODE_EXPIRED") {
|
|
134
|
+
session.state = "failed";
|
|
135
|
+
return { status: "expired" };
|
|
136
|
+
}
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Verify 2FA password
|
|
142
|
+
*/
|
|
143
|
+
async verifyPassword(authSessionId, password) {
|
|
144
|
+
const session = this.getSession(authSessionId);
|
|
145
|
+
if (!session) return { status: "expired" };
|
|
146
|
+
if (session.state !== "2fa_required") return { status: "expired" };
|
|
147
|
+
if (session.passwordAttempts >= MAX_PASSWORD_ATTEMPTS) {
|
|
148
|
+
return { status: "too_many_attempts" };
|
|
149
|
+
}
|
|
150
|
+
session.passwordAttempts++;
|
|
151
|
+
try {
|
|
152
|
+
const srpResult = await session.client.invoke(new Api.account.GetPassword());
|
|
153
|
+
const srpCheck = await computeCheck(srpResult, password);
|
|
154
|
+
const result = await session.client.invoke(
|
|
155
|
+
new Api.auth.CheckPassword({ password: srpCheck })
|
|
156
|
+
);
|
|
157
|
+
session.state = "authenticated";
|
|
158
|
+
const user = this.extractUser(result);
|
|
159
|
+
await this.saveSession(session);
|
|
160
|
+
log.info("Telegram 2FA authentication successful");
|
|
161
|
+
return { status: "authenticated", user };
|
|
162
|
+
} catch (err) {
|
|
163
|
+
const error = err;
|
|
164
|
+
if (error.errorMessage === "PASSWORD_HASH_INVALID") {
|
|
165
|
+
return { status: "invalid_password" };
|
|
166
|
+
}
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Resend verification code
|
|
172
|
+
*/
|
|
173
|
+
async resendCode(authSessionId) {
|
|
174
|
+
const session = this.getSession(authSessionId);
|
|
175
|
+
if (!session || session.state !== "code_sent") return null;
|
|
176
|
+
const result = await session.client.invoke(
|
|
177
|
+
new Api.auth.ResendCode({
|
|
178
|
+
phoneNumber: session.phone,
|
|
179
|
+
phoneCodeHash: session.phoneCodeHash
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
if (result instanceof Api.auth.SentCode) {
|
|
183
|
+
session.phoneCodeHash = result.phoneCodeHash;
|
|
184
|
+
session.codeAttempts = 0;
|
|
185
|
+
const codeViaApp = result.type instanceof Api.auth.SentCodeTypeApp;
|
|
186
|
+
return { codeViaApp };
|
|
187
|
+
}
|
|
188
|
+
return { codeViaApp: false };
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Cancel and clean up session
|
|
192
|
+
*/
|
|
193
|
+
async cancelSession(authSessionId) {
|
|
194
|
+
if (this.session?.id === authSessionId) {
|
|
195
|
+
await this.cleanup();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Clean up: disconnect client, clear timer, remove session
|
|
200
|
+
*/
|
|
201
|
+
async cleanup() {
|
|
202
|
+
if (!this.session) return;
|
|
203
|
+
clearTimeout(this.session.timer);
|
|
204
|
+
try {
|
|
205
|
+
if (this.session.client.connected) {
|
|
206
|
+
await this.session.client.disconnect();
|
|
207
|
+
}
|
|
208
|
+
} catch (err) {
|
|
209
|
+
log.warn({ err }, "Error disconnecting auth client");
|
|
210
|
+
}
|
|
211
|
+
this.session = null;
|
|
212
|
+
}
|
|
213
|
+
getSession(id) {
|
|
214
|
+
if (!this.session || this.session.id !== id) return null;
|
|
215
|
+
if (Date.now() - this.session.createdAt > SESSION_TTL_MS) {
|
|
216
|
+
this.cleanup();
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
return this.session;
|
|
220
|
+
}
|
|
221
|
+
extractUser(result) {
|
|
222
|
+
if (result instanceof Api.auth.Authorization && result.user instanceof Api.User) {
|
|
223
|
+
return {
|
|
224
|
+
id: Number(result.user.id),
|
|
225
|
+
firstName: result.user.firstName ?? "",
|
|
226
|
+
username: result.user.username ?? void 0
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
231
|
+
async saveSession(session) {
|
|
232
|
+
const sessionString = session.client.session.save();
|
|
233
|
+
const sessionPath = join(TELETON_ROOT, "telegram_session.txt");
|
|
234
|
+
const dir = dirname(sessionPath);
|
|
235
|
+
if (!existsSync(dir)) {
|
|
236
|
+
mkdirSync(dir, { recursive: true });
|
|
237
|
+
}
|
|
238
|
+
writeFileSync(sessionPath, sessionString, { mode: 384 });
|
|
239
|
+
log.info("Telegram session saved");
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/webui/routes/setup.ts
|
|
244
|
+
var log2 = createLogger("Setup");
|
|
245
|
+
var MODEL_OPTIONS = {
|
|
246
|
+
anthropic: [
|
|
247
|
+
{
|
|
248
|
+
value: "claude-opus-4-5-20251101",
|
|
249
|
+
name: "Claude Opus 4.5",
|
|
250
|
+
description: "Most capable, $5/M"
|
|
251
|
+
},
|
|
252
|
+
{ value: "claude-sonnet-4-0", name: "Claude Sonnet 4", description: "Balanced, $3/M" },
|
|
253
|
+
{
|
|
254
|
+
value: "claude-haiku-4-5-20251001",
|
|
255
|
+
name: "Claude Haiku 4.5",
|
|
256
|
+
description: "Fast & cheap, $1/M"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
value: "claude-3-5-haiku-20241022",
|
|
260
|
+
name: "Claude 3.5 Haiku",
|
|
261
|
+
description: "Cheapest, $0.80/M"
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
openai: [
|
|
265
|
+
{ value: "gpt-5", name: "GPT-5", description: "Most capable, 400K ctx, $1.25/M" },
|
|
266
|
+
{ value: "gpt-4o", name: "GPT-4o", description: "Balanced, 128K ctx, $2.50/M" },
|
|
267
|
+
{ value: "gpt-4.1", name: "GPT-4.1", description: "1M ctx, $2/M" },
|
|
268
|
+
{ value: "gpt-4.1-mini", name: "GPT-4.1 Mini", description: "1M ctx, cheap, $0.40/M" },
|
|
269
|
+
{ value: "o3", name: "o3", description: "Reasoning, 200K ctx, $2/M" }
|
|
270
|
+
],
|
|
271
|
+
google: [
|
|
272
|
+
{ value: "gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "Fast, 1M ctx, $0.30/M" },
|
|
273
|
+
{
|
|
274
|
+
value: "gemini-2.5-pro",
|
|
275
|
+
name: "Gemini 2.5 Pro",
|
|
276
|
+
description: "Most capable, 1M ctx, $1.25/M"
|
|
277
|
+
},
|
|
278
|
+
{ value: "gemini-2.0-flash", name: "Gemini 2.0 Flash", description: "Cheap, 1M ctx, $0.10/M" }
|
|
279
|
+
],
|
|
280
|
+
xai: [
|
|
281
|
+
{ value: "grok-4-fast", name: "Grok 4 Fast", description: "Vision, 2M ctx, $0.20/M" },
|
|
282
|
+
{ value: "grok-4", name: "Grok 4", description: "Reasoning, 256K ctx, $3/M" },
|
|
283
|
+
{ value: "grok-3", name: "Grok 3", description: "Stable, 131K ctx, $3/M" }
|
|
284
|
+
],
|
|
285
|
+
groq: [
|
|
286
|
+
{
|
|
287
|
+
value: "meta-llama/llama-4-maverick-17b-128e-instruct",
|
|
288
|
+
name: "Llama 4 Maverick",
|
|
289
|
+
description: "Vision, 131K ctx, $0.20/M"
|
|
290
|
+
},
|
|
291
|
+
{ value: "qwen/qwen3-32b", name: "Qwen3 32B", description: "Reasoning, 131K ctx, $0.29/M" },
|
|
292
|
+
{
|
|
293
|
+
value: "deepseek-r1-distill-llama-70b",
|
|
294
|
+
name: "DeepSeek R1 70B",
|
|
295
|
+
description: "Reasoning, 131K ctx, $0.75/M"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
value: "llama-3.3-70b-versatile",
|
|
299
|
+
name: "Llama 3.3 70B",
|
|
300
|
+
description: "General purpose, 131K ctx, $0.59/M"
|
|
301
|
+
}
|
|
302
|
+
],
|
|
303
|
+
openrouter: [
|
|
304
|
+
{ value: "anthropic/claude-opus-4.5", name: "Claude Opus 4.5", description: "200K ctx, $5/M" },
|
|
305
|
+
{ value: "openai/gpt-5", name: "GPT-5", description: "400K ctx, $1.25/M" },
|
|
306
|
+
{ value: "google/gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "1M ctx, $0.30/M" },
|
|
307
|
+
{
|
|
308
|
+
value: "deepseek/deepseek-r1",
|
|
309
|
+
name: "DeepSeek R1",
|
|
310
|
+
description: "Reasoning, 64K ctx, $0.70/M"
|
|
311
|
+
},
|
|
312
|
+
{ value: "x-ai/grok-4", name: "Grok 4", description: "256K ctx, $3/M" }
|
|
313
|
+
],
|
|
314
|
+
moonshot: [
|
|
315
|
+
{ value: "kimi-k2.5", name: "Kimi K2.5", description: "Free, 256K ctx, multimodal" },
|
|
316
|
+
{
|
|
317
|
+
value: "kimi-k2-thinking",
|
|
318
|
+
name: "Kimi K2 Thinking",
|
|
319
|
+
description: "Free, 256K ctx, reasoning"
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
mistral: [
|
|
323
|
+
{
|
|
324
|
+
value: "devstral-small-2507",
|
|
325
|
+
name: "Devstral Small",
|
|
326
|
+
description: "Coding, 128K ctx, $0.10/M"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
value: "devstral-medium-latest",
|
|
330
|
+
name: "Devstral Medium",
|
|
331
|
+
description: "Coding, 262K ctx, $0.40/M"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
value: "mistral-large-latest",
|
|
335
|
+
name: "Mistral Large",
|
|
336
|
+
description: "General, 128K ctx, $2/M"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
value: "magistral-small",
|
|
340
|
+
name: "Magistral Small",
|
|
341
|
+
description: "Reasoning, 128K ctx, $0.50/M"
|
|
342
|
+
}
|
|
343
|
+
]
|
|
344
|
+
};
|
|
345
|
+
function maskKey(key) {
|
|
346
|
+
if (key.length <= 10) return "***";
|
|
347
|
+
return key.slice(0, 6) + "..." + key.slice(-4);
|
|
348
|
+
}
|
|
349
|
+
function createSetupRoutes() {
|
|
350
|
+
const app = new Hono();
|
|
351
|
+
const authManager = new TelegramAuthManager();
|
|
352
|
+
app.get("/status", async (c) => {
|
|
353
|
+
try {
|
|
354
|
+
const configPath = join2(TELETON_ROOT, "config.yaml");
|
|
355
|
+
const sessionPath = join2(TELETON_ROOT, "telegram_session.txt");
|
|
356
|
+
const envApiKey = process.env.TELETON_API_KEY;
|
|
357
|
+
const envApiId = process.env.TELETON_TG_API_ID;
|
|
358
|
+
const envApiHash = process.env.TELETON_TG_API_HASH;
|
|
359
|
+
const envPhone = process.env.TELETON_TG_PHONE;
|
|
360
|
+
return c.json({
|
|
361
|
+
success: true,
|
|
362
|
+
data: {
|
|
363
|
+
workspaceExists: existsSync2(join2(TELETON_ROOT, "workspace")),
|
|
364
|
+
configExists: existsSync2(configPath),
|
|
365
|
+
walletExists: walletExists(),
|
|
366
|
+
walletAddress: getWalletAddress(),
|
|
367
|
+
sessionExists: existsSync2(sessionPath),
|
|
368
|
+
envVars: {
|
|
369
|
+
apiKey: envApiKey ? maskKey(envApiKey) : null,
|
|
370
|
+
apiKeyRaw: !!envApiKey,
|
|
371
|
+
telegramApiId: envApiId ?? null,
|
|
372
|
+
telegramApiHash: envApiHash ? maskKey(envApiHash) : null,
|
|
373
|
+
telegramPhone: envPhone ?? null
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
} catch (err) {
|
|
378
|
+
return c.json(
|
|
379
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
380
|
+
500
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
app.get("/providers", (c) => {
|
|
385
|
+
const providers = getSupportedProviders().map((p) => ({
|
|
386
|
+
id: p.id,
|
|
387
|
+
displayName: p.displayName,
|
|
388
|
+
defaultModel: p.defaultModel,
|
|
389
|
+
utilityModel: p.utilityModel,
|
|
390
|
+
toolLimit: p.toolLimit,
|
|
391
|
+
keyPrefix: p.keyPrefix,
|
|
392
|
+
consoleUrl: p.consoleUrl,
|
|
393
|
+
requiresApiKey: p.id !== "cocoon" && p.id !== "local",
|
|
394
|
+
requiresBaseUrl: p.id === "local"
|
|
395
|
+
}));
|
|
396
|
+
return c.json({ success: true, data: providers });
|
|
397
|
+
});
|
|
398
|
+
app.get("/models/:provider", (c) => {
|
|
399
|
+
const provider = c.req.param("provider");
|
|
400
|
+
const models = MODEL_OPTIONS[provider] || [];
|
|
401
|
+
const result = [
|
|
402
|
+
...models,
|
|
403
|
+
{
|
|
404
|
+
value: "__custom__",
|
|
405
|
+
name: "Custom",
|
|
406
|
+
description: "Enter a model ID manually",
|
|
407
|
+
isCustom: true
|
|
408
|
+
}
|
|
409
|
+
];
|
|
410
|
+
return c.json({ success: true, data: result });
|
|
411
|
+
});
|
|
412
|
+
app.post("/validate/api-key", async (c) => {
|
|
413
|
+
try {
|
|
414
|
+
const body = await c.req.json();
|
|
415
|
+
const error = validateApiKeyFormat(body.provider, body.apiKey);
|
|
416
|
+
return c.json({ success: true, data: { valid: !error, error } });
|
|
417
|
+
} catch (err) {
|
|
418
|
+
return c.json(
|
|
419
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
420
|
+
400
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
app.post("/validate/bot-token", async (c) => {
|
|
425
|
+
try {
|
|
426
|
+
const body = await c.req.json();
|
|
427
|
+
if (!body.token || !body.token.includes(":")) {
|
|
428
|
+
return c.json({
|
|
429
|
+
success: true,
|
|
430
|
+
data: { valid: false, networkError: false, error: "Invalid format (expected id:hash)" }
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
const res = await fetchWithTimeout(`https://api.telegram.org/bot${body.token}/getMe`);
|
|
435
|
+
const data = await res.json();
|
|
436
|
+
if (!data.ok) {
|
|
437
|
+
return c.json({
|
|
438
|
+
success: true,
|
|
439
|
+
data: { valid: false, networkError: false, error: "Bot token is invalid" }
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return c.json({
|
|
443
|
+
success: true,
|
|
444
|
+
data: {
|
|
445
|
+
valid: true,
|
|
446
|
+
networkError: false,
|
|
447
|
+
bot: { username: data.result.username, firstName: data.result.first_name }
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
} catch {
|
|
451
|
+
return c.json({
|
|
452
|
+
success: true,
|
|
453
|
+
data: { valid: false, networkError: true, error: "Could not reach Telegram API" }
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
} catch (err) {
|
|
457
|
+
return c.json(
|
|
458
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
459
|
+
400
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
app.post("/workspace/init", async (c) => {
|
|
464
|
+
try {
|
|
465
|
+
const body = await c.req.json().catch(() => ({ agentName: void 0, workspaceDir: void 0 }));
|
|
466
|
+
const workspace = await ensureWorkspace({
|
|
467
|
+
workspaceDir: body.workspaceDir,
|
|
468
|
+
ensureTemplates: true
|
|
469
|
+
});
|
|
470
|
+
if (body.agentName?.trim() && existsSync2(workspace.identityPath)) {
|
|
471
|
+
const identity = readFileSync(workspace.identityPath, "utf-8");
|
|
472
|
+
const updated = identity.replace(
|
|
473
|
+
"[Your name - pick one or ask your human]",
|
|
474
|
+
body.agentName.trim()
|
|
475
|
+
);
|
|
476
|
+
writeFileSync2(workspace.identityPath, updated, "utf-8");
|
|
477
|
+
}
|
|
478
|
+
return c.json({
|
|
479
|
+
success: true,
|
|
480
|
+
data: { created: !isNewWorkspace(workspace) === false, path: workspace.root }
|
|
481
|
+
});
|
|
482
|
+
} catch (err) {
|
|
483
|
+
return c.json(
|
|
484
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
485
|
+
500
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
app.get("/wallet/status", (c) => {
|
|
490
|
+
const exists = walletExists();
|
|
491
|
+
const address = exists ? getWalletAddress() : void 0;
|
|
492
|
+
return c.json({ success: true, data: { exists, address } });
|
|
493
|
+
});
|
|
494
|
+
app.post("/wallet/generate", async (c) => {
|
|
495
|
+
try {
|
|
496
|
+
const wallet = await generateWallet();
|
|
497
|
+
saveWallet(wallet);
|
|
498
|
+
log2.info("New TON wallet generated via setup UI");
|
|
499
|
+
return c.json({
|
|
500
|
+
success: true,
|
|
501
|
+
data: { address: wallet.address, mnemonic: wallet.mnemonic }
|
|
502
|
+
});
|
|
503
|
+
} catch (err) {
|
|
504
|
+
return c.json(
|
|
505
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
506
|
+
500
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
app.post("/wallet/import", async (c) => {
|
|
511
|
+
try {
|
|
512
|
+
const body = await c.req.json();
|
|
513
|
+
const words = body.mnemonic.trim().split(/\s+/);
|
|
514
|
+
if (words.length !== 24) {
|
|
515
|
+
return c.json({ success: false, error: `Expected 24 words, got ${words.length}` }, 400);
|
|
516
|
+
}
|
|
517
|
+
const wallet = await importWallet(words);
|
|
518
|
+
saveWallet(wallet);
|
|
519
|
+
log2.info("TON wallet imported via setup UI");
|
|
520
|
+
return c.json({ success: true, data: { address: wallet.address } });
|
|
521
|
+
} catch (err) {
|
|
522
|
+
return c.json(
|
|
523
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
524
|
+
400
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
app.post("/telegram/send-code", async (c) => {
|
|
529
|
+
try {
|
|
530
|
+
const body = await c.req.json();
|
|
531
|
+
if (!body.apiId || !body.apiHash || !body.phone) {
|
|
532
|
+
return c.json({ success: false, error: "Missing apiId, apiHash, or phone" }, 400);
|
|
533
|
+
}
|
|
534
|
+
const result = await authManager.sendCode(body.apiId, body.apiHash, body.phone);
|
|
535
|
+
return c.json({ success: true, data: result });
|
|
536
|
+
} catch (err) {
|
|
537
|
+
const error = err;
|
|
538
|
+
if (error.seconds) {
|
|
539
|
+
return c.json(
|
|
540
|
+
{
|
|
541
|
+
success: false,
|
|
542
|
+
error: `Rate limited. Please wait ${error.seconds} seconds.`
|
|
543
|
+
},
|
|
544
|
+
429
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
return c.json(
|
|
548
|
+
{ success: false, error: error.errorMessage || error.message || String(err) },
|
|
549
|
+
500
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
app.post("/telegram/verify-code", async (c) => {
|
|
554
|
+
try {
|
|
555
|
+
const body = await c.req.json();
|
|
556
|
+
if (!body.authSessionId || !body.code) {
|
|
557
|
+
return c.json({ success: false, error: "Missing authSessionId or code" }, 400);
|
|
558
|
+
}
|
|
559
|
+
const result = await authManager.verifyCode(body.authSessionId, body.code);
|
|
560
|
+
return c.json({ success: true, data: result });
|
|
561
|
+
} catch (err) {
|
|
562
|
+
const error = err;
|
|
563
|
+
if (error.seconds) {
|
|
564
|
+
return c.json(
|
|
565
|
+
{
|
|
566
|
+
success: false,
|
|
567
|
+
error: `Rate limited. Please wait ${error.seconds} seconds.`
|
|
568
|
+
},
|
|
569
|
+
429
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
return c.json(
|
|
573
|
+
{ success: false, error: error.errorMessage || error.message || String(err) },
|
|
574
|
+
500
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
app.post("/telegram/verify-password", async (c) => {
|
|
579
|
+
try {
|
|
580
|
+
const body = await c.req.json();
|
|
581
|
+
if (!body.authSessionId || !body.password) {
|
|
582
|
+
return c.json({ success: false, error: "Missing authSessionId or password" }, 400);
|
|
583
|
+
}
|
|
584
|
+
const result = await authManager.verifyPassword(body.authSessionId, body.password);
|
|
585
|
+
return c.json({ success: true, data: result });
|
|
586
|
+
} catch (err) {
|
|
587
|
+
const error = err;
|
|
588
|
+
if (error.seconds) {
|
|
589
|
+
return c.json(
|
|
590
|
+
{
|
|
591
|
+
success: false,
|
|
592
|
+
error: `Rate limited. Please wait ${error.seconds} seconds.`
|
|
593
|
+
},
|
|
594
|
+
429
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
return c.json(
|
|
598
|
+
{ success: false, error: error.errorMessage || error.message || String(err) },
|
|
599
|
+
500
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
app.post("/telegram/resend-code", async (c) => {
|
|
604
|
+
try {
|
|
605
|
+
const body = await c.req.json();
|
|
606
|
+
if (!body.authSessionId) {
|
|
607
|
+
return c.json({ success: false, error: "Missing authSessionId" }, 400);
|
|
608
|
+
}
|
|
609
|
+
const result = await authManager.resendCode(body.authSessionId);
|
|
610
|
+
if (!result) {
|
|
611
|
+
return c.json({ success: false, error: "Session expired or invalid" }, 400);
|
|
612
|
+
}
|
|
613
|
+
return c.json({ success: true, data: result });
|
|
614
|
+
} catch (err) {
|
|
615
|
+
const error = err;
|
|
616
|
+
if (error.seconds) {
|
|
617
|
+
return c.json(
|
|
618
|
+
{
|
|
619
|
+
success: false,
|
|
620
|
+
error: `Rate limited. Please wait ${error.seconds} seconds.`
|
|
621
|
+
},
|
|
622
|
+
429
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
return c.json(
|
|
626
|
+
{ success: false, error: error.errorMessage || error.message || String(err) },
|
|
627
|
+
500
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
app.delete("/telegram/session", async (c) => {
|
|
632
|
+
try {
|
|
633
|
+
const body = await c.req.json().catch(() => ({ authSessionId: "" }));
|
|
634
|
+
await authManager.cancelSession(body.authSessionId);
|
|
635
|
+
return c.json({ success: true });
|
|
636
|
+
} catch (err) {
|
|
637
|
+
return c.json(
|
|
638
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
639
|
+
500
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
app.post("/config/save", async (c) => {
|
|
644
|
+
try {
|
|
645
|
+
const input = await c.req.json();
|
|
646
|
+
const workspace = await ensureWorkspace({ ensureTemplates: true });
|
|
647
|
+
const providerMeta = getProviderMetadata(input.agent.provider);
|
|
648
|
+
const config = {
|
|
649
|
+
meta: {
|
|
650
|
+
version: "1.0.0",
|
|
651
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
652
|
+
onboard_command: "teleton setup --ui"
|
|
653
|
+
},
|
|
654
|
+
agent: {
|
|
655
|
+
provider: input.agent.provider,
|
|
656
|
+
api_key: input.agent.api_key ?? "",
|
|
657
|
+
...input.agent.base_url ? { base_url: input.agent.base_url } : {},
|
|
658
|
+
model: input.agent.model || providerMeta.defaultModel,
|
|
659
|
+
max_tokens: 4096,
|
|
660
|
+
temperature: 0.7,
|
|
661
|
+
system_prompt: null,
|
|
662
|
+
max_agentic_iterations: input.agent.max_agentic_iterations ?? 5,
|
|
663
|
+
session_reset_policy: {
|
|
664
|
+
daily_reset_enabled: true,
|
|
665
|
+
daily_reset_hour: 4,
|
|
666
|
+
idle_expiry_enabled: true,
|
|
667
|
+
idle_expiry_minutes: 1440
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
telegram: {
|
|
671
|
+
api_id: input.telegram.api_id,
|
|
672
|
+
api_hash: input.telegram.api_hash,
|
|
673
|
+
phone: input.telegram.phone,
|
|
674
|
+
session_name: "teleton_session",
|
|
675
|
+
session_path: workspace.sessionPath,
|
|
676
|
+
dm_policy: input.telegram.dm_policy ?? "open",
|
|
677
|
+
allow_from: [],
|
|
678
|
+
group_policy: input.telegram.group_policy ?? "open",
|
|
679
|
+
group_allow_from: [],
|
|
680
|
+
require_mention: input.telegram.require_mention ?? true,
|
|
681
|
+
max_message_length: TELEGRAM_MAX_MESSAGE_LENGTH,
|
|
682
|
+
typing_simulation: true,
|
|
683
|
+
rate_limit_messages_per_second: 1,
|
|
684
|
+
rate_limit_groups_per_minute: 20,
|
|
685
|
+
admin_ids: [input.telegram.owner_id],
|
|
686
|
+
owner_id: input.telegram.owner_id,
|
|
687
|
+
agent_channel: null,
|
|
688
|
+
debounce_ms: 1500,
|
|
689
|
+
bot_token: input.telegram.bot_token,
|
|
690
|
+
bot_username: input.telegram.bot_username
|
|
691
|
+
},
|
|
692
|
+
storage: {
|
|
693
|
+
sessions_file: `${workspace.root}/sessions.json`,
|
|
694
|
+
pairing_file: `${workspace.root}/pairing.json`,
|
|
695
|
+
memory_file: `${workspace.root}/memory.json`,
|
|
696
|
+
history_limit: 100
|
|
697
|
+
},
|
|
698
|
+
embedding: { provider: "local" },
|
|
699
|
+
deals: DealsConfigSchema.parse({
|
|
700
|
+
enabled: true,
|
|
701
|
+
...input.deals ?? {}
|
|
702
|
+
}),
|
|
703
|
+
webui: {
|
|
704
|
+
enabled: input.webui?.enabled ?? false,
|
|
705
|
+
port: 7777,
|
|
706
|
+
host: "127.0.0.1",
|
|
707
|
+
cors_origins: ["http://localhost:5173", "http://localhost:7777"],
|
|
708
|
+
log_requests: false
|
|
709
|
+
},
|
|
710
|
+
logging: { level: "info", pretty: true },
|
|
711
|
+
dev: { hot_reload: false },
|
|
712
|
+
tool_rag: {
|
|
713
|
+
enabled: true,
|
|
714
|
+
top_k: 25,
|
|
715
|
+
always_include: [
|
|
716
|
+
"telegram_send_message",
|
|
717
|
+
"telegram_reply_message",
|
|
718
|
+
"telegram_send_photo",
|
|
719
|
+
"telegram_send_document",
|
|
720
|
+
"journal_*",
|
|
721
|
+
"workspace_*",
|
|
722
|
+
"web_*"
|
|
723
|
+
],
|
|
724
|
+
skip_unlimited_providers: false
|
|
725
|
+
},
|
|
726
|
+
mcp: { servers: {} },
|
|
727
|
+
plugins: {},
|
|
728
|
+
...input.cocoon ? { cocoon: input.cocoon } : {},
|
|
729
|
+
...input.tonapi_key ? { tonapi_key: input.tonapi_key } : {},
|
|
730
|
+
...input.tavily_api_key ? { tavily_api_key: input.tavily_api_key } : {}
|
|
731
|
+
};
|
|
732
|
+
ConfigSchema.parse(config);
|
|
733
|
+
const configPath = workspace.configPath;
|
|
734
|
+
writeFileSync2(configPath, YAML.stringify(config), { encoding: "utf-8", mode: 384 });
|
|
735
|
+
log2.info(`Configuration saved: ${configPath}`);
|
|
736
|
+
return c.json({ success: true, data: { path: configPath } });
|
|
737
|
+
} catch (err) {
|
|
738
|
+
return c.json(
|
|
739
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
740
|
+
400
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
return app;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/webui/setup-server.ts
|
|
748
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
749
|
+
import { readFileSync as readYaml, writeFileSync as writeFileSync3 } from "fs";
|
|
750
|
+
import YAML2 from "yaml";
|
|
751
|
+
var log3 = createLogger("Setup");
|
|
752
|
+
function findWebDist() {
|
|
753
|
+
const candidates = [resolve("dist/web"), resolve("web")];
|
|
754
|
+
const __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
755
|
+
candidates.push(resolve(__dirname, "web"), resolve(__dirname, "../dist/web"));
|
|
756
|
+
for (const candidate of candidates) {
|
|
757
|
+
if (existsSync3(join3(candidate, "index.html"))) {
|
|
758
|
+
return candidate;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return null;
|
|
762
|
+
}
|
|
763
|
+
function autoOpenBrowser(url) {
|
|
764
|
+
const os = platform();
|
|
765
|
+
let cmd;
|
|
766
|
+
if (os === "darwin") {
|
|
767
|
+
cmd = `open "${url}"`;
|
|
768
|
+
} else if (os === "win32") {
|
|
769
|
+
cmd = `start "${url}"`;
|
|
770
|
+
} else {
|
|
771
|
+
cmd = `xdg-open "${url}"`;
|
|
772
|
+
}
|
|
773
|
+
exec(cmd, (err) => {
|
|
774
|
+
if (err) {
|
|
775
|
+
log3.info(`Open this URL in your browser: ${url}`);
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
var SetupServer = class {
|
|
780
|
+
constructor(port = 7777) {
|
|
781
|
+
this.port = port;
|
|
782
|
+
this.app = new Hono2();
|
|
783
|
+
this.launchPromise = new Promise((resolve2) => {
|
|
784
|
+
this.launchResolve = resolve2;
|
|
785
|
+
});
|
|
786
|
+
this.setupMiddleware();
|
|
787
|
+
this.setupRoutes();
|
|
788
|
+
this.setupStaticServing();
|
|
789
|
+
}
|
|
790
|
+
app;
|
|
791
|
+
server = null;
|
|
792
|
+
launchResolve = null;
|
|
793
|
+
launchPromise;
|
|
794
|
+
/** Returns a promise that resolves with the auth token when the user clicks "Start Agent" */
|
|
795
|
+
waitForLaunch() {
|
|
796
|
+
return this.launchPromise;
|
|
797
|
+
}
|
|
798
|
+
setupMiddleware() {
|
|
799
|
+
this.app.use(
|
|
800
|
+
"*",
|
|
801
|
+
cors({
|
|
802
|
+
origin: [
|
|
803
|
+
"http://localhost:5173",
|
|
804
|
+
`http://localhost:${this.port}`,
|
|
805
|
+
"http://127.0.0.1:5173",
|
|
806
|
+
`http://127.0.0.1:${this.port}`
|
|
807
|
+
],
|
|
808
|
+
credentials: true,
|
|
809
|
+
allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
|
|
810
|
+
allowHeaders: ["Content-Type"],
|
|
811
|
+
maxAge: 3600
|
|
812
|
+
})
|
|
813
|
+
);
|
|
814
|
+
this.app.use(
|
|
815
|
+
"*",
|
|
816
|
+
bodyLimit({
|
|
817
|
+
maxSize: 2 * 1024 * 1024,
|
|
818
|
+
onError: (c) => c.json({ success: false, error: "Request body too large (max 2MB)" }, 413)
|
|
819
|
+
})
|
|
820
|
+
);
|
|
821
|
+
this.app.use("*", async (c, next) => {
|
|
822
|
+
await next();
|
|
823
|
+
c.res.headers.set("X-Content-Type-Options", "nosniff");
|
|
824
|
+
c.res.headers.set("X-Frame-Options", "DENY");
|
|
825
|
+
c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
setupRoutes() {
|
|
829
|
+
this.app.get("/health", (c) => c.json({ status: "ok" }));
|
|
830
|
+
this.app.route("/api/setup", createSetupRoutes());
|
|
831
|
+
this.app.get(
|
|
832
|
+
"/auth/check",
|
|
833
|
+
(c) => c.json({ success: true, data: { authenticated: false, setup: true } })
|
|
834
|
+
);
|
|
835
|
+
this.app.post("/api/setup/launch", async (c) => {
|
|
836
|
+
try {
|
|
837
|
+
const token = randomBytes2(32).toString("hex");
|
|
838
|
+
const configPath = join3(TELETON_ROOT, "config.yaml");
|
|
839
|
+
const raw = readYaml(configPath, "utf-8");
|
|
840
|
+
const config = YAML2.parse(raw);
|
|
841
|
+
config.webui = { ...config.webui || {}, enabled: true, auth_token: token };
|
|
842
|
+
writeFileSync3(configPath, YAML2.stringify(config), { encoding: "utf-8", mode: 384 });
|
|
843
|
+
log3.info("Launch requested \u2014 auth token generated");
|
|
844
|
+
const resolve2 = this.launchResolve;
|
|
845
|
+
this.launchResolve = null;
|
|
846
|
+
if (resolve2) {
|
|
847
|
+
setTimeout(() => resolve2(token), 500);
|
|
848
|
+
}
|
|
849
|
+
return c.json({ success: true, data: { token } });
|
|
850
|
+
} catch (err) {
|
|
851
|
+
return c.json(
|
|
852
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
853
|
+
500
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
this.app.onError((err, c) => {
|
|
858
|
+
log3.error({ err }, "Setup server error");
|
|
859
|
+
return c.json({ success: false, error: err.message || "Internal server error" }, 500);
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
setupStaticServing() {
|
|
863
|
+
const webDist = findWebDist();
|
|
864
|
+
if (!webDist) return;
|
|
865
|
+
const indexHtml = readFileSync2(join3(webDist, "index.html"), "utf-8");
|
|
866
|
+
const mimeTypes = {
|
|
867
|
+
js: "application/javascript",
|
|
868
|
+
css: "text/css",
|
|
869
|
+
svg: "image/svg+xml",
|
|
870
|
+
png: "image/png",
|
|
871
|
+
jpg: "image/jpeg",
|
|
872
|
+
jpeg: "image/jpeg",
|
|
873
|
+
ico: "image/x-icon",
|
|
874
|
+
json: "application/json",
|
|
875
|
+
woff2: "font/woff2",
|
|
876
|
+
woff: "font/woff"
|
|
877
|
+
};
|
|
878
|
+
this.app.get("*", (c) => {
|
|
879
|
+
const filePath = resolve(join3(webDist, c.req.path));
|
|
880
|
+
const rel = relative(webDist, filePath);
|
|
881
|
+
if (rel.startsWith("..") || resolve(filePath) !== filePath) {
|
|
882
|
+
return c.html(indexHtml);
|
|
883
|
+
}
|
|
884
|
+
try {
|
|
885
|
+
const content = readFileSync2(filePath);
|
|
886
|
+
const ext = filePath.split(".").pop() || "";
|
|
887
|
+
if (mimeTypes[ext]) {
|
|
888
|
+
const immutable = c.req.path.startsWith("/assets/");
|
|
889
|
+
return c.body(content, 200, {
|
|
890
|
+
"Content-Type": mimeTypes[ext],
|
|
891
|
+
"Cache-Control": immutable ? "public, max-age=31536000, immutable" : "public, max-age=3600"
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
} catch {
|
|
895
|
+
}
|
|
896
|
+
return c.html(indexHtml);
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
async start() {
|
|
900
|
+
return new Promise((resolve2, reject) => {
|
|
901
|
+
try {
|
|
902
|
+
this.server = serve(
|
|
903
|
+
{
|
|
904
|
+
fetch: this.app.fetch,
|
|
905
|
+
hostname: "127.0.0.1",
|
|
906
|
+
port: this.port
|
|
907
|
+
},
|
|
908
|
+
() => {
|
|
909
|
+
const url = `http://localhost:${this.port}/setup`;
|
|
910
|
+
log3.info(`Setup wizard: ${url}`);
|
|
911
|
+
autoOpenBrowser(url);
|
|
912
|
+
resolve2();
|
|
913
|
+
}
|
|
914
|
+
);
|
|
915
|
+
} catch (error) {
|
|
916
|
+
reject(error);
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
async stop() {
|
|
921
|
+
if (this.server) {
|
|
922
|
+
return new Promise((resolve2) => {
|
|
923
|
+
this.server.closeAllConnections();
|
|
924
|
+
this.server.close(() => {
|
|
925
|
+
log3.info("Setup server stopped");
|
|
926
|
+
resolve2();
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
export {
|
|
933
|
+
SetupServer
|
|
934
|
+
};
|