@helyx/bot 1.5.0 → 1.5.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { parseBotEnvironment } from "@helyx/config";
2
2
  import { StatusHeartbeatReporter } from "@helyx/status-client";
3
3
  import { safeError, ServiceRegistry } from "@helyx/core";
4
- import { checkDatabaseConnection, createDatabasePool, EckoOperationsRepository, inspectConfiguredModuleMigrations, inspectCoreMigrations, inspectCreatorOnboardingMigrations, runCreatorOnboardingMigrations, PremiumAllocationRepository, runCoreMigrations, runConfiguredModuleMigrations, } from "@helyx/database";
4
+ import { checkDatabaseConnection, createDatabasePool, EckoOperationsRepository, InstallationRepository, inspectConfiguredModuleMigrations, inspectCoreMigrations, inspectCreatorOnboardingMigrations, runCreatorOnboardingMigrations, PremiumAllocationRepository, runCoreMigrations, runConfiguredModuleMigrations, } from "@helyx/database";
5
5
  import { createRuntime } from "@helyx/framework";
6
6
  import { assertRepositoryEngineSupported } from "@helyx/database/adapters";
7
7
  import { createPlatformServices, gamingStatisticsRecordOwner, achievementContributionRecordOwner, PostgresPrivacyProviderExecutor, PlatformMemberRoleGrantOwnershipService, PostgresMemberRoleGrantOwnershipStore, } from "@helyx/platform";
@@ -20,6 +20,7 @@ import { assertConfiguredModuleDatabaseCompatibility, loadConfiguredModulePackag
20
20
  import { resolveModulePackageSpecifiers } from "./module-configuration.js";
21
21
  import { createPermissionsModule } from "./permissions-module.js";
22
22
  import { createManagementModule } from "./management-module.js";
23
+ import { createDiagnosticModule, createMysqlDiagnosticLock, createPostgresDiagnosticLock, } from "./diagnostic-command.js";
23
24
  import { DiscordMessageDeliveryService, DiscordMemberRoleService, DiscordVerificationMemberService, DiscordResourceInspection, installModuleEvents, } from "./events.js";
24
25
  import { DiscordModerationMemberEnforcementAdapter } from "./discord-member-enforcement-service.js";
25
26
  import { DiscordModuleLoggingService } from "./module-logging.js";
@@ -303,6 +304,30 @@ async function startUnshardedBot(processEnvironment) {
303
304
  });
304
305
  const permissionsModule = createPermissionsModule(featureModules);
305
306
  const managementModule = createManagementModule(featureModules, guildResources);
307
+ const diagnosticInstallations = mysql
308
+ ? new (await import("@helyx/database-mysql")).InstallationRepository(mysql.pool)
309
+ : new InstallationRepository(database);
310
+ const diagnosticModule = createDiagnosticModule({
311
+ client,
312
+ modules: featureModules,
313
+ runExclusive: mysql
314
+ ? createMysqlDiagnosticLock(mysql.pool)
315
+ : createPostgresDiagnosticLock(database),
316
+ assertGuildAvailable: async (guildId) => {
317
+ if (shuttingDown ||
318
+ !(await diagnosticInstallations.getActiveGuild(guildId)))
319
+ throw new Error("The server installation is not available");
320
+ },
321
+ listEnabledModules: (guildId) => diagnosticInstallations.listEnabledModules(guildId),
322
+ commandStatus: {
323
+ get: (guildId) => {
324
+ return guildCommandReads.getStatus(guildId);
325
+ },
326
+ refresh: (input) => {
327
+ return guildCommandReads.refreshStatus(input);
328
+ },
329
+ },
330
+ });
306
331
  const cloudManagementModule = environment.HELYX_CLOUD_CONNECT_ENABLED
307
332
  ? createCloudManagementModule({
308
333
  connector: cloudConnector,
@@ -327,6 +352,7 @@ async function startUnshardedBot(processEnvironment) {
327
352
  : undefined;
328
353
  const publicModules = [
329
354
  managementModule,
355
+ diagnosticModule,
330
356
  permissionsModule,
331
357
  supportModule,
332
358
  privacyModule,
@@ -405,6 +431,7 @@ async function startUnshardedBot(processEnvironment) {
405
431
  ...(deployedCommit ? { deploymentReference: deployedCommit } : {}),
406
432
  coreFunctions: [
407
433
  managementModule,
434
+ diagnosticModule,
408
435
  permissionsModule,
409
436
  supportModule,
410
437
  privacyModule,
@@ -534,6 +561,7 @@ async function startUnshardedBot(processEnvironment) {
534
561
  });
535
562
  const enabledCoreModuleIds = new Set([
536
563
  managementModule.manifest.id,
564
+ diagnosticModule.manifest.id,
537
565
  permissionsModule.manifest.id,
538
566
  supportModule.manifest.id,
539
567
  ...(premiumActivationModule ? [premiumActivationModule.manifest.id] : []),
@@ -555,6 +583,7 @@ async function startUnshardedBot(processEnvironment) {
555
583
  synchroniseInternalGuild: false,
556
584
  prepare: prepareGuilds,
557
585
  selfAuthorizingGuildModuleIds: new Set([
586
+ diagnosticModule.manifest.id,
558
587
  supportModule.manifest.id,
559
588
  ...(premiumActivationModule
560
589
  ? [premiumActivationModule.manifest.id]
@@ -13,6 +13,7 @@ import { CloudConnectorController, } from "./cloud-connector.js";
13
13
  import { createCloudManagementModule } from "./cloud-management-module.js";
14
14
  import { BotControlService, createBotControlServer, mapBotControlError, } from "./control-server.js";
15
15
  import { createManagementModule } from "./management-module.js";
16
+ import { createDiagnosticModule } from "./diagnostic-command.js";
16
17
  import { buildApplicationCommandDefinitions } from "./interactions.js";
17
18
  import { resolveModulePackageSpecifiers } from "./module-configuration.js";
18
19
  import { deriveSecureRandomSelectionKey, loadConfiguredModulePackages, platformServiceOptions, secureRandomSelectionWorkerKeyName, } from "./modules.js";
@@ -217,6 +218,10 @@ export async function startShardSupervisor(environment, processEnvironment, work
217
218
  };
218
219
  const permissionsModule = createPermissionsModule(featureModules);
219
220
  const managementModule = createManagementModule(featureModules, unavailableResources);
221
+ // The supervisor registers metadata; guild checks and repairs run in workers.
222
+ const diagnosticModule = createDiagnosticModule({
223
+ modules: featureModules,
224
+ });
220
225
  const cloudManagementModule = environment.HELYX_CLOUD_CONNECT_ENABLED
221
226
  ? createCloudManagementModule({
222
227
  connector: cloudConnector,
@@ -242,6 +247,7 @@ export async function startShardSupervisor(environment, processEnvironment, work
242
247
  : undefined;
243
248
  const publicModules = [
244
249
  managementModule,
250
+ diagnosticModule,
245
251
  permissionsModule,
246
252
  supportModule,
247
253
  privacyModule,
@@ -265,6 +271,7 @@ export async function startShardSupervisor(environment, processEnvironment, work
265
271
  : {}),
266
272
  coreFunctions: [
267
273
  managementModule,
274
+ diagnosticModule,
268
275
  permissionsModule,
269
276
  supportModule,
270
277
  privacyModule,
@@ -102,6 +102,7 @@ export declare function shardWorkerCommandRegistration(input: {
102
102
  prepare: NonNullable<CommandRegistration["prepare"]>;
103
103
  operationsModuleId?: string;
104
104
  supportModuleId: string;
105
+ diagnosticModuleId?: string;
105
106
  premiumActivationModuleId?: string;
106
107
  oauthModuleId?: string;
107
108
  }): CommandRegistration;
@@ -1,6 +1,6 @@
1
1
  import { parseBotEnvironment } from "@helyx/config";
2
2
  import { safeError, ServiceRegistry } from "@helyx/core";
3
- import { checkDatabaseConnection, createDatabasePool, PremiumAllocationRepository, } from "@helyx/database";
3
+ import { checkDatabaseConnection, createDatabasePool, PremiumAllocationRepository, InstallationRepository, } from "@helyx/database";
4
4
  import { assertRepositoryEngineSupported } from "@helyx/database/adapters";
5
5
  import { REVIEWED_PREMIUM_MODULE_IDS } from "@helyx/module-manifest";
6
6
  import { createRuntime } from "@helyx/framework";
@@ -18,6 +18,8 @@ import { installCreatorInvitePlatform } from "./creator-onboarding-platform.js";
18
18
  import { installGuildTracking, } from "./guilds.js";
19
19
  import { installInteractions, } from "./interactions.js";
20
20
  import { createManagementModule } from "./management-module.js";
21
+ import { createDiagnosticModule, createPostgresDiagnosticLock, } from "./diagnostic-command.js";
22
+ import { GuildCommandReadService } from "./guild-command-read-service.js";
21
23
  import { DiscordModuleLoggingService } from "./module-logging.js";
22
24
  import { resolveModulePackageSpecifiers } from "./module-configuration.js";
23
25
  import { loadConfiguredModulePackages, platformServiceOptions, secureRandomSelectionWorkerKeyName, } from "./modules.js";
@@ -158,6 +160,35 @@ export async function startShardWorker(processEnvironment = process.env, identit
158
160
  const guildResources = new DiscordGuildResourceDirectory(client);
159
161
  const permissionsModule = createPermissionsModule(featureModules);
160
162
  const managementModule = createManagementModule(featureModules, guildResources);
163
+ const diagnosticInstallations = new InstallationRepository(database);
164
+ const diagnosticModule = createDiagnosticModule({
165
+ client,
166
+ modules: featureModules,
167
+ runExclusive: createPostgresDiagnosticLock(database),
168
+ assertGuildAvailable: async (guildId) => {
169
+ if (shuttingDown ||
170
+ guildIdToShardId(guildId, identity.shardCount) !== identity.shardId)
171
+ throw new Error("The server is no longer owned by this shard");
172
+ const installation = await diagnosticInstallations.getActiveGuild(guildId);
173
+ if (!installation ||
174
+ installation.shardGeneration !== identity.generation ||
175
+ installation.shardDeploymentOrder !==
176
+ BigInt(identity.deploymentOrder ?? 1) ||
177
+ installation.shardSupervisorId !== identity.supervisorId ||
178
+ installation.shardId !== identity.shardId ||
179
+ installation.shardFencingToken !== BigInt(identity.fencingToken))
180
+ throw new Error("The server installation or shard ownership changed");
181
+ },
182
+ listEnabledModules: (guildId) => diagnosticInstallations.listEnabledModules(guildId),
183
+ commandStatus: {
184
+ get: (guildId) => {
185
+ return guildCommandReads.getStatus(guildId);
186
+ },
187
+ refresh: (input) => {
188
+ return guildCommandReads.refreshStatus(input);
189
+ },
190
+ },
191
+ });
161
192
  cloudProxy = new WorkerCloudConnectorProxy();
162
193
  const cloudManagementModule = environment.HELYX_CLOUD_CONNECT_ENABLED
163
194
  ? createCloudManagementModule({
@@ -184,6 +215,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
184
215
  : undefined;
185
216
  const publicModules = [
186
217
  managementModule,
218
+ diagnosticModule,
187
219
  permissionsModule,
188
220
  supportModule,
189
221
  privacyModule,
@@ -206,6 +238,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
206
238
  : {}),
207
239
  coreFunctions: [
208
240
  managementModule,
241
+ diagnosticModule,
209
242
  permissionsModule,
210
243
  supportModule,
211
244
  privacyModule,
@@ -224,6 +257,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
224
257
  ...publicModules,
225
258
  ...(operationsModule ? [operationsModule] : []),
226
259
  ];
260
+ const guildCommandReads = new GuildCommandReadService(database, environment.DISCORD_CLIENT_ID, undefined, environment.DISCORD_TOKEN, environment.HELYX_GUILD_COMMAND_WRITES_ENABLED, environment.HELYX_GUILD_COMMAND_WRITE_GUILD_IDS, environment.HELYX_GUILD_COMMAND_WRITE_SCOPE === "all", modules);
227
261
  const platformServices = new Map();
228
262
  const serviceAccess = new ServiceRegistry(platformServices);
229
263
  const serviceOptions = platformServiceOptions(environment, publicModules);
@@ -328,6 +362,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
328
362
  runtime = createRuntime({ modules, logger, services: platformServices });
329
363
  const enabledCoreModuleIds = new Set([
330
364
  managementModule.manifest.id,
365
+ diagnosticModule.manifest.id,
331
366
  permissionsModule.manifest.id,
332
367
  supportModule.manifest.id,
333
368
  ...(premiumActivationModule ? [premiumActivationModule.manifest.id] : []),
@@ -359,6 +394,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
359
394
  ? { operationsModuleId: operationsModule.manifest.id }
360
395
  : {}),
361
396
  supportModuleId: supportModule.manifest.id,
397
+ diagnosticModuleId: diagnosticModule.manifest.id,
362
398
  ...(premiumActivationModule
363
399
  ? { premiumActivationModuleId: premiumActivationModule.manifest.id }
364
400
  : {}),
@@ -563,6 +599,7 @@ export function shardWorkerCommandRegistration(input) {
563
599
  synchronise: false,
564
600
  selfAuthorizingGuildModuleIds: new Set([
565
601
  input.supportModuleId,
602
+ ...(input.diagnosticModuleId ? [input.diagnosticModuleId] : []),
566
603
  ...(input.premiumActivationModuleId
567
604
  ? [input.premiumActivationModuleId]
568
605
  : []),
@@ -37,7 +37,7 @@ commented.
37
37
 
38
38
  Enable privileged intents in the Discord Developer Portal as well as the bot
39
39
  environment when required: Counting needs Message Content, Welcome and Access
40
- Control need Guild Members, and Levels needs both. Access Control's Password
40
+ Control need Guild Members. Levels needs Guild Members, and Message Content only when using **Custom message types** rather than **All messages**. Access Control's Password
41
41
  Entry also needs Message Content. The corresponding variables are
42
42
  `HELYX_MESSAGE_CONTENT_ENABLED` and `HELYX_GUILD_MEMBERS_ENABLED`.
43
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helyx/bot",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Production Discord runtime for the modular Helyx platform.",
5
5
  "keywords": [
6
6
  "helyx",
@@ -53,7 +53,7 @@
53
53
  "@helyx/config": ">=1.4.0 <2.0.0",
54
54
  "@helyx/control-protocol": ">=0.8.0 <0.9.0",
55
55
  "@helyx/core": ">=0.2.0 <0.3.0",
56
- "@helyx/database": ">=2.4.0 <3.0.0",
56
+ "@helyx/database": ">=2.4.1 <3.0.0",
57
57
  "@helyx/database-contracts": ">=0.2.0 <0.3.0",
58
58
  "@helyx/framework": ">=0.2.0 <0.3.0",
59
59
  "@helyx/module-manifest": ">=0.13.0 <0.14.0",
@@ -70,7 +70,7 @@
70
70
  "zod": "4.4.3"
71
71
  },
72
72
  "optionalDependencies": {
73
- "@helyx/database-mysql": ">=0.2.0 <0.3.0"
73
+ "@helyx/database-mysql": ">=0.2.1 <0.3.0"
74
74
  },
75
75
  "peerDependencies": {
76
76
  "@helyx/module-automod": ">=1.1.1 <2.0.0",