@helyx/bot 1.5.4 → 1.7.0

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +5 -2
  3. package/command-root-catalogue.json +21 -5
  4. package/dist/cloud-connector.js +2 -0
  5. package/dist/cloud-control-dispatcher.js +20 -0
  6. package/dist/command-registration-policy.js +2 -0
  7. package/dist/control-directory-contracts.d.ts +50 -0
  8. package/dist/control-directory-contracts.js +2 -0
  9. package/dist/control-server-schemas.d.ts +3 -3
  10. package/dist/control-server.d.ts +10 -46
  11. package/dist/control-server.js +50 -3
  12. package/dist/creator-invite-service.d.ts +7 -0
  13. package/dist/creator-invite-service.js +17 -0
  14. package/dist/developer-operations-module.js +0 -55
  15. package/dist/diagnostic-command.js +1 -0
  16. package/dist/discord-guild-health.d.ts +2 -2
  17. package/dist/discord-guild-health.js +1 -0
  18. package/dist/events.d.ts +1 -0
  19. package/dist/events.js +2 -0
  20. package/dist/help-credentials.d.ts +25 -0
  21. package/dist/help-credentials.js +149 -0
  22. package/dist/help-module.d.ts +27 -0
  23. package/dist/help-module.js +288 -0
  24. package/dist/help-runtime.d.ts +3 -0
  25. package/dist/help-runtime.js +42 -0
  26. package/dist/help-transport.d.ts +53 -0
  27. package/dist/help-transport.js +267 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +10 -0
  30. package/dist/interactions.js +10 -6
  31. package/dist/process-info-module.d.ts +3 -0
  32. package/dist/process-info-module.js +97 -0
  33. package/dist/server-overview-control.d.ts +35 -0
  34. package/dist/server-overview-control.js +362 -0
  35. package/dist/server-overview-discord.d.ts +33 -0
  36. package/dist/server-overview-discord.js +212 -0
  37. package/dist/server-overview-profile.d.ts +8 -0
  38. package/dist/server-overview-profile.js +62 -0
  39. package/dist/server-overview-routes.d.ts +4 -0
  40. package/dist/server-overview-routes.js +41 -0
  41. package/dist/shard-contracts.d.ts +66 -0
  42. package/dist/shard-contracts.js +23 -0
  43. package/dist/shard-coordinator.d.ts +1 -1
  44. package/dist/shard-router.d.ts +9 -0
  45. package/dist/shard-router.js +6 -0
  46. package/dist/shard-supervisor.d.ts +1 -1
  47. package/dist/shard-supervisor.js +8 -0
  48. package/dist/shard-worker.d.ts +1 -1
  49. package/dist/shard-worker.js +8 -0
  50. package/dist/verification-service.d.ts +4 -0
  51. package/dist/verification-service.js +10 -0
  52. package/documentation/README.md +1 -0
  53. package/documentation/examples/.env.example +29 -85
  54. package/documentation/guides/help-command.md +62 -0
  55. package/documentation/reference/environment.md +7 -6
  56. package/documentation/runbooks/installation-and-upgrades.md +4 -1
  57. package/package.json +6 -6
@@ -0,0 +1,4 @@
1
+ import { type ServerOverviewControl } from "@helyx/control-protocol";
2
+ import type { FastifyInstance } from "fastify";
3
+ export declare function registerServerOverviewControlRoutes(server: FastifyInstance, control: ServerOverviewControl): void;
4
+ //# sourceMappingURL=server-overview-routes.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { overviewReadInputSchema, overviewRevokeInputSchema, } from "@helyx/control-protocol";
2
+ import { z } from "zod";
3
+ import { BotControlTransportError } from "./control-errors.js";
4
+ export function registerServerOverviewControlRoutes(server, control) {
5
+ const actor = z.string().regex(/^\d{17,20}$/u);
6
+ server.post("/v1/guilds/:guildId/overview", async (request) => {
7
+ const { guildId } = z
8
+ .object({ guildId: actor })
9
+ .strict()
10
+ .parse(request.params);
11
+ const raw = z
12
+ .object({ actorUserId: actor })
13
+ .passthrough()
14
+ .parse(request.body);
15
+ const { actorUserId, ...query } = raw;
16
+ const input = overviewReadInputSchema.parse({ ...query, guildId });
17
+ if (query.guildId !== undefined && query.guildId !== guildId)
18
+ throw new BotControlTransportError(400, "Server scope does not match");
19
+ if (!control.readServerOverview)
20
+ throw new BotControlTransportError(503, "Overview is unavailable");
21
+ return control.readServerOverview({ ...input, actorUserId });
22
+ });
23
+ server.post("/v1/guilds/:guildId/overview/invites/revoke", async (request) => {
24
+ const { guildId } = z
25
+ .object({ guildId: actor })
26
+ .strict()
27
+ .parse(request.params);
28
+ const raw = z
29
+ .object({ actorUserId: actor })
30
+ .passthrough()
31
+ .parse(request.body);
32
+ const { actorUserId, ...query } = raw;
33
+ const input = overviewRevokeInputSchema.parse({ ...query, guildId });
34
+ if (query.guildId !== undefined && query.guildId !== guildId)
35
+ throw new BotControlTransportError(400, "Server scope does not match");
36
+ if (!control.revokeServerOverviewInvite)
37
+ throw new BotControlTransportError(503, "Invite management is unavailable");
38
+ return control.revokeServerOverviewInvite({ ...input, actorUserId });
39
+ });
40
+ }
41
+ //# sourceMappingURL=server-overview-routes.js.map
@@ -239,6 +239,28 @@ export declare const shardControlOperationSchema: z.ZodDiscriminatedUnion<[z.Zod
239
239
  }, z.core.$strict>, z.ZodObject<{
240
240
  kind: z.ZodLiteral<"guild.state.get">;
241
241
  guildId: z.ZodString;
242
+ }, z.core.$strict>, z.ZodObject<{
243
+ guildId: z.ZodString;
244
+ operation: z.ZodEnum<{
245
+ summary: "summary";
246
+ members: "members";
247
+ member: "member";
248
+ invites: "invites";
249
+ }>;
250
+ memberId: z.ZodOptional<z.ZodString>;
251
+ refresh: z.ZodOptional<z.ZodBoolean>;
252
+ cursor: z.ZodOptional<z.ZodString>;
253
+ limit: z.ZodOptional<z.ZodNumber>;
254
+ search: z.ZodOptional<z.ZodString>;
255
+ roleId: z.ZodOptional<z.ZodString>;
256
+ kind: z.ZodLiteral<"guild.overview.read">;
257
+ actorUserId: z.ZodString;
258
+ }, z.core.$strict>, z.ZodObject<{
259
+ guildId: z.ZodString;
260
+ code: z.ZodString;
261
+ confirmed: z.ZodLiteral<true>;
262
+ kind: z.ZodLiteral<"guild.overview.invite.revoke">;
263
+ actorUserId: z.ZodString;
242
264
  }, z.core.$strict>, z.ZodObject<{
243
265
  guildId: z.ZodString;
244
266
  userIds: z.ZodArray<z.ZodString>;
@@ -742,6 +764,28 @@ export declare const shardControlRequestSchema: z.ZodObject<{
742
764
  }, z.core.$strict>, z.ZodObject<{
743
765
  kind: z.ZodLiteral<"guild.state.get">;
744
766
  guildId: z.ZodString;
767
+ }, z.core.$strict>, z.ZodObject<{
768
+ guildId: z.ZodString;
769
+ operation: z.ZodEnum<{
770
+ summary: "summary";
771
+ members: "members";
772
+ member: "member";
773
+ invites: "invites";
774
+ }>;
775
+ memberId: z.ZodOptional<z.ZodString>;
776
+ refresh: z.ZodOptional<z.ZodBoolean>;
777
+ cursor: z.ZodOptional<z.ZodString>;
778
+ limit: z.ZodOptional<z.ZodNumber>;
779
+ search: z.ZodOptional<z.ZodString>;
780
+ roleId: z.ZodOptional<z.ZodString>;
781
+ kind: z.ZodLiteral<"guild.overview.read">;
782
+ actorUserId: z.ZodString;
783
+ }, z.core.$strict>, z.ZodObject<{
784
+ guildId: z.ZodString;
785
+ code: z.ZodString;
786
+ confirmed: z.ZodLiteral<true>;
787
+ kind: z.ZodLiteral<"guild.overview.invite.revoke">;
788
+ actorUserId: z.ZodString;
745
789
  }, z.core.$strict>, z.ZodObject<{
746
790
  guildId: z.ZodString;
747
791
  userIds: z.ZodArray<z.ZodString>;
@@ -1765,6 +1809,28 @@ export declare const supervisorMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObje
1765
1809
  }, z.core.$strict>, z.ZodObject<{
1766
1810
  kind: z.ZodLiteral<"guild.state.get">;
1767
1811
  guildId: z.ZodString;
1812
+ }, z.core.$strict>, z.ZodObject<{
1813
+ guildId: z.ZodString;
1814
+ operation: z.ZodEnum<{
1815
+ summary: "summary";
1816
+ members: "members";
1817
+ member: "member";
1818
+ invites: "invites";
1819
+ }>;
1820
+ memberId: z.ZodOptional<z.ZodString>;
1821
+ refresh: z.ZodOptional<z.ZodBoolean>;
1822
+ cursor: z.ZodOptional<z.ZodString>;
1823
+ limit: z.ZodOptional<z.ZodNumber>;
1824
+ search: z.ZodOptional<z.ZodString>;
1825
+ roleId: z.ZodOptional<z.ZodString>;
1826
+ kind: z.ZodLiteral<"guild.overview.read">;
1827
+ actorUserId: z.ZodString;
1828
+ }, z.core.$strict>, z.ZodObject<{
1829
+ guildId: z.ZodString;
1830
+ code: z.ZodString;
1831
+ confirmed: z.ZodLiteral<true>;
1832
+ kind: z.ZodLiteral<"guild.overview.invite.revoke">;
1833
+ actorUserId: z.ZodString;
1768
1834
  }, z.core.$strict>, z.ZodObject<{
1769
1835
  guildId: z.ZodString;
1770
1836
  userIds: z.ZodArray<z.ZodString>;
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { overviewReadInputSchema, overviewRevokeInputSchema, } from "@helyx/control-protocol";
2
3
  import { discordUserIdentityRequestSchema } from "@helyx/control-protocol/discord-user-identities";
3
4
  import { dashboardFieldValidationSchema } from "@helyx/control-protocol/field-validation";
4
5
  import { channelAuditModuleIdSchema, channelAuditInputSchema, channelAuditConfigurationSchema, channelAuditReportSchema, } from "@helyx/control-protocol/channel-audit";
@@ -299,6 +300,14 @@ export const shardControlOperationSchema = z.discriminatedUnion("kind", [
299
300
  })
300
301
  .strict(),
301
302
  z.object({ kind: z.literal("guild.state.get"), guildId: snowflake }).strict(),
303
+ overviewReadInputSchema.safeExtend({
304
+ kind: z.literal("guild.overview.read"),
305
+ actorUserId: snowflake,
306
+ }),
307
+ overviewRevokeInputSchema.extend({
308
+ kind: z.literal("guild.overview.invite.revoke"),
309
+ actorUserId: snowflake,
310
+ }),
302
311
  discordUserIdentityRequestSchema.extend({
303
312
  kind: z.literal("guild.user-identities.read"),
304
313
  }),
@@ -1107,6 +1116,20 @@ export async function executeShardControlOperation(handler, operation) {
1107
1116
  });
1108
1117
  case "guild.state.get":
1109
1118
  return handler.getGuildState(operation.guildId);
1119
+ case "guild.overview.read": {
1120
+ if (!handler.readServerOverview)
1121
+ throw new Error("Overview is unavailable");
1122
+ const { kind: _kind, ...input } = operation;
1123
+ void _kind;
1124
+ return handler.readServerOverview(input);
1125
+ }
1126
+ case "guild.overview.invite.revoke": {
1127
+ if (!handler.revokeServerOverviewInvite)
1128
+ throw new Error("Invite management is unavailable");
1129
+ const { kind: _kind, ...input } = operation;
1130
+ void _kind;
1131
+ return handler.revokeServerOverviewInvite(input);
1132
+ }
1110
1133
  case "guild.user-identities.read": {
1111
1134
  if (!handler.resolveDiscordUserIdentities)
1112
1135
  throw new Error("Discord identity lookup is unavailable");
@@ -5,9 +5,9 @@ declare const generationDescriptorSchema: z.ZodObject<{
5
5
  version: z.ZodLiteral<1>;
6
6
  applicationId: z.ZodString;
7
7
  environment: z.ZodEnum<{
8
- production: "production";
9
8
  development: "development";
10
9
  test: "test";
10
+ production: "production";
11
11
  }>;
12
12
  generation: z.ZodString;
13
13
  shardCount: z.ZodNumber;
@@ -1,3 +1,4 @@
1
+ import type { OverviewReadInput, OverviewRevokeInput, OverviewResponse } from "@helyx/control-protocol";
1
2
  import type { DiscordUserIdentityRequest, DiscordUserIdentityResponse } from "@helyx/control-protocol/discord-user-identities";
2
3
  import { type AutoModerationEnhancedResultOutcome, type CreatorOnboardingRequest, type CreatorOnboardingResponse } from "@helyx/sdk";
3
4
  import { type BotControlHandler } from "./control-server.js";
@@ -9,6 +10,14 @@ type LocalDispatcher = (shardId: number, request: ShardControlRequest) => Promis
9
10
  export declare class ShardControlRouter implements BotControlHandler {
10
11
  #private;
11
12
  private readonly input;
13
+ readServerOverview(input: OverviewReadInput & {
14
+ actorUserId: string;
15
+ }): Promise<OverviewResponse>;
16
+ revokeServerOverviewInvite(input: OverviewRevokeInput & {
17
+ actorUserId: string;
18
+ }): Promise<{
19
+ revoked: true;
20
+ }>;
12
21
  creatorOnboarding(input: CreatorOnboardingRequest): Promise<CreatorOnboardingResponse>;
13
22
  constructor(input: {
14
23
  generation: string;
@@ -11,6 +11,12 @@ const LEASE_VALIDATION_TIMEOUT_MS = 3_000;
11
11
  const ECKO_RESULT_TIMEOUT_MS = AUTOMOD_SCANNER_LIMITS.resultAcknowledgementSeconds * 1_000;
12
12
  export class ShardControlRouter {
13
13
  input;
14
+ readServerOverview(input) {
15
+ return this.#route({ kind: "guild.overview.read", ...input });
16
+ }
17
+ revokeServerOverviewInvite(input) {
18
+ return this.#route({ kind: "guild.overview.invite.revoke", ...input });
19
+ }
14
20
  creatorOnboarding(input) {
15
21
  return this.#route({
16
22
  kind: "creator.onboarding",
@@ -22,7 +22,7 @@ export declare function shardHostedControlCallbacks(router: Pick<ShardControlRou
22
22
  deliverHostedServerLeave: (input: {
23
23
  operationId: string;
24
24
  guildId: string;
25
- }) => Promise<"completed" | "requires_review" | "queued" | "not_currently_installed" | "accepted_for_retry">;
25
+ }) => Promise<"queued" | "completed" | "not_currently_installed" | "accepted_for_retry" | "requires_review">;
26
26
  refreshHostedServerOwner: (guildId: string) => Promise<{
27
27
  username: string;
28
28
  observedAt: string;
@@ -36,6 +36,8 @@ import { SupervisorCloudDiscordDirectory } from "./supervisor-cloud-directory.js
36
36
  import { createSupportModule } from "./support-module.js";
37
37
  import { createOAuthModule } from "./oauth-module.js";
38
38
  import { createPrivacyModule } from "./privacy-module.js";
39
+ import { createProcessInfoModule } from "./process-info-module.js";
40
+ import { createRuntimeHelpModule } from "./help-runtime.js";
39
41
  import { REVIEWED_PREMIUM_MODULE_IDS } from "@helyx/module-manifest";
40
42
  import { createPremiumActivationModule } from "./premium-activation-module.js";
41
43
  import { DiscordPremiumGuildAuthority } from "./premium-guild-authority.js";
@@ -248,6 +250,8 @@ export async function startShardSupervisor(environment, processEnvironment, work
248
250
  : undefined;
249
251
  const supportModule = createSupportModule(cloudConnector);
250
252
  const privacyModule = createPrivacyModule();
253
+ const processInfoModule = createProcessInfoModule("shard supervisor");
254
+ const helpModule = createRuntimeHelpModule(environment);
251
255
  const premiumEnvironment = requirePremiumProviderEnvironment(featureModules, environment.STRIPE_ENVIRONMENT);
252
256
  const premiumActivationModule = !premiumEnvironment
253
257
  ? undefined
@@ -267,6 +271,8 @@ export async function startShardSupervisor(environment, processEnvironment, work
267
271
  permissionsModule,
268
272
  supportModule,
269
273
  privacyModule,
274
+ processInfoModule,
275
+ helpModule,
270
276
  ...(premiumActivationModule ? [premiumActivationModule] : []),
271
277
  ...(oauthModule ? [oauthModule] : []),
272
278
  ...(cloudManagementModule ? [cloudManagementModule] : []),
@@ -291,6 +297,8 @@ export async function startShardSupervisor(environment, processEnvironment, work
291
297
  permissionsModule,
292
298
  supportModule,
293
299
  privacyModule,
300
+ processInfoModule,
301
+ helpModule,
294
302
  ...(premiumActivationModule ? [premiumActivationModule] : []),
295
303
  ...(oauthModule ? [oauthModule] : []),
296
304
  ...(cloudManagementModule ? [cloudManagementModule] : []),
@@ -63,7 +63,7 @@ export declare function parseShardWorkerEnvironment(processEnvironment: NodeJS.P
63
63
  HELYX_OAUTH_ENABLED: boolean;
64
64
  HELYX_CLOUD_ENDPOINT: string;
65
65
  HELYX_OWNER_USER_IDS: string[];
66
- HELYX_SHARD_MODE: "fixed" | "off" | "auto";
66
+ HELYX_SHARD_MODE: "off" | "auto" | "fixed";
67
67
  HELYX_SHARD_SCOPE: "local" | "coordinated";
68
68
  HELYX_CLOUD_AUDIT_RETENTION_DAYS: number;
69
69
  HELYX_CLOUD_CREDENTIAL_AUDIT_RETENTION_DAYS: number;
@@ -44,6 +44,8 @@ import { HostedBotInviteGateClient, HostedServerLeaveWorker, HostedServerModerat
44
44
  import { createSupportModule } from "./support-module.js";
45
45
  import { createOAuthModule } from "./oauth-module.js";
46
46
  import { createPrivacyModule } from "./privacy-module.js";
47
+ import { createProcessInfoModule } from "./process-info-module.js";
48
+ import { createRuntimeHelpModule } from "./help-runtime.js";
47
49
  import { HttpOAuthService } from "./oauth-service.js";
48
50
  import { createLocalScheduledTaskRoute, } from "./scheduled-task-runner.js";
49
51
  import { createLocalNumericWriteBehind } from "./numeric-write-behind.js";
@@ -202,6 +204,8 @@ export async function startShardWorker(processEnvironment = process.env, identit
202
204
  : undefined;
203
205
  const supportModule = createSupportModule(cloudProxy);
204
206
  const privacyModule = createPrivacyModule();
207
+ const processInfoModule = createProcessInfoModule(`shard worker ${identity.shardId}`);
208
+ const helpModule = createRuntimeHelpModule(environment);
205
209
  const premiumEnvironment = requirePremiumProviderEnvironment(featureModules, environment.STRIPE_ENVIRONMENT);
206
210
  const premiumActivationModule = !premiumEnvironment
207
211
  ? undefined
@@ -221,6 +225,8 @@ export async function startShardWorker(processEnvironment = process.env, identit
221
225
  permissionsModule,
222
226
  supportModule,
223
227
  privacyModule,
228
+ processInfoModule,
229
+ helpModule,
224
230
  ...(premiumActivationModule ? [premiumActivationModule] : []),
225
231
  ...(oauthModule ? [oauthModule] : []),
226
232
  ...(cloudManagementModule ? [cloudManagementModule] : []),
@@ -244,6 +250,8 @@ export async function startShardWorker(processEnvironment = process.env, identit
244
250
  permissionsModule,
245
251
  supportModule,
246
252
  privacyModule,
253
+ processInfoModule,
254
+ helpModule,
247
255
  ...(premiumActivationModule ? [premiumActivationModule] : []),
248
256
  ...(oauthModule ? [oauthModule] : []),
249
257
  ...(cloudManagementModule ? [cloudManagementModule] : []),
@@ -21,6 +21,10 @@ export declare class HttpVerificationService implements VerificationService {
21
21
  }): Promise<{
22
22
  cancelled: number;
23
23
  }>;
24
+ countPendingAttempts(input: {
25
+ installationId: string;
26
+ guildId: string;
27
+ }): Promise<number>;
24
28
  listAttempts(input: DashboardAttemptQuery & {
25
29
  installationId: string;
26
30
  guildId: string;
@@ -82,6 +82,16 @@ export class HttpVerificationService {
82
82
  }
83
83
  return cancelled;
84
84
  }
85
+ async countPendingAttempts(input) {
86
+ const result = z
87
+ .object({ count: z.number().int().nonnegative() })
88
+ .strict()
89
+ .parse(await this.#request("/internal/v1/attempts/pending-count", {
90
+ method: "POST",
91
+ body: input,
92
+ }));
93
+ return result.count;
94
+ }
85
95
  async listAttempts(input) {
86
96
  const { installationId, guildId, ...query } = input;
87
97
  return dashboardAttemptPageSchema.parse(await this.#request("/internal/v1/attempts/query", {
@@ -18,6 +18,7 @@ and module guides.
18
18
  - [Operate installations and upgrades](runbooks/installation-and-upgrades.md)
19
19
  - [Plan backup and recovery](runbooks/backup-and-recovery.md)
20
20
  - [Handle privacy and support](guides/privacy-and-support.md)
21
+ - [Use Help and optional online matching](guides/help-command.md)
21
22
  - [Build an independent module](modules/building-a-module.md)
22
23
  - [Test a module](modules/testing-a-module.md)
23
24
  - [Prepare a module package](modules/publishing-a-module.md)
@@ -1,89 +1,33 @@
1
- # REQUIRED — EDIT THESE VALUES
1
+ # Helyx self-hosted environment
2
+ # Keep this file private. Retain the encryption key when updating.
2
3
 
3
- HELYX_RUNTIME_PROFILE=self-hosted
4
- HELYX_DEPLOYMENT_ENVIRONMENT=self-hosted
4
+ # Runtime
5
+ HELYX_RUNTIME_PROFILE='self-hosted'
6
+ HELYX_DEPLOYMENT_ENVIRONMENT='self-hosted'
7
+ NODE_ENV='production'
5
8
 
6
9
  # Discord
7
- DISCORD_TOKEN=replace-me
8
- DISCORD_CLIENT_ID=12345678901234567
9
- # Explicit privileged gateway opt-in. Keep false unless a reviewed loaded module
10
- # requires message content and it is enabled in the Discord developer portal.
11
- HELYX_MESSAGE_CONTENT_ENABLED=false
12
- # Enable for loaded member workflows such as Welcome, Access Control or Levels,
13
- # with Server Members Intent also enabled in the Discord developer portal.
14
- HELYX_GUILD_MEMBERS_ENABLED=false
15
- # Database
16
- # Docker: keep the URL. Direct Node.js/managed hosting: use your provider URL.
17
- DATABASE_ENGINE=postgresql
18
- DATABASE_URL=postgresql://database:5432/helyx
19
- DATABASE_SSL=disable
20
- # Self-host startup applies pending migrations automatically (the default).
21
- # Hosted-only inspect mode is not a self-host setting; leave this commented.
22
- # HELYX_DATABASE_STARTUP_MODE=apply
23
- # Match your provider: disable=no TLS; require=TLS without certificate
24
- # verification; verify-full=TLS with certificate verification.
25
-
26
- # Included Docker database — both password values must match.
27
- PGUSER=helyx
28
- PGPASSWORD=replace-with-a-strong-password
29
- POSTGRES_DB=helyx
30
- POSTGRES_USER=helyx
31
- POSTGRES_PASSWORD=replace-with-a-strong-password
32
-
33
- # OPTIONAL EVERYDAY SETTINGS
34
-
35
- # Ready for dashboard linking, but remains unpaired until you use a one-use code.
36
- HELYX_CLOUD_CONNECT_ENABLED=true
37
- # Public dashboard origin used in bot-generated report links.
38
- # HELYX_DASHBOARD_PUBLIC_URL=https://app.helyx.gg
39
- # HELYX_OWNER_USER_IDS=12345678901234567
40
-
41
- # trace, debug, info, warn, error, fatal or silent
42
- LOG_LEVEL=info
43
-
44
- # SHARDING: OFF BY DEFAULT
45
-
46
- # `off` is the compatible self-host default. Keep shard-only values commented
47
- # in this mode; an empty value is still rejected as configured. MySQL must stay
48
- # off. Advanced PostgreSQL self-hosting may use `auto` under one
49
- # supervisor, or `fixed` with a deliberate total count. Local mode never needs
50
- # Redis. Coordinated multi-host self-hosting is outside the first release.
51
- HELYX_SHARD_MODE=off
52
- # HELYX_SHARD_SCOPE=local
53
- # HELYX_SHARD_COUNT=2
54
- # HELYX_SHARD_WORKERS_PER_REPLICA=2
55
- # HELYX_SHARD_REDIS_URL=rediss://private-redis.example:6379
56
- # HELYX_SHARD_REDIS_NAMESPACE=helyx.self-host
57
- # HELYX_SHARD_GENERATION=local-20260728
58
- # HELYX_SHARD_DATABASE_CONNECTION_BUDGET=10
59
- # HELYX_SHARD_SUPERVISOR_DATABASE_POOL_MAX=2
60
- # HELYX_SHARD_WORKER_DATABASE_POOL_MAX=4
61
- # Redis URL and namespace are intentionally unsupported for the first
62
- # self-hosted release: do not uncomment them for local auto or fixed mode.
10
+ DISCORD_CLIENT_ID='12345678901234567'
11
+ DISCORD_TOKEN='replace-me'
12
+ HELYX_GUILD_MEMBERS_ENABLED='false'
13
+ HELYX_MESSAGE_CONTENT_ENABLED='false'
63
14
 
64
- # ADVANCED INTEGRATIONS — EDIT ONLY WHEN NEEDED
65
-
66
- # Additional reviewed module packages
67
- # HELYX_MODULE_PACKAGES=
68
-
69
- # Guild command writes remain off until explicitly enabled for known guild IDs.
70
- # For enabled-module server commands, set writes=true, retain allowlist scope,
71
- # add comma-separated Discord server IDs below, and use global mode platform-only.
72
- # See README.md before changing these defaults. Legacy mode still allows globals.
73
- HELYX_GUILD_COMMAND_WRITES_ENABLED=false
74
- HELYX_GUILD_COMMAND_WRITE_SCOPE=allowlist
75
- # HELYX_GUILD_COMMAND_RELEASE_ID=
76
- HELYX_GLOBAL_COMMAND_MODE=legacy
77
- # HELYX_GUILD_COMMAND_WRITE_GUILD_IDS=
78
-
79
- # DANGER ZONE — HELYX-MANAGED VALUES, DO NOT EDIT
80
-
81
- # Generated module selection
82
- HELYX_MODULE_CATALOGUE_PATH=./helyx.modules.json
83
-
84
- # Generated privately by npm run setup. Required by Cloud Connect, Giveaways,
85
- # and Invite Tracking; retain it unchanged across restarts and deployments.
86
- # HELYX_DATA_ENCRYPTION_KEY=replace-with-a-base64-encoded-32-byte-key
87
-
88
- # Runtime mode
89
- NODE_ENV=production
15
+ # Database
16
+ DATABASE_ENGINE='postgresql'
17
+ DATABASE_URL='postgresql://database:5432/helyx'
18
+ DATABASE_SSL='disable'
19
+
20
+ # Commands
21
+ HELYX_GUILD_COMMAND_WRITES_ENABLED='true'
22
+ HELYX_GUILD_COMMAND_WRITE_SCOPE='allowlist'
23
+ HELYX_GLOBAL_COMMAND_MODE='platform-only'
24
+ HELYX_GUILD_COMMAND_WRITE_GUILD_IDS=''
25
+
26
+ # Modules and dashboard
27
+ HELYX_MODULE_CATALOGUE_PATH='./helyx.modules.json'
28
+ HELYX_CLOUD_CONNECT_ENABLED='true'
29
+ HELYX_SHARD_MODE='off'
30
+ LOG_LEVEL='info'
31
+
32
+ # Keep this key unchanged across restarts and updates
33
+ HELYX_DATA_ENCRYPTION_KEY='replace-with-a-base64-encoded-32-byte-key'
@@ -0,0 +1,62 @@
1
+ # Help Command
2
+
3
+ Use `/help question:your question` to search Helyx's saved FAQ answers. You can
4
+ choose a module or documentation area to narrow the question, for example
5
+ `/help module:Feedback question:The command is not visible`. Use `/help` for a
6
+ short introduction. Replies are private, and Help is available without enabling
7
+ a customer module or purchasing Premium.
8
+
9
+ Help returns a stored answer, possible FAQ questions to choose from, or a
10
+ documentation link when it cannot find a suitable match. You can also enter a
11
+ six-digit FAQ ID. Answers retain their source and availability labels; a Planned
12
+ or Testing answer does not mean that feature is available. Staff-authored shared
13
+ and Custom answers are labelled separately. Help does not inspect your server
14
+ settings, execute repairs or generate new answers.
15
+
16
+ ## Self-hosted installations
17
+
18
+ The bot includes an approved FAQ snapshot for local search. Local Help needs no
19
+ Helyx account, Cloud Connect, Cloudflare key, local AI model or internet service.
20
+ The snapshot belongs to the installed release; update the bot to receive a newer
21
+ one. Central suppression or editing cannot change an offline release already on
22
+ your computer. When an enrolled online request fails, self-hosted Help labels
23
+ its local fallback clearly.
24
+
25
+ Online matching is optional. When available, open your Helyx account's
26
+ self-hosting page and create a Help code. On the bot's host, from the generated
27
+ project folder, run:
28
+
29
+ ```sh
30
+ npx helyx help connect
31
+ npx helyx help status
32
+ npx helyx help disconnect
33
+ ```
34
+
35
+ Read the connection notice and paste the single-use code at the prompt. Codes
36
+ expire after ten minutes; do not put one in a command argument or screenshot.
37
+ The project needs its existing data-encryption key and a writable `.helyx`
38
+ directory. Help saves a separate encrypted credential there. Docker starters
39
+ retain it in their private named volume. Preserve the encryption key when
40
+ restarting; changing it makes the saved credential unreadable.
41
+
42
+ Status reads only the local file. Disconnect revokes online access when the
43
+ service is reachable and removes the local credential. If remote revocation
44
+ fails, revoke the installation from the account dashboard. A replacement code
45
+ rotates the credential when consumed; account revocation takes effect centrally.
46
+ Neither action disables local Help or requires Cloud Connect.
47
+
48
+ ## Questions and privacy
49
+
50
+ Online Help sends the question and selected area to Helyx; its embedding
51
+ provider receives the public question text needed for meaning comparison.
52
+ Do not include credentials, private messages or personal details. Self-host
53
+ online requests use a Help installation identity and do not send Discord user
54
+ or server IDs. Hosted requests use trusted member/server identities for limits.
55
+ The service does not store a persistent history of member questions or completed
56
+ question embeddings. Short-lived request counters and Help connection metadata
57
+ are handled through Helyx's privacy system. Providers have their own processing
58
+ terms. See [Privacy and support](privacy-and-support.md).
59
+
60
+ Shared request and spending limits may make semantic matching temporarily
61
+ unavailable. Hosted Help fails safely to documentation when it cannot verify
62
+ the current collection; self-hosted Help can still use its labelled local copy.
@@ -4,7 +4,7 @@ Start from [the published example](../examples/.env.example). The example is a
4
4
  copy of the starter emitted by the supported CLI and is checked for drift.
5
5
 
6
6
  This page explains the ownership and safe defaults of the generated variables;
7
- the comments in `.env.example` remain the version-matched field reference.
7
+ the compact `.env.example` contains only the standard installation settings.
8
8
 
9
9
  ## Required values
10
10
 
@@ -12,8 +12,9 @@ the comments in `.env.example` remain the version-matched field reference.
12
12
  `DISCORD_CLIENT_ID` is the application's numeric ID. `DATABASE_ENGINE` accepts
13
13
  `postgresql` or `mysql` and defaults to PostgreSQL when omitted. `DATABASE_URL`
14
14
  must match the selected engine, and `DATABASE_SSL` must match the database
15
- provider. PostgreSQL Docker users must also replace the example password
16
- consistently in `PGPASSWORD` and `POSTGRES_PASSWORD`. The MySQL Compose starter
15
+ provider. PostgreSQL Docker users can run `npm run envbuilder` and select the
16
+ bundled database. That choice adds matching `PGPASSWORD` and `POSTGRES_PASSWORD`
17
+ values and the Docker database/user settings. The MySQL Compose starter
17
18
  runs only the bot and connects to the external database in `DATABASE_URL`.
18
19
 
19
20
  Percent-encode special characters in URL credentials. `DATABASE_SSL=disable`
@@ -30,7 +31,7 @@ boundary and prevents Hosted-only Helyx Ecko calls from entering the local
30
31
  runtime.
31
32
 
32
33
  Privileged Discord intents, privacy execution, hosted OAuth, status reporting,
33
- guild command writes, and advanced sharding stay disabled until their complete
34
+ and advanced sharding stay disabled until their complete
34
35
  requirements are deliberately configured. An empty variable still counts as a
35
36
  configured value in many environments, so leave unused optional lines
36
37
  commented.
@@ -48,8 +49,8 @@ For enabled-module command builds in approved servers, set
48
49
  Discord server IDs. Use `HELYX_GLOBAL_COMMAND_MODE=platform-only` to retain global
49
50
  core/deployment commands while feature commands use per-server builds. Restart
50
51
  after changing these values and check the dashboard command-build status. The
51
- template's default `legacy` mode can still register compatible globals while
52
- guild writes are disabled; it does not mean that every command is disabled.
52
+ template uses `platform-only` and enables guild writes for the server IDs you
53
+ provide. Enter those IDs before starting; leave the allowlist scope in place.
53
54
  Do not use the advanced `all` scope merely to bypass an allowlist error.
54
55
 
55
56
  `HELYX_AUTOMOD_EMBEDDED_WORKERS` controls only the in-process Self-Hosted
@@ -22,7 +22,10 @@ below.
22
22
 
23
23
  1. Download a starter ZIP, or generate it from the builder's reviewed manifest.
24
24
  2. Install its dependencies with `npm ci` unless generation used `--install`.
25
- 3. Run `npm run setup`, then complete `.env`. A managed host may supply the
25
+ 3. Run `npm run envbuilder` to prepare `.env`, or use `npm run setup` and edit
26
+ the compact example. For the included Docker PostgreSQL service, use the
27
+ builder and choose **bundled** so its required database credentials are added.
28
+ A managed host may supply the
26
29
  required values through its protected variables panel instead. Keep the
27
30
  generated encryption key stable.
28
31
  4. Make the selected database reachable and run doctor through the matching
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helyx/bot",
3
- "version": "1.5.4",
3
+ "version": "1.7.0",
4
4
  "description": "Production Discord runtime for the modular Helyx platform.",
5
5
  "keywords": [
6
6
  "helyx",
@@ -51,15 +51,15 @@
51
51
  "start": "node --env-file-if-exists=../../.env dist/index.js"
52
52
  },
53
53
  "dependencies": {
54
- "@helyx/config": ">=1.6.0 <2.0.0",
55
- "@helyx/control-protocol": ">=0.9.0 <0.10.0",
56
- "@helyx/core": ">=0.2.0 <0.3.0",
57
- "@helyx/database": ">=2.5.0 <3.0.0",
54
+ "@helyx/config": ">=1.7.0 <2.0.0",
55
+ "@helyx/control-protocol": ">=0.9.1 <0.10.0",
56
+ "@helyx/core": ">=0.2.3 <0.3.0",
57
+ "@helyx/database": ">=2.5.1 <3.0.0",
58
58
  "@helyx/database-contracts": ">=0.3.0 <0.4.0",
59
59
  "@helyx/framework": ">=0.2.0 <0.3.0",
60
60
  "@helyx/module-manifest": ">=0.14.0 <0.15.0",
61
61
  "@helyx/platform": ">=1.3.0 <2.0.0",
62
- "@helyx/sdk": ">=0.17.0 <0.18.0",
62
+ "@helyx/sdk": ">=0.17.1 <0.18.0",
63
63
  "@helyx/status-client": ">=0.3.0 <0.4.0",
64
64
  "@helyx/verification-contracts": ">=0.5.0 <0.6.0",
65
65
  "discord.js": "14.27.0",