@helyx/bot 0.5.0 → 0.6.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.
@@ -1,5 +1,5 @@
1
1
  import { safeError, ServiceRegistry } from "@helyx/core";
2
- import { checkDatabaseConnection, createDatabasePool, AuditRepository, GuildCommandRepository, InteractionSessionRepository, RateLimitRepository, runConfiguredModuleMigrations, runCoreMigrations, RuntimeStateRepository, } from "@helyx/database";
2
+ import { checkDatabaseConnection, createDatabasePool, AuditRepository, GuildCommandRepository, InteractionSessionRepository, PremiumAllocationRepository, RateLimitRepository, runConfiguredModuleMigrations, runCoreMigrations, RuntimeStateRepository, } from "@helyx/database";
3
3
  import { createPlatformServices, gamingStatisticsRecordOwner, achievementContributionRecordOwner, PostgresPrivacyProviderExecutor, } from "@helyx/platform";
4
4
  import { HELYX_SERVICE_NAMES } from "@helyx/sdk";
5
5
  import { Client, ShardingManager } from "discord.js";
@@ -24,6 +24,9 @@ import { SupervisorCloudDiscordDirectory } from "./supervisor-cloud-directory.js
24
24
  import { createSupportModule } from "./support-module.js";
25
25
  import { createOAuthModule } from "./oauth-module.js";
26
26
  import { createPrivacyModule } from "./privacy-module.js";
27
+ import { REVIEWED_PREMIUM_MODULE_IDS } from "@helyx/module-manifest";
28
+ import { createPremiumActivationModule } from "./premium-activation-module.js";
29
+ import { DiscordPremiumGuildAuthority } from "./premium-guild-authority.js";
27
30
  import { discordRestOptions } from "./discord-rest.js";
28
31
  import { availabilityCatalogue, availabilityCatalogueDefinitions, statusCatalogueDefinitions, } from "./module-availability-control.js";
29
32
  import { createScheduledTaskRunner, schedulerOperationalHealth, } from "./scheduled-task-runner.js";
@@ -35,6 +38,8 @@ import { GuildCommandWorker } from "./guild-command-worker.js";
35
38
  import { GuildCommandDiscordClient } from "./guild-command-discord-client.js";
36
39
  import { GuildCommandReadService } from "./guild-command-read-service.js";
37
40
  import { scheduleGuildCommandRelease } from "./guild-command-release.js";
41
+ import { assertReviewedPremiumCatalogue, requirePremiumProviderEnvironment, } from "./premium-access.js";
42
+ import { enforcePremiumCatalogue, PREMIUM_CATALOGUE_ENFORCEMENT_INTERVAL_MS, } from "./premium-catalogue-enforcement.js";
38
43
  const LEASE_RENEW_INTERVAL_MS = 10_000;
39
44
  const STARTUP_LEASE_RENEW_INTERVAL_MS = 5_000;
40
45
  const LEASE_VALIDATION_TIMEOUT_MS = 1_000;
@@ -121,6 +126,7 @@ export async function startShardSupervisor(environment, processEnvironment, work
121
126
  let maintainingLeases = false;
122
127
  let rebalancingShards = false;
123
128
  let retentionTimer;
129
+ let premiumCatalogueTimer;
124
130
  let leaseTimer;
125
131
  let startupLeaseTimer;
126
132
  let startupWorkerHeartbeats;
@@ -156,6 +162,7 @@ export async function startShardSupervisor(environment, processEnvironment, work
156
162
  const moduleSpecifiers = await resolveModulePackageSpecifiers(environment.HELYX_MODULE_PACKAGES, undefined, undefined, environment.HELYX_MODULE_CATALOGUE_PATH);
157
163
  const modulePackages = await loadConfiguredModulePackages(moduleSpecifiers);
158
164
  const featureModules = modulePackages.map(({ definition }) => definition);
165
+ assertReviewedPremiumCatalogue(featureModules);
159
166
  const gateway = await fetchGatewayBotInformation(environment.DISCORD_TOKEN);
160
167
  shardCount =
161
168
  environment.HELYX_SHARD_MODE === "fixed"
@@ -211,6 +218,16 @@ export async function startShardSupervisor(environment, processEnvironment, work
211
218
  : undefined;
212
219
  const supportModule = createSupportModule(cloudConnector);
213
220
  const privacyModule = createPrivacyModule();
221
+ const premiumEnvironment = requirePremiumProviderEnvironment(featureModules, environment.STRIPE_ENVIRONMENT);
222
+ const premiumActivationModule = !premiumEnvironment
223
+ ? undefined
224
+ : createPremiumActivationModule({
225
+ allocations: new PremiumAllocationRepository(database),
226
+ authority: new DiscordPremiumGuildAuthority(commandClient),
227
+ provider: "stripe",
228
+ providerEnvironment: premiumEnvironment,
229
+ reviewedPremiumModuleIds: REVIEWED_PREMIUM_MODULE_IDS,
230
+ });
214
231
  const oauthModule = environment.HELYX_OAUTH_ENABLED
215
232
  ? createOAuthModule()
216
233
  : undefined;
@@ -219,6 +236,7 @@ export async function startShardSupervisor(environment, processEnvironment, work
219
236
  permissionsModule,
220
237
  supportModule,
221
238
  privacyModule,
239
+ ...(premiumActivationModule ? [premiumActivationModule] : []),
222
240
  ...(oauthModule ? [oauthModule] : []),
223
241
  ...(cloudManagementModule ? [cloudManagementModule] : []),
224
242
  ...featureModules,
@@ -240,6 +258,7 @@ export async function startShardSupervisor(environment, processEnvironment, work
240
258
  permissionsModule,
241
259
  supportModule,
242
260
  privacyModule,
261
+ ...(premiumActivationModule ? [premiumActivationModule] : []),
243
262
  ...(oauthModule ? [oauthModule] : []),
244
263
  ...(cloudManagementModule ? [cloudManagementModule] : []),
245
264
  ].map(({ manifest }) => manifest),
@@ -1102,6 +1121,13 @@ export async function startShardSupervisor(environment, processEnvironment, work
1102
1121
  await cleanupExpiredCoreRecords(database, logger);
1103
1122
  retentionTimer = setInterval(() => void cleanupExpiredCoreRecords(database, logger), RETENTION_CLEANUP_INTERVAL_MS);
1104
1123
  retentionTimer.unref();
1124
+ premiumCatalogueTimer = setInterval(() => void enforcePremiumCatalogue(database, logger).catch((error) => {
1125
+ logger.warn({
1126
+ event: "premium.catalogue_enforcement_failed",
1127
+ error: safeError(error),
1128
+ }, "Premium module catalogue enforcement failed");
1129
+ }), PREMIUM_CATALOGUE_ENFORCEMENT_INTERVAL_MS);
1130
+ premiumCatalogueTimer.unref();
1105
1131
  await cloudConnector?.start();
1106
1132
  cloudStarted = true;
1107
1133
  if (workersRoutable)
@@ -1373,6 +1399,8 @@ export async function startShardSupervisor(environment, processEnvironment, work
1373
1399
  startupWorkerHeartbeats = undefined;
1374
1400
  if (retentionTimer)
1375
1401
  clearInterval(retentionTimer);
1402
+ if (premiumCatalogueTimer)
1403
+ clearInterval(premiumCatalogueTimer);
1376
1404
  workersRoutable = false;
1377
1405
  await scheduledTasks?.stop().catch(() => undefined);
1378
1406
  scheduledTasks = undefined;
@@ -1443,6 +1471,7 @@ async function runLeaderStartup(database, environment, modulePackages, modules,
1443
1471
  moduleVersion: definition.manifest.version,
1444
1472
  migrationsDirectory: join(packageRoot, "migrations"),
1445
1473
  })));
1474
+ await enforcePremiumCatalogue(database, logger);
1446
1475
  const repository = new RuntimeStateRepository(database);
1447
1476
  await synchroniseApplicationCommands({
1448
1477
  applicationId: environment.DISCORD_CLIENT_ID,
@@ -63,6 +63,7 @@ export declare function parseShardWorkerEnvironment(processEnvironment: NodeJS.P
63
63
  HELYX_STATUS_ENABLED: boolean;
64
64
  HELYX_STATUS_URL: string;
65
65
  HELYX_STATUS_HEARTBEAT_INTERVAL_SECONDS: number;
66
+ STRIPE_ENVIRONMENT?: "sandbox" | "live" | undefined;
66
67
  HELYX_BOT_CONTROL_SECRET?: string | undefined;
67
68
  HELYX_SUPPORT_SERVICE_SECRET?: string | undefined;
68
69
  HELYX_VERIFICATION_INSTALLATION_ID?: string | undefined;
@@ -86,6 +87,7 @@ export declare function shardWorkerCommandRegistration(input: {
86
87
  prepare: NonNullable<CommandRegistration["prepare"]>;
87
88
  operationsModuleId?: string;
88
89
  supportModuleId: string;
90
+ premiumActivationModuleId?: string;
89
91
  oauthModuleId?: string;
90
92
  }): CommandRegistration;
91
93
  //# sourceMappingURL=shard-worker.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { parseBotEnvironment } from "@helyx/config";
2
2
  import { safeError, ServiceRegistry } from "@helyx/core";
3
- import { checkDatabaseConnection, createDatabasePool } from "@helyx/database";
3
+ import { checkDatabaseConnection, createDatabasePool, PremiumAllocationRepository, } from "@helyx/database";
4
+ import { REVIEWED_PREMIUM_MODULE_IDS } from "@helyx/module-manifest";
4
5
  import { createRuntime } from "@helyx/framework";
5
6
  import { createPlatformServices, PlatformMemberRoleGrantOwnershipService, PostgresMemberRoleGrantOwnershipStore, } from "@helyx/platform";
6
7
  import { HELYX_SERVICE_NAMES, } from "@helyx/sdk";
@@ -18,6 +19,9 @@ import { DiscordModuleLoggingService } from "./module-logging.js";
18
19
  import { resolveModulePackageSpecifiers } from "./module-configuration.js";
19
20
  import { loadConfiguredModulePackages, platformServiceOptions, secureRandomSelectionWorkerKeyName, } from "./modules.js";
20
21
  import { createPermissionsModule } from "./permissions-module.js";
22
+ import { createPremiumActivationModule } from "./premium-activation-module.js";
23
+ import { DiscordPremiumGuildAuthority } from "./premium-guild-authority.js";
24
+ import { assertReviewedPremiumCatalogue, requirePremiumProviderEnvironment, } from "./premium-access.js";
21
25
  import { WorkerCloudConnectorProxy } from "./shard-cloud-proxy.js";
22
26
  import { DiscordOwnedMessageDeletionService } from "./discord-owned-message-service.js";
23
27
  import { DiscordGuildHealthInspection } from "./discord-guild-health.js";
@@ -118,6 +122,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
118
122
  const moduleSpecifiers = await resolveModulePackageSpecifiers(environment.HELYX_MODULE_PACKAGES, undefined, undefined, environment.HELYX_MODULE_CATALOGUE_PATH);
119
123
  const modulePackages = await loadConfiguredModulePackages(moduleSpecifiers);
120
124
  const featureModules = modulePackages.map(({ definition }) => definition);
125
+ assertReviewedPremiumCatalogue(featureModules);
121
126
  client = new Client({
122
127
  rest: discordRestOptions,
123
128
  intents: gatewayIntentsForModules(featureModules, environment.HELYX_MESSAGE_CONTENT_ENABLED, environment.HELYX_GUILD_MEMBERS_ENABLED),
@@ -140,6 +145,16 @@ export async function startShardWorker(processEnvironment = process.env, identit
140
145
  : undefined;
141
146
  const supportModule = createSupportModule(cloudProxy);
142
147
  const privacyModule = createPrivacyModule();
148
+ const premiumEnvironment = requirePremiumProviderEnvironment(featureModules, environment.STRIPE_ENVIRONMENT);
149
+ const premiumActivationModule = !premiumEnvironment
150
+ ? undefined
151
+ : createPremiumActivationModule({
152
+ allocations: new PremiumAllocationRepository(database),
153
+ authority: new DiscordPremiumGuildAuthority(client),
154
+ provider: "stripe",
155
+ providerEnvironment: premiumEnvironment,
156
+ reviewedPremiumModuleIds: REVIEWED_PREMIUM_MODULE_IDS,
157
+ });
143
158
  const oauthModule = environment.HELYX_OAUTH_ENABLED
144
159
  ? createOAuthModule()
145
160
  : undefined;
@@ -148,6 +163,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
148
163
  permissionsModule,
149
164
  supportModule,
150
165
  privacyModule,
166
+ ...(premiumActivationModule ? [premiumActivationModule] : []),
151
167
  ...(oauthModule ? [oauthModule] : []),
152
168
  ...(cloudManagementModule ? [cloudManagementModule] : []),
153
169
  ...featureModules,
@@ -168,6 +184,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
168
184
  permissionsModule,
169
185
  supportModule,
170
186
  privacyModule,
187
+ ...(premiumActivationModule ? [premiumActivationModule] : []),
171
188
  ...(oauthModule ? [oauthModule] : []),
172
189
  ...(cloudManagementModule ? [cloudManagementModule] : []),
173
190
  ].map(({ manifest }) => manifest),
@@ -236,6 +253,7 @@ export async function startShardWorker(processEnvironment = process.env, identit
236
253
  managementModule.manifest.id,
237
254
  permissionsModule.manifest.id,
238
255
  supportModule.manifest.id,
256
+ ...(premiumActivationModule ? [premiumActivationModule.manifest.id] : []),
239
257
  ...(oauthModule ? [oauthModule.manifest.id] : []),
240
258
  ...(cloudManagementModule ? [cloudManagementModule.manifest.id] : []),
241
259
  ...(operationsModule ? [operationsModule.manifest.id] : []),
@@ -258,6 +276,9 @@ export async function startShardWorker(processEnvironment = process.env, identit
258
276
  ? { operationsModuleId: operationsModule.manifest.id }
259
277
  : {}),
260
278
  supportModuleId: supportModule.manifest.id,
279
+ ...(premiumActivationModule
280
+ ? { premiumActivationModuleId: premiumActivationModule.manifest.id }
281
+ : {}),
261
282
  ...(oauthModule ? { oauthModuleId: oauthModule.manifest.id } : {}),
262
283
  }), logger, serviceAccess);
263
284
  moduleEvents = installModuleEvents(client, publicModules, logger, serviceAccess);
@@ -452,6 +473,9 @@ export function shardWorkerCommandRegistration(input) {
452
473
  synchronise: false,
453
474
  selfAuthorizingGuildModuleIds: new Set([
454
475
  input.supportModuleId,
476
+ ...(input.premiumActivationModuleId
477
+ ? [input.premiumActivationModuleId]
478
+ : []),
455
479
  ...(input.oauthModuleId ? [input.oauthModuleId] : []),
456
480
  ...(input.operationsModuleId ? [input.operationsModuleId] : []),
457
481
  ]),
@@ -92,8 +92,8 @@ HELYX_OAUTH_ENABLED=false
92
92
  # Generated module selection
93
93
  HELYX_MODULE_CATALOGUE_PATH=./helyx.modules.json
94
94
 
95
- # Generated privately by npm run setup. Never change it while Cloud Connect is
96
- # enrolled or a checkpointed Giveaways draw is in progress.
95
+ # Generated privately by npm run setup. Required by Cloud Connect, Giveaways,
96
+ # and Invite Tracking; retain it unchanged across restarts and deployments.
97
97
  # HELYX_DATA_ENCRYPTION_KEY=replace-with-a-base64-encoded-32-byte-key
98
98
 
99
99
  # Official Cloud Connect endpoints
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helyx/bot",
3
- "version": "0.5.0",
3
+ "version": "0.6.2",
4
4
  "description": "Production Discord runtime for the modular Helyx platform.",
5
5
  "keywords": [
6
6
  "helyx",
@@ -50,18 +50,18 @@
50
50
  "start": "node --env-file-if-exists=../../.env dist/index.js"
51
51
  },
52
52
  "dependencies": {
53
- "@helyx/config": ">=0.5.0 <0.6.0",
53
+ "@helyx/config": ">=1.0.0 <2.0.0",
54
54
  "@helyx/control-protocol": ">=0.4.0 <0.5.0",
55
55
  "@helyx/core": ">=0.1.0 <0.2.0",
56
- "@helyx/database": ">=0.10.0",
56
+ "@helyx/database": ">=1.0.0 <2.0.0",
57
57
  "@helyx/framework": ">=0.1.0 <0.2.0",
58
- "@helyx/module-manifest": ">=0.8.0 <0.9.0",
59
- "@helyx/platform": ">=0.7.0",
60
- "@helyx/sdk": ">=0.10.0",
58
+ "@helyx/module-manifest": ">=0.9.0 <0.10.0",
59
+ "@helyx/platform": ">=0.8.0 <0.9.0",
60
+ "@helyx/sdk": ">=0.11.0 <0.12.0",
61
61
  "@helyx/status-client": ">=0.1.0 <0.2.0",
62
62
  "@helyx/verification-contracts": ">=0.3.0 <0.4.0",
63
63
  "discord.js": "14.27.0",
64
- "fastify": "5.10.0",
64
+ "fastify": "5.12.3",
65
65
  "pino": "10.3.1",
66
66
  "redis": "6.1.0",
67
67
  "undici": "6.28.0",