@waifucave/discord-waifus 1.5.154
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/LICENSE +21 -0
- package/README.md +230 -0
- package/THIRD_PARTY_NOTICES.md +26 -0
- package/assets/ocr/eng.traineddata +0 -0
- package/bin/waifus.mjs +36 -0
- package/dist/api/errors.d.ts +9 -0
- package/dist/api/errors.js +23 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/server.d.ts +19 -0
- package/dist/api/server.js +1290 -0
- package/dist/api/server.js.map +1 -0
- package/dist/backend/logger.d.ts +20 -0
- package/dist/backend/logger.js +65 -0
- package/dist/backend/logger.js.map +1 -0
- package/dist/backend/migrations.d.ts +4 -0
- package/dist/backend/migrations.js +521 -0
- package/dist/backend/migrations.js.map +1 -0
- package/dist/backend/redaction.d.ts +1 -0
- package/dist/backend/redaction.js +22 -0
- package/dist/backend/redaction.js.map +1 -0
- package/dist/backend/runtime.d.ts +30 -0
- package/dist/backend/runtime.js +49 -0
- package/dist/backend/runtime.js.map +1 -0
- package/dist/backend/server.d.ts +18 -0
- package/dist/backend/server.js +581 -0
- package/dist/backend/server.js.map +1 -0
- package/dist/cli/commands.d.ts +35 -0
- package/dist/cli/commands.js +510 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +12 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/parser.d.ts +10 -0
- package/dist/cli/parser.js +64 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/config/appConfig.d.ts +3 -0
- package/dist/config/appConfig.js +27 -0
- package/dist/config/appConfig.js.map +1 -0
- package/dist/config/layout.d.ts +13 -0
- package/dist/config/layout.js +173 -0
- package/dist/config/layout.js.map +1 -0
- package/dist/config/paths.d.ts +5 -0
- package/dist/config/paths.js +20 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/prebuiltWaifus.d.ts +3 -0
- package/dist/config/prebuiltWaifus.js +106 -0
- package/dist/config/prebuiltWaifus.js.map +1 -0
- package/dist/discord/client.d.ts +394 -0
- package/dist/discord/client.js +1196 -0
- package/dist/discord/client.js.map +1 -0
- package/dist/discord/contextBuilder.d.ts +15 -0
- package/dist/discord/contextBuilder.js +18 -0
- package/dist/discord/contextBuilder.js.map +1 -0
- package/dist/discord/intents.d.ts +5 -0
- package/dist/discord/intents.js +21 -0
- package/dist/discord/intents.js.map +1 -0
- package/dist/discord/memberCache.d.ts +12 -0
- package/dist/discord/memberCache.js +55 -0
- package/dist/discord/memberCache.js.map +1 -0
- package/dist/discord/normalization.d.ts +34 -0
- package/dist/discord/normalization.js +330 -0
- package/dist/discord/normalization.js.map +1 -0
- package/dist/discord/rateLimit.d.ts +9 -0
- package/dist/discord/rateLimit.js +11 -0
- package/dist/discord/rateLimit.js.map +1 -0
- package/dist/orchestration/context.d.ts +85 -0
- package/dist/orchestration/context.js +200 -0
- package/dist/orchestration/context.js.map +1 -0
- package/dist/orchestration/decisions.d.ts +52 -0
- package/dist/orchestration/decisions.js +61 -0
- package/dist/orchestration/decisions.js.map +1 -0
- package/dist/orchestration/messageSplit.d.ts +6 -0
- package/dist/orchestration/messageSplit.js +118 -0
- package/dist/orchestration/messageSplit.js.map +1 -0
- package/dist/orchestration/ocr.d.ts +43 -0
- package/dist/orchestration/ocr.js +504 -0
- package/dist/orchestration/ocr.js.map +1 -0
- package/dist/orchestration/ocrPackages.d.ts +24 -0
- package/dist/orchestration/ocrPackages.js +85 -0
- package/dist/orchestration/ocrPackages.js.map +1 -0
- package/dist/orchestration/promptBlocks.d.ts +28 -0
- package/dist/orchestration/promptBlocks.js +232 -0
- package/dist/orchestration/promptBlocks.js.map +1 -0
- package/dist/orchestration/replyQuote.d.ts +7 -0
- package/dist/orchestration/replyQuote.js +198 -0
- package/dist/orchestration/replyQuote.js.map +1 -0
- package/dist/orchestration/reviewer.d.ts +5 -0
- package/dist/orchestration/reviewer.js +5 -0
- package/dist/orchestration/reviewer.js.map +1 -0
- package/dist/orchestration/runtime.d.ts +152 -0
- package/dist/orchestration/runtime.js +3535 -0
- package/dist/orchestration/runtime.js.map +1 -0
- package/dist/orchestration/session.d.ts +30 -0
- package/dist/orchestration/session.js +41 -0
- package/dist/orchestration/session.js.map +1 -0
- package/dist/orchestration/stageManager.d.ts +42 -0
- package/dist/orchestration/stageManager.js +50 -0
- package/dist/orchestration/stageManager.js.map +1 -0
- package/dist/providers/catalog.d.ts +6 -0
- package/dist/providers/catalog.js +212 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/pipelines.d.ts +13 -0
- package/dist/providers/pipelines.js +2388 -0
- package/dist/providers/pipelines.js.map +1 -0
- package/dist/providers/types.d.ts +91 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/shared/queryLog.d.ts +39 -0
- package/dist/shared/queryLog.js +80 -0
- package/dist/shared/queryLog.js.map +1 -0
- package/dist/shared/schemas/common.d.ts +21 -0
- package/dist/shared/schemas/common.js +27 -0
- package/dist/shared/schemas/common.js.map +1 -0
- package/dist/shared/schemas/config.d.ts +57 -0
- package/dist/shared/schemas/config.js +49 -0
- package/dist/shared/schemas/config.js.map +1 -0
- package/dist/shared/schemas/domain.d.ts +825 -0
- package/dist/shared/schemas/domain.js +444 -0
- package/dist/shared/schemas/domain.js.map +1 -0
- package/dist/storage/atomic.d.ts +6 -0
- package/dist/storage/atomic.js +60 -0
- package/dist/storage/atomic.js.map +1 -0
- package/dist/storage/errors.d.ts +12 -0
- package/dist/storage/errors.js +23 -0
- package/dist/storage/errors.js.map +1 -0
- package/dist/storage/locks.d.ts +9 -0
- package/dist/storage/locks.js +42 -0
- package/dist/storage/locks.js.map +1 -0
- package/dist/storage/storageService.d.ts +25 -0
- package/dist/storage/storageService.js +66 -0
- package/dist/storage/storageService.js.map +1 -0
- package/dist-frontend/assets/index-B2bB3_2r.js +39 -0
- package/dist-frontend/assets/index-B2bB3_2r.js.map +1 -0
- package/dist-frontend/assets/index-Dj1L8Px-.css +1 -0
- package/dist-frontend/index.html +14 -0
- package/docs/api.md +162 -0
- package/docs/old-orchestrator-prompt.md +123 -0
- package/package.json +81 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DiscordGatewayFacade, DiscordJsGatewayOptions } from "../discord/client.js";
|
|
2
|
+
import { Logger } from "./logger.js";
|
|
3
|
+
import { RuntimeState } from "./runtime.js";
|
|
4
|
+
export type StartBackendOptions = {
|
|
5
|
+
dataRoot: string;
|
|
6
|
+
port?: number;
|
|
7
|
+
host?: string;
|
|
8
|
+
mode?: "start" | "dev" | "test";
|
|
9
|
+
logger?: Logger;
|
|
10
|
+
createDiscordGateway?: (options: DiscordJsGatewayOptions) => DiscordGatewayFacade;
|
|
11
|
+
discordRetryDelaysMs?: number[];
|
|
12
|
+
};
|
|
13
|
+
export type RunningBackend = {
|
|
14
|
+
url: string;
|
|
15
|
+
runtime: RuntimeState;
|
|
16
|
+
close: () => Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export declare function startBackend(options: StartBackendOptions): Promise<RunningBackend>;
|
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
import { readdir, rm } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { loadAppConfig } from "../config/appConfig.js";
|
|
4
|
+
import { appDataPath } from "../config/paths.js";
|
|
5
|
+
import { readPackageVersion } from "../config/layout.js";
|
|
6
|
+
import { atomicWriteJson } from "../storage/atomic.js";
|
|
7
|
+
import { StorageService } from "../storage/storageService.js";
|
|
8
|
+
import { DiscordJsGateway } from "../discord/client.js";
|
|
9
|
+
import { mergeConfiguredBotsIntoMembers } from "../discord/memberCache.js";
|
|
10
|
+
import { RuntimeOrchestrator } from "../orchestration/runtime.js";
|
|
11
|
+
import { ImageOcrService } from "../orchestration/ocr.js";
|
|
12
|
+
import { DiscordBotsFileSchema, GuildEmojisFileSchema, GuildMembersFileSchema, GuildRolesFileSchema, createEmptyRevisionedFile } from "../shared/schemas/domain.js";
|
|
13
|
+
import { createApiServer } from "../api/server.js";
|
|
14
|
+
import { createLogger } from "./logger.js";
|
|
15
|
+
import { runMigrations } from "./migrations.js";
|
|
16
|
+
import { createRuntimeState } from "./runtime.js";
|
|
17
|
+
const DEFAULT_DISCORD_RETRY_DELAYS_MS = [5_000, 15_000, 30_000, 60_000, 120_000];
|
|
18
|
+
export async function startBackend(options) {
|
|
19
|
+
await runMigrations(options.dataRoot);
|
|
20
|
+
const config = await loadAppConfig(options.dataRoot);
|
|
21
|
+
const packageVersion = await readPackageVersion();
|
|
22
|
+
const port = options.port ?? config.http.port;
|
|
23
|
+
const host = options.host ?? config.http.host;
|
|
24
|
+
const logger = options.logger ?? createLogger({ dataRoot: options.dataRoot });
|
|
25
|
+
const storage = new StorageService(options.dataRoot, {
|
|
26
|
+
onLockWait: (resourceKey, waitMs) => logger.warn("Storage lock wait exceeded threshold", { resourceKey, waitMs })
|
|
27
|
+
});
|
|
28
|
+
const runtime = createRuntimeState({
|
|
29
|
+
pid: process.pid,
|
|
30
|
+
startedAt: new Date().toISOString(),
|
|
31
|
+
packageVersion,
|
|
32
|
+
port,
|
|
33
|
+
dataRoot: options.dataRoot,
|
|
34
|
+
mode: options.mode ?? "start",
|
|
35
|
+
paused: config.runtime.paused,
|
|
36
|
+
discord: offlineDiscordStatus(),
|
|
37
|
+
queues: {
|
|
38
|
+
active: 0,
|
|
39
|
+
configuredGuilds: await countConfiguredGuilds(storage)
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const createDiscordGateway = options.createDiscordGateway ??
|
|
43
|
+
((gatewayOptions) => new DiscordJsGateway(gatewayOptions));
|
|
44
|
+
const discordRetryDelaysMs = options.discordRetryDelaysMs?.length
|
|
45
|
+
? options.discordRetryDelaysMs
|
|
46
|
+
: [...DEFAULT_DISCORD_RETRY_DELAYS_MS];
|
|
47
|
+
let gateway;
|
|
48
|
+
let runtimeOrchestrator;
|
|
49
|
+
let discordRetryTimer;
|
|
50
|
+
let discordRetryAttempt = 0;
|
|
51
|
+
let discordRecoveryInProgress = false;
|
|
52
|
+
let pendingLiveDiscordErrorMessage;
|
|
53
|
+
let closing = false;
|
|
54
|
+
let enqueueReloadRuntime;
|
|
55
|
+
const cleanupOcr = async (currentConfig = config) => {
|
|
56
|
+
const ocr = new ImageOcrService({
|
|
57
|
+
dataRoot: options.dataRoot,
|
|
58
|
+
config: currentConfig.ocr,
|
|
59
|
+
logger
|
|
60
|
+
});
|
|
61
|
+
await ocr.cleanupExpired().catch((error) => {
|
|
62
|
+
logger.warn("OCR cleanup failed", { message: error instanceof Error ? error.message : String(error) });
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const makeRuntimeOrchestrator = (nextGateway, currentConfig = config) => {
|
|
66
|
+
const ocr = new ImageOcrService({
|
|
67
|
+
dataRoot: options.dataRoot,
|
|
68
|
+
config: currentConfig.ocr,
|
|
69
|
+
logger
|
|
70
|
+
});
|
|
71
|
+
return new RuntimeOrchestrator({
|
|
72
|
+
storage,
|
|
73
|
+
discord: nextGateway,
|
|
74
|
+
logger,
|
|
75
|
+
ocr,
|
|
76
|
+
isPaused: () => runtime.paused,
|
|
77
|
+
onActiveRunsChange: (activeRuns) => {
|
|
78
|
+
runtime.queues.active = activeRuns;
|
|
79
|
+
runtime.updatedAt = new Date().toISOString();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
const clearDiscordRetry = () => {
|
|
84
|
+
if (discordRetryTimer) {
|
|
85
|
+
clearTimeout(discordRetryTimer);
|
|
86
|
+
discordRetryTimer = undefined;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const nextDiscordRetryDelayMs = (attempt) => discordRetryDelaysMs[Math.min(attempt - 1, discordRetryDelaysMs.length - 1)] ??
|
|
90
|
+
DEFAULT_DISCORD_RETRY_DELAYS_MS[0];
|
|
91
|
+
const scheduleDiscordRetry = async (message, retryOptions = {}) => {
|
|
92
|
+
if (closing)
|
|
93
|
+
return;
|
|
94
|
+
const failureLabel = retryOptions.failureLabel ?? "Discord auto-connect failed";
|
|
95
|
+
if (retryOptions.preserveExistingTimer && discordRetryTimer) {
|
|
96
|
+
const lastErrorAt = new Date().toISOString();
|
|
97
|
+
const attempt = Math.max(discordRetryAttempt, 1);
|
|
98
|
+
const nextRetryAt = runtime.discord.nextRetryAt ??
|
|
99
|
+
new Date(Date.now() + nextDiscordRetryDelayMs(attempt)).toISOString();
|
|
100
|
+
runtime.discord = {
|
|
101
|
+
...withoutDiscordConnecting(runtime.discord),
|
|
102
|
+
connected: false,
|
|
103
|
+
orchestratorConnected: false,
|
|
104
|
+
waifuBotCount: 0,
|
|
105
|
+
retrying: true,
|
|
106
|
+
retryAttempt: attempt,
|
|
107
|
+
nextRetryAt,
|
|
108
|
+
lastError: message,
|
|
109
|
+
lastErrorAt,
|
|
110
|
+
warnings: [
|
|
111
|
+
`${failureLabel}: ${message}`,
|
|
112
|
+
`Discord auto-connect will retry automatically at ${nextRetryAt}.`
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
runtime.updatedAt = new Date().toISOString();
|
|
116
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
117
|
+
logger.warn("Discord auto-connect retry already pending; updated latest error", {
|
|
118
|
+
attempt: runtime.discord.retryAttempt,
|
|
119
|
+
nextRetryAt,
|
|
120
|
+
message,
|
|
121
|
+
reason: retryOptions.logReason
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
clearDiscordRetry();
|
|
126
|
+
discordRetryAttempt += 1;
|
|
127
|
+
const lastErrorAt = new Date().toISOString();
|
|
128
|
+
const delayMs = nextDiscordRetryDelayMs(discordRetryAttempt);
|
|
129
|
+
const nextRetryAt = new Date(Date.now() + delayMs).toISOString();
|
|
130
|
+
runtime.discord = {
|
|
131
|
+
...withoutDiscordConnecting(runtime.discord),
|
|
132
|
+
connected: false,
|
|
133
|
+
orchestratorConnected: false,
|
|
134
|
+
waifuBotCount: 0,
|
|
135
|
+
retrying: true,
|
|
136
|
+
retryAttempt: discordRetryAttempt,
|
|
137
|
+
nextRetryAt,
|
|
138
|
+
lastError: message,
|
|
139
|
+
lastErrorAt,
|
|
140
|
+
warnings: [
|
|
141
|
+
`${failureLabel}: ${message}`,
|
|
142
|
+
`Discord auto-connect will retry automatically at ${nextRetryAt}.`
|
|
143
|
+
]
|
|
144
|
+
};
|
|
145
|
+
runtime.updatedAt = new Date().toISOString();
|
|
146
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
147
|
+
logger.warn("Discord auto-connect retry scheduled", {
|
|
148
|
+
attempt: discordRetryAttempt,
|
|
149
|
+
nextRetryAt,
|
|
150
|
+
delayMs,
|
|
151
|
+
message,
|
|
152
|
+
reason: retryOptions.logReason
|
|
153
|
+
});
|
|
154
|
+
discordRetryTimer = setTimeout(() => {
|
|
155
|
+
discordRetryTimer = undefined;
|
|
156
|
+
void enqueueReloadRuntime("discord-auto-retry", { scheduledRetry: true }).catch((error) => {
|
|
157
|
+
const retryMessage = error instanceof Error ? error.message : String(error);
|
|
158
|
+
logger.error("Discord auto-connect retry failed outside gateway connection", { message: retryMessage });
|
|
159
|
+
});
|
|
160
|
+
}, delayMs);
|
|
161
|
+
};
|
|
162
|
+
const handleDiscordRuntimeIssue = async (issue) => {
|
|
163
|
+
if (closing)
|
|
164
|
+
return;
|
|
165
|
+
const message = issue.message || "Discord runtime issue.";
|
|
166
|
+
if (!isRetryableDiscordRuntimeIssue(issue)) {
|
|
167
|
+
logger.warn("Discord runtime issue did not trigger reconnect", discordRuntimeIssueLogContext(issue));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
pendingLiveDiscordErrorMessage = message;
|
|
171
|
+
if (discordRetryTimer) {
|
|
172
|
+
await scheduleDiscordRetry(message, {
|
|
173
|
+
preserveExistingTimer: true,
|
|
174
|
+
failureLabel: "Discord connection lost",
|
|
175
|
+
logReason: issue.source
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (discordRecoveryInProgress) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
discordRecoveryInProgress = true;
|
|
183
|
+
try {
|
|
184
|
+
logger.warn("Discord runtime issue triggered reconnect", discordRuntimeIssueLogContext(issue));
|
|
185
|
+
await runtimeOrchestrator?.stop();
|
|
186
|
+
await gateway?.disconnect();
|
|
187
|
+
runtimeOrchestrator = undefined;
|
|
188
|
+
gateway = undefined;
|
|
189
|
+
runtime.queues.active = 0;
|
|
190
|
+
await scheduleDiscordRetry(pendingLiveDiscordErrorMessage ?? message, {
|
|
191
|
+
preserveExistingTimer: true,
|
|
192
|
+
failureLabel: "Discord connection lost",
|
|
193
|
+
logReason: issue.source
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
discordRecoveryInProgress = false;
|
|
198
|
+
pendingLiveDiscordErrorMessage = undefined;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const reloadRuntime = async (reason, retryOptions = {}) => {
|
|
202
|
+
if (closing)
|
|
203
|
+
return;
|
|
204
|
+
if (!retryOptions.scheduledRetry) {
|
|
205
|
+
clearDiscordRetry();
|
|
206
|
+
discordRetryAttempt = 0;
|
|
207
|
+
}
|
|
208
|
+
logger.info("Reloading runtime", { reason });
|
|
209
|
+
await runtimeOrchestrator?.stop();
|
|
210
|
+
await gateway?.disconnect();
|
|
211
|
+
runtimeOrchestrator = undefined;
|
|
212
|
+
gateway = undefined;
|
|
213
|
+
runtime.queues.active = 0;
|
|
214
|
+
const currentConfig = await loadAppConfig(options.dataRoot);
|
|
215
|
+
await cleanupOcr(currentConfig);
|
|
216
|
+
if (closing)
|
|
217
|
+
return;
|
|
218
|
+
runtime.paused = currentConfig.runtime.paused;
|
|
219
|
+
runtime.queues.configuredGuilds = await countConfiguredGuilds(storage);
|
|
220
|
+
if (currentConfig.runtime.autoConnectDiscord) {
|
|
221
|
+
runtime.discord = connectingDiscordStatus();
|
|
222
|
+
runtime.updatedAt = new Date().toISOString();
|
|
223
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
224
|
+
}
|
|
225
|
+
const connected = await maybeConnectDiscord(storage, currentConfig.runtime.autoConnectDiscord, logger, createDiscordGateway, handleDiscordRuntimeIssue);
|
|
226
|
+
if (closing) {
|
|
227
|
+
await connected.gateway?.disconnect();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
runtime.discord = connected.status;
|
|
231
|
+
gateway = connected.gateway;
|
|
232
|
+
if (gateway) {
|
|
233
|
+
clearDiscordRetry();
|
|
234
|
+
discordRetryAttempt = 0;
|
|
235
|
+
runtimeOrchestrator = makeRuntimeOrchestrator(gateway, currentConfig);
|
|
236
|
+
await runtimeOrchestrator.start();
|
|
237
|
+
}
|
|
238
|
+
else if (connected.retryableFailure) {
|
|
239
|
+
await scheduleDiscordRetry(connected.retryableFailure.message);
|
|
240
|
+
}
|
|
241
|
+
if (closing) {
|
|
242
|
+
await runtimeOrchestrator?.stop();
|
|
243
|
+
await gateway?.disconnect();
|
|
244
|
+
runtimeOrchestrator = undefined;
|
|
245
|
+
gateway = undefined;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
runtime.queues.configuredGuilds = await countConfiguredGuilds(storage);
|
|
249
|
+
runtime.updatedAt = new Date().toISOString();
|
|
250
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
251
|
+
};
|
|
252
|
+
let reloadQueue = Promise.resolve();
|
|
253
|
+
enqueueReloadRuntime = (reason, retryOptions = {}) => {
|
|
254
|
+
const run = () => reloadRuntime(reason, retryOptions);
|
|
255
|
+
const next = reloadQueue.then(run, run);
|
|
256
|
+
reloadQueue = next.catch(() => undefined);
|
|
257
|
+
return next;
|
|
258
|
+
};
|
|
259
|
+
runtime.queues.configuredGuilds = await countConfiguredGuilds(storage);
|
|
260
|
+
const app = await createApiServer({
|
|
261
|
+
dataRoot: options.dataRoot,
|
|
262
|
+
storage,
|
|
263
|
+
runtime,
|
|
264
|
+
runtimeControl: {
|
|
265
|
+
getOrchestrator: () => runtimeOrchestrator,
|
|
266
|
+
pause: async () => {
|
|
267
|
+
runtime.paused = true;
|
|
268
|
+
await runtimeOrchestrator?.pause();
|
|
269
|
+
runtime.updatedAt = new Date().toISOString();
|
|
270
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
271
|
+
},
|
|
272
|
+
resume: async () => {
|
|
273
|
+
runtime.paused = false;
|
|
274
|
+
runtime.updatedAt = new Date().toISOString();
|
|
275
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
276
|
+
},
|
|
277
|
+
reload: enqueueReloadRuntime
|
|
278
|
+
},
|
|
279
|
+
logger
|
|
280
|
+
});
|
|
281
|
+
await app.listen({ host, port });
|
|
282
|
+
await writeRuntimeFiles(options.dataRoot, runtime);
|
|
283
|
+
logger.info("Backend started", { url: `http://${host}:${port}`, dataRoot: options.dataRoot });
|
|
284
|
+
void enqueueReloadRuntime("startup").catch((error) => {
|
|
285
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
286
|
+
logger.error("Startup runtime reload failed", { message });
|
|
287
|
+
});
|
|
288
|
+
return {
|
|
289
|
+
url: `http://${host}:${port}`,
|
|
290
|
+
runtime,
|
|
291
|
+
close: async () => {
|
|
292
|
+
closing = true;
|
|
293
|
+
clearDiscordRetry();
|
|
294
|
+
const shutdownStartedAt = Date.now();
|
|
295
|
+
logger.info("Shutdown step start", { step: "orchestrator.stop" });
|
|
296
|
+
let stepStartedAt = Date.now();
|
|
297
|
+
await runtimeOrchestrator?.stop();
|
|
298
|
+
logger.info("Shutdown step done", { step: "orchestrator.stop", ms: Date.now() - stepStartedAt });
|
|
299
|
+
logger.info("Shutdown step start", { step: "discord.disconnect" });
|
|
300
|
+
stepStartedAt = Date.now();
|
|
301
|
+
await gateway?.disconnect();
|
|
302
|
+
logger.info("Shutdown step done", { step: "discord.disconnect", ms: Date.now() - stepStartedAt });
|
|
303
|
+
logger.info("Shutdown step start", { step: "fastify.close" });
|
|
304
|
+
stepStartedAt = Date.now();
|
|
305
|
+
await app.close();
|
|
306
|
+
logger.info("Shutdown step done", { step: "fastify.close", ms: Date.now() - stepStartedAt });
|
|
307
|
+
await rm(appDataPath(options.dataRoot, "pid.json"), { force: true });
|
|
308
|
+
runtime.updatedAt = new Date().toISOString();
|
|
309
|
+
await atomicWriteJson(appDataPath(options.dataRoot, "runtime.json"), runtime);
|
|
310
|
+
logger.info("Backend stopped", { dataRoot: options.dataRoot, totalMs: Date.now() - shutdownStartedAt });
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function offlineDiscordStatus(warnings = []) {
|
|
315
|
+
return {
|
|
316
|
+
connected: false,
|
|
317
|
+
orchestratorConnected: false,
|
|
318
|
+
waifuBotCount: 0,
|
|
319
|
+
warnings
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function connectingDiscordStatus() {
|
|
323
|
+
return {
|
|
324
|
+
connected: false,
|
|
325
|
+
orchestratorConnected: false,
|
|
326
|
+
waifuBotCount: 0,
|
|
327
|
+
warnings: [],
|
|
328
|
+
connecting: true
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function withoutDiscordConnecting(status) {
|
|
332
|
+
const next = { ...status };
|
|
333
|
+
delete next.connecting;
|
|
334
|
+
return next;
|
|
335
|
+
}
|
|
336
|
+
async function maybeConnectDiscord(storage, autoConnect, logger, createDiscordGateway, onRuntimeIssue) {
|
|
337
|
+
const offline = offlineDiscordStatus(autoConnect ? ["Discord auto-connect is enabled but no orchestrator token is configured."] : []);
|
|
338
|
+
if (!autoConnect) {
|
|
339
|
+
return { status: offline };
|
|
340
|
+
}
|
|
341
|
+
const bots = await storage.readJson("user/discord-bots.json", DiscordBotsFileSchema, DiscordBotsFileSchema.parse(createEmptyRevisionedFile({ orchestrator: null, waifus: [] })));
|
|
342
|
+
if (!bots.orchestrator?.token) {
|
|
343
|
+
return { status: offline };
|
|
344
|
+
}
|
|
345
|
+
const gateway = createDiscordGateway({
|
|
346
|
+
orchestrator: bots.orchestrator,
|
|
347
|
+
waifus: bots.waifus,
|
|
348
|
+
logger,
|
|
349
|
+
cacheForGuild: async (guildId) => {
|
|
350
|
+
const [members, emojis, roles] = await Promise.all([
|
|
351
|
+
storage.readJson(`user/servers/${guildId}/members.json`, GuildMembersFileSchema, GuildMembersFileSchema.parse(createEmptyRevisionedFile({ guildId, members: [] }))),
|
|
352
|
+
storage.readJson(`user/servers/${guildId}/emojis.json`, GuildEmojisFileSchema, GuildEmojisFileSchema.parse(createEmptyRevisionedFile({ guildId, emojis: [] }))),
|
|
353
|
+
storage.readJson(`user/servers/${guildId}/roles.json`, GuildRolesFileSchema, GuildRolesFileSchema.parse(createEmptyRevisionedFile({ guildId, roles: [] })))
|
|
354
|
+
]);
|
|
355
|
+
return {
|
|
356
|
+
members: mergeConfiguredBotsIntoMembers(members.members, bots),
|
|
357
|
+
emojis: emojis.emojis,
|
|
358
|
+
roles: roles.roles
|
|
359
|
+
};
|
|
360
|
+
},
|
|
361
|
+
refreshMembersForGuild: async (guildId) => {
|
|
362
|
+
const members = await refreshDiscordMembersForRuntime(storage, guildId);
|
|
363
|
+
return {
|
|
364
|
+
members: mergeConfiguredBotsIntoMembers(members.members, bots)
|
|
365
|
+
};
|
|
366
|
+
},
|
|
367
|
+
refreshRolesForGuild: async (guildId) => {
|
|
368
|
+
const roles = await refreshDiscordRolesForRuntime(storage, guildId);
|
|
369
|
+
return {
|
|
370
|
+
roles: roles.roles
|
|
371
|
+
};
|
|
372
|
+
},
|
|
373
|
+
onRuntimeIssue
|
|
374
|
+
});
|
|
375
|
+
try {
|
|
376
|
+
const status = await gateway.connect();
|
|
377
|
+
return { status, gateway };
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
381
|
+
const retryable = isRetryableDiscordAutoConnectError(error);
|
|
382
|
+
logger.error("Discord auto-connect failed", { message });
|
|
383
|
+
await gateway.disconnect();
|
|
384
|
+
return {
|
|
385
|
+
status: {
|
|
386
|
+
connected: false,
|
|
387
|
+
orchestratorConnected: false,
|
|
388
|
+
waifuBotCount: 0,
|
|
389
|
+
warnings: [`Discord auto-connect failed: ${message}`]
|
|
390
|
+
},
|
|
391
|
+
retryableFailure: retryable ? { message } : undefined
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const RETRYABLE_DISCORD_ERROR_CODES = new Set([
|
|
396
|
+
"ENOTFOUND",
|
|
397
|
+
"EAI_AGAIN",
|
|
398
|
+
"ETIMEDOUT",
|
|
399
|
+
"ECONNRESET",
|
|
400
|
+
"ECONNREFUSED",
|
|
401
|
+
"ENETUNREACH",
|
|
402
|
+
"EHOSTUNREACH",
|
|
403
|
+
"EPIPE",
|
|
404
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
405
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
406
|
+
"UND_ERR_SOCKET"
|
|
407
|
+
]);
|
|
408
|
+
const RETRYABLE_DISCORD_MESSAGE_PATTERNS = [
|
|
409
|
+
/\bgetaddrinfo\b/i,
|
|
410
|
+
/\bdns\b/i,
|
|
411
|
+
/\bnetwork\b/i,
|
|
412
|
+
/\btimeout\b/i,
|
|
413
|
+
/\btimed out\b/i,
|
|
414
|
+
/\bsocket\b/i,
|
|
415
|
+
/\bfetch failed\b/i,
|
|
416
|
+
/\bconnection reset\b/i,
|
|
417
|
+
/\bconnection refused\b/i,
|
|
418
|
+
/\bunreachable\b/i
|
|
419
|
+
];
|
|
420
|
+
const RETRYABLE_DISCORD_CLOSE_CODES = new Set([1001, 1006, 1011, 1012, 1013, 4000]);
|
|
421
|
+
function isRetryableDiscordAutoConnectError(error) {
|
|
422
|
+
const code = errorCode(error);
|
|
423
|
+
if (code && RETRYABLE_DISCORD_ERROR_CODES.has(code)) {
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
427
|
+
return RETRYABLE_DISCORD_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
|
|
428
|
+
}
|
|
429
|
+
function isRetryableDiscordRuntimeIssue(issue) {
|
|
430
|
+
if (isRetryableDiscordAutoConnectError(issue.error ?? issue) || isRetryableDiscordAutoConnectError(issue)) {
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
if (issue.source === "invalidated") {
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
if (issue.source === "shard-disconnect" && issue.wasClean === false && typeof issue.code === "number") {
|
|
437
|
+
return RETRYABLE_DISCORD_CLOSE_CODES.has(issue.code);
|
|
438
|
+
}
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
function discordRuntimeIssueLogContext(issue) {
|
|
442
|
+
return {
|
|
443
|
+
source: issue.source,
|
|
444
|
+
botId: issue.botId,
|
|
445
|
+
shardId: issue.shardId,
|
|
446
|
+
code: issue.code,
|
|
447
|
+
wasClean: issue.wasClean,
|
|
448
|
+
message: issue.message
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
function errorCode(error) {
|
|
452
|
+
if (!error || typeof error !== "object")
|
|
453
|
+
return undefined;
|
|
454
|
+
const code = error.code;
|
|
455
|
+
if (typeof code === "string")
|
|
456
|
+
return code;
|
|
457
|
+
const nestedError = errorCode(error.error);
|
|
458
|
+
if (nestedError)
|
|
459
|
+
return nestedError;
|
|
460
|
+
return errorCode(error.cause);
|
|
461
|
+
}
|
|
462
|
+
async function refreshDiscordMembersForRuntime(storage, guildId) {
|
|
463
|
+
const token = await readDiscordBotToken(storage);
|
|
464
|
+
if (!token) {
|
|
465
|
+
return storage.readJson(`user/servers/${guildId}/members.json`, GuildMembersFileSchema, GuildMembersFileSchema.parse(createEmptyRevisionedFile({ guildId, members: [] })));
|
|
466
|
+
}
|
|
467
|
+
const rawMembers = await fetchAllDiscordGuildMembers(token, guildId);
|
|
468
|
+
const now = new Date().toISOString();
|
|
469
|
+
const members = rawMembers.map((member) => ({
|
|
470
|
+
userId: member.user.id,
|
|
471
|
+
username: member.user.username,
|
|
472
|
+
globalDisplayName: member.user.global_name ?? undefined,
|
|
473
|
+
guildDisplayName: member.nick ?? member.user.global_name ?? member.user.username,
|
|
474
|
+
bot: member.user.bot ?? false,
|
|
475
|
+
lastSeenAt: now,
|
|
476
|
+
perChannelLastSeenAt: {}
|
|
477
|
+
}));
|
|
478
|
+
return storage.updateRevisionedJson({
|
|
479
|
+
resourceKey: `members:${guildId}`,
|
|
480
|
+
relativePath: path.join("user", "servers", guildId, "members.json"),
|
|
481
|
+
schema: GuildMembersFileSchema,
|
|
482
|
+
fallback: GuildMembersFileSchema.parse(createEmptyRevisionedFile({ guildId, members: [] })),
|
|
483
|
+
transform: (current) => ({
|
|
484
|
+
...current,
|
|
485
|
+
guildId,
|
|
486
|
+
members
|
|
487
|
+
})
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
async function fetchAllDiscordGuildMembers(token, guildId) {
|
|
491
|
+
const members = [];
|
|
492
|
+
let after = "0";
|
|
493
|
+
for (;;) {
|
|
494
|
+
const response = await discordApiFetch(token, `/guilds/${guildId}/members?limit=1000&after=${encodeURIComponent(after)}`);
|
|
495
|
+
const page = response;
|
|
496
|
+
members.push(...page);
|
|
497
|
+
if (page.length < 1000) {
|
|
498
|
+
return members;
|
|
499
|
+
}
|
|
500
|
+
after = page[page.length - 1]?.user.id ?? after;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
async function refreshDiscordRolesForRuntime(storage, guildId) {
|
|
504
|
+
const token = await readDiscordBotToken(storage);
|
|
505
|
+
if (!token) {
|
|
506
|
+
return storage.readJson(`user/servers/${guildId}/roles.json`, GuildRolesFileSchema, GuildRolesFileSchema.parse(createEmptyRevisionedFile({ guildId, roles: [] })));
|
|
507
|
+
}
|
|
508
|
+
const rawRoles = await fetchAllDiscordGuildRoles(token, guildId);
|
|
509
|
+
const roles = mapDiscordRoles(rawRoles);
|
|
510
|
+
return storage.updateRevisionedJson({
|
|
511
|
+
resourceKey: `roles:${guildId}`,
|
|
512
|
+
relativePath: path.join("user", "servers", guildId, "roles.json"),
|
|
513
|
+
schema: GuildRolesFileSchema,
|
|
514
|
+
fallback: GuildRolesFileSchema.parse(createEmptyRevisionedFile({ guildId, roles: [] })),
|
|
515
|
+
transform: (current) => ({
|
|
516
|
+
...current,
|
|
517
|
+
guildId,
|
|
518
|
+
roles
|
|
519
|
+
})
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
async function fetchAllDiscordGuildRoles(token, guildId) {
|
|
523
|
+
const response = await discordApiFetch(token, `/guilds/${guildId}/roles`);
|
|
524
|
+
return response;
|
|
525
|
+
}
|
|
526
|
+
function mapDiscordRoles(rawRoles) {
|
|
527
|
+
const now = new Date().toISOString();
|
|
528
|
+
return rawRoles
|
|
529
|
+
.filter((role) => role.name !== "@everyone")
|
|
530
|
+
.map((role) => ({
|
|
531
|
+
id: role.id,
|
|
532
|
+
name: role.name,
|
|
533
|
+
color: role.color ?? 0,
|
|
534
|
+
hoist: role.hoist ?? false,
|
|
535
|
+
mentionable: role.mentionable ?? false,
|
|
536
|
+
managed: role.managed ?? false,
|
|
537
|
+
fetchedAt: now
|
|
538
|
+
}));
|
|
539
|
+
}
|
|
540
|
+
async function readDiscordBotToken(storage) {
|
|
541
|
+
const bots = await storage.readJson("user/discord-bots.json", DiscordBotsFileSchema, DiscordBotsFileSchema.parse(createEmptyRevisionedFile({ orchestrator: null, waifus: [] })));
|
|
542
|
+
return bots.orchestrator?.enabled === false
|
|
543
|
+
? bots.waifus.find((bot) => bot.enabled && bot.token)?.token
|
|
544
|
+
: bots.orchestrator?.token ?? bots.waifus.find((bot) => bot.enabled && bot.token)?.token;
|
|
545
|
+
}
|
|
546
|
+
async function discordApiFetch(token, pathAndQuery) {
|
|
547
|
+
const response = await fetch(`https://discord.com/api/v10${pathAndQuery}`, {
|
|
548
|
+
headers: {
|
|
549
|
+
authorization: token.startsWith("Bot ") ? token : `Bot ${token}`,
|
|
550
|
+
"user-agent": "Discord-Waifus/0.1"
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
const text = await response.text();
|
|
554
|
+
const parsed = text ? JSON.parse(text) : undefined;
|
|
555
|
+
if (!response.ok) {
|
|
556
|
+
const message = typeof parsed === "object" && parsed && "message" in parsed
|
|
557
|
+
? String(parsed.message)
|
|
558
|
+
: response.statusText;
|
|
559
|
+
throw new Error(`Discord API request failed (${response.status}): ${message}`);
|
|
560
|
+
}
|
|
561
|
+
return parsed;
|
|
562
|
+
}
|
|
563
|
+
async function countConfiguredGuilds(storage) {
|
|
564
|
+
try {
|
|
565
|
+
const entries = await readdir(path.join(storage.dataRoot, "user", "servers"));
|
|
566
|
+
return entries.length;
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
if (error.code === "ENOENT") {
|
|
570
|
+
return 0;
|
|
571
|
+
}
|
|
572
|
+
throw error;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
async function writeRuntimeFiles(dataRoot, runtime) {
|
|
576
|
+
await Promise.all([
|
|
577
|
+
atomicWriteJson(appDataPath(dataRoot, "pid.json"), runtime),
|
|
578
|
+
atomicWriteJson(appDataPath(dataRoot, "runtime.json"), runtime)
|
|
579
|
+
]);
|
|
580
|
+
}
|
|
581
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/backend/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type SpawnOptions } from "node:child_process";
|
|
2
|
+
import type { RuntimeState } from "../backend/runtime.js";
|
|
3
|
+
import { ParsedCli } from "./parser.js";
|
|
4
|
+
export type CliProcessOptions = {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
};
|
|
8
|
+
export type CliProcessRunner = {
|
|
9
|
+
run(command: string, args: string[], options?: CliProcessOptions): Promise<number>;
|
|
10
|
+
};
|
|
11
|
+
export type GitHubReleaseAsset = {
|
|
12
|
+
name: string;
|
|
13
|
+
browser_download_url: string;
|
|
14
|
+
};
|
|
15
|
+
export type GitHubRelease = {
|
|
16
|
+
tag_name?: string;
|
|
17
|
+
assets?: GitHubReleaseAsset[];
|
|
18
|
+
};
|
|
19
|
+
export type CliRuntimeOptions = {
|
|
20
|
+
processRunner?: CliProcessRunner;
|
|
21
|
+
githubReleaseFetcher?: () => Promise<GitHubRelease>;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
23
|
+
platform?: NodeJS.Platform;
|
|
24
|
+
argv?: string[];
|
|
25
|
+
execPath?: string;
|
|
26
|
+
cwd?: string;
|
|
27
|
+
detachedSpawner?: CliDetachedSpawner;
|
|
28
|
+
detachedBackendWaiter?: (dataRoot: string, pid: number, timeoutMs: number) => Promise<RuntimeState | undefined>;
|
|
29
|
+
processAlive?: (pid: number) => boolean;
|
|
30
|
+
};
|
|
31
|
+
export type CliDetachedSpawner = (command: string, args: string[], options: SpawnOptions) => {
|
|
32
|
+
pid?: number;
|
|
33
|
+
unref(): void;
|
|
34
|
+
};
|
|
35
|
+
export declare function runCommand(parsed: ParsedCli, options?: CliRuntimeOptions): Promise<number>;
|