@helyx/bot 1.5.1 → 1.5.3
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/CHANGELOG.md +25 -0
- package/command-root-catalogue.json +452 -0
- package/dist/cached-message-deletion-authority.d.ts +27 -0
- package/dist/cached-message-deletion-authority.js +288 -0
- package/dist/channel-audit-configuration.d.ts +11 -1
- package/dist/channel-audit-configuration.js +28 -6
- package/dist/channel-audit-control.js +42 -2
- package/dist/channel-audit-permissions.js +76 -3
- package/dist/cloud-command-policy-sync.d.ts +26 -0
- package/dist/cloud-command-policy-sync.js +198 -0
- package/dist/cloud-connector.d.ts +6 -1
- package/dist/cloud-connector.js +224 -53
- package/dist/cloud-control-dispatcher.js +18 -0
- package/dist/command-policy-runtime.d.ts +23 -0
- package/dist/command-policy-runtime.js +53 -0
- package/dist/command-root-catalogue.d.ts +5 -0
- package/dist/command-root-catalogue.js +16 -0
- package/dist/control-error-mapping.d.ts +8 -0
- package/dist/control-error-mapping.js +60 -0
- package/dist/control-errors.d.ts +3 -1
- package/dist/control-errors.js +4 -1
- package/dist/control-health-routes.d.ts +10 -0
- package/dist/control-health-routes.js +28 -0
- package/dist/control-server-schemas.d.ts +7 -0
- package/dist/control-server-schemas.js +9 -0
- package/dist/control-server.d.ts +27 -6
- package/dist/control-server.js +103 -122
- package/dist/creator-invite-key.d.ts +6 -0
- package/dist/creator-invite-key.js +16 -0
- package/dist/creator-invite-service.d.ts +3 -1
- package/dist/creator-invite-service.js +8 -7
- package/dist/creator-onboarding-platform.d.ts +1 -0
- package/dist/creator-onboarding-platform.js +5 -2
- package/dist/dashboard-feature-control.d.ts +2 -1
- package/dist/dashboard-feature-control.js +1 -0
- package/dist/dashboard-logging.d.ts +20 -0
- package/dist/dashboard-logging.js +39 -0
- package/dist/dashboard-module-projection.d.ts +1 -1
- package/dist/dashboard-module-projection.js +5 -2
- package/dist/dashboard-preview-import-routes.js +8 -0
- package/dist/database-bootstrap.d.ts +1 -1
- package/dist/database-bootstrap.js +4 -3
- package/dist/discord-channel-audit.js +1 -0
- package/dist/discord-user-identities.d.ts +14 -0
- package/dist/discord-user-identities.js +64 -0
- package/dist/emergency-deletion-dispatcher.d.ts +68 -0
- package/dist/emergency-deletion-dispatcher.js +502 -0
- package/dist/emergency-deletion-rest-transport.d.ts +24 -0
- package/dist/emergency-deletion-rest-transport.js +253 -0
- package/dist/events.d.ts +5 -0
- package/dist/events.js +53 -10
- package/dist/guarded-discord-dispatcher.d.ts +29 -0
- package/dist/guarded-discord-dispatcher.js +204 -0
- package/dist/guild-command-discord-client.d.ts +2 -0
- package/dist/guild-command-discord-client.js +7 -0
- package/dist/guild-command-projection.d.ts +4 -1
- package/dist/guild-command-projection.js +25 -0
- package/dist/guild-command-read-service.d.ts +10 -1
- package/dist/guild-command-read-service.js +37 -0
- package/dist/guild-command-worker.d.ts +19 -4
- package/dist/guild-command-worker.js +356 -26
- package/dist/guild-message-protection-author-roles.d.ts +7 -0
- package/dist/guild-message-protection-author-roles.js +93 -0
- package/dist/guild-message-protection-deletion.d.ts +21 -0
- package/dist/guild-message-protection-deletion.js +138 -0
- package/dist/guild-message-protection-delivery.d.ts +41 -0
- package/dist/guild-message-protection-delivery.js +223 -0
- package/dist/guild-message-update-metadata.d.ts +32 -0
- package/dist/guild-message-update-metadata.js +255 -0
- package/dist/guilds.d.ts +2 -1
- package/dist/guilds.js +11 -1
- package/dist/hosted-server-moderation.d.ts +2 -2
- package/dist/index.js +68 -4
- package/dist/interactions.d.ts +3 -1
- package/dist/interactions.js +77 -12
- package/dist/invite-rollup-maintenance.d.ts +9 -0
- package/dist/invite-rollup-maintenance.js +12 -0
- package/dist/managed-resource-authorization.d.ts +15 -0
- package/dist/managed-resource-authorization.js +37 -0
- package/dist/managed-resource-create-defaults.d.ts +21 -0
- package/dist/managed-resource-create-defaults.js +83 -0
- package/dist/managed-resource-query.d.ts +6 -0
- package/dist/managed-resource-query.js +15 -0
- package/dist/member-role-ids.d.ts +17 -0
- package/dist/member-role-ids.js +66 -0
- package/dist/message-protection-admission.d.ts +60 -0
- package/dist/message-protection-admission.js +279 -0
- package/dist/message-protection-cold-data.d.ts +42 -0
- package/dist/message-protection-cold-data.js +180 -0
- package/dist/message-protection-coordinator.d.ts +73 -0
- package/dist/message-protection-coordinator.js +622 -0
- package/dist/message-protection-settings.d.ts +40 -0
- package/dist/message-protection-settings.js +275 -0
- package/dist/message-protection-summary.d.ts +8 -0
- package/dist/message-protection-summary.js +98 -0
- package/dist/module-availability-control.js +20 -12
- package/dist/module-logging.d.ts +3 -2
- package/dist/module-logging.js +6 -1
- package/dist/modules.js +56 -1
- package/dist/mysql-runtime-persistence.d.ts +1 -0
- package/dist/mysql-runtime-persistence.js +4 -1
- package/dist/nexus-command-recovery-control-routes.d.ts +5 -0
- package/dist/nexus-command-recovery-control-routes.js +48 -0
- package/dist/nexus-command-references.d.ts +6 -0
- package/dist/nexus-command-references.js +33 -0
- package/dist/scheduled-task-runner.js +23 -4
- package/dist/shard-command-startup.d.ts +13 -0
- package/dist/shard-command-startup.js +27 -0
- package/dist/shard-contracts.d.ts +84 -0
- package/dist/shard-contracts.js +33 -0
- package/dist/shard-core-readiness.d.ts +5 -0
- package/dist/shard-core-readiness.js +19 -0
- package/dist/shard-router.d.ts +3 -0
- package/dist/shard-router.js +10 -1
- package/dist/shard-supervisor.d.ts +1 -1
- package/dist/shard-supervisor.js +131 -43
- package/dist/shard-worker.d.ts +1 -0
- package/dist/shard-worker.js +37 -15
- package/documentation/README.md +1 -0
- package/documentation/guides/self-hosting.md +54 -0
- package/package.json +18 -17
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GuildCommandVisibilityProfile } from "@helyx/database";
|
|
1
|
+
import type { GuildCommandRootMappingRecord, GuildCommandVisibilityProfile } from "@helyx/database";
|
|
2
2
|
import type { ModuleDefinition } from "@helyx/sdk";
|
|
3
3
|
export { commandRegistrationPolicy } from "./command-registration-policy.js";
|
|
4
4
|
export interface ProjectedGuildCommand {
|
|
@@ -15,6 +15,7 @@ export interface GuildCommandProjection {
|
|
|
15
15
|
rootCount: number;
|
|
16
16
|
subcommandCount: number;
|
|
17
17
|
selectedModuleIds: readonly string[];
|
|
18
|
+
rootMappings?: readonly GuildCommandRootMappingRecord[];
|
|
18
19
|
}
|
|
19
20
|
export interface ObservedGuildCommand {
|
|
20
21
|
id?: string;
|
|
@@ -39,6 +40,8 @@ export declare function projectGuildCommands(input: {
|
|
|
39
40
|
globallyDisabledModuleIds?: ReadonlySet<string>;
|
|
40
41
|
profile: GuildCommandVisibilityProfile;
|
|
41
42
|
includeInternalCommands?: boolean;
|
|
43
|
+
rootMappings?: readonly GuildCommandRootMappingRecord[];
|
|
44
|
+
reservedCommandNames?: readonly string[];
|
|
42
45
|
}): GuildCommandProjection;
|
|
43
46
|
export declare function diffGuildCommands(desired: GuildCommandProjection, observedInput: readonly ObservedGuildCommand[]): GuildCommandDiff;
|
|
44
47
|
export declare function guildCommandDefinitionHash(definitions: readonly Readonly<Record<string, unknown>>[]): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isCustomerSelectableModule } from "@helyx/module-manifest";
|
|
2
|
+
import { collectReservedCommandNames } from "@helyx/sdk";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { collectCommandRegistrations, } from "./shared-commands.js";
|
|
4
5
|
import { toCommandDefinition } from "./interactions.js";
|
|
@@ -46,6 +47,7 @@ export function projectGuildCommands(input) {
|
|
|
46
47
|
(input.includeInternalCommands && policy === "internal-guild"));
|
|
47
48
|
})
|
|
48
49
|
.map(projectRegistration)
|
|
50
|
+
.map((command) => projectRootMapping(command, input))
|
|
49
51
|
.sort(compareProjectedCommands);
|
|
50
52
|
validateProjectedCommands(definitions);
|
|
51
53
|
const canonicalDefinitions = definitions.map(({ definition }) => definition);
|
|
@@ -55,6 +57,29 @@ export function projectGuildCommands(input) {
|
|
|
55
57
|
rootCount: definitions.length,
|
|
56
58
|
subcommandCount: definitions.reduce((total, definition) => total + definition.executablePaths.length, 0),
|
|
57
59
|
selectedModuleIds: [...selected].sort(),
|
|
60
|
+
...(input.rootMappings ? { rootMappings: input.rootMappings } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function projectRootMapping(command, input) {
|
|
64
|
+
if (command.name !== "nexus" || command.type !== 1)
|
|
65
|
+
return command;
|
|
66
|
+
const mappings = (input.rootMappings ?? []).filter(({ canonicalRoot }) => canonicalRoot === "nexus");
|
|
67
|
+
if (mappings.length > 1)
|
|
68
|
+
throw new Error("Duplicate Nexus root mapping");
|
|
69
|
+
const mapping = mappings[0];
|
|
70
|
+
if (!mapping || mapping.desiredRoot === "nexus")
|
|
71
|
+
return command;
|
|
72
|
+
// Reserve every loaded command, including currently disabled modules and aliases.
|
|
73
|
+
const reserved = new Set([
|
|
74
|
+
...collectReservedCommandNames(input.modules),
|
|
75
|
+
...(input.reservedCommandNames ?? []),
|
|
76
|
+
]);
|
|
77
|
+
if (reserved.has(mapping.desiredRoot))
|
|
78
|
+
throw new Error("Nexus root conflicts with a reserved command");
|
|
79
|
+
return {
|
|
80
|
+
...command,
|
|
81
|
+
name: mapping.desiredRoot,
|
|
82
|
+
definition: { ...command.definition, name: mapping.desiredRoot },
|
|
58
83
|
};
|
|
59
84
|
}
|
|
60
85
|
function projectionRegistrationPolicy(module, contribution) {
|
|
@@ -16,6 +16,13 @@ export interface GuildCommandReadStatus {
|
|
|
16
16
|
windowStartedAt: string;
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
export interface GuildCommandInteractionRoute {
|
|
20
|
+
applicationId: string;
|
|
21
|
+
guildId: string | null;
|
|
22
|
+
commandGuildId: string | null;
|
|
23
|
+
commandId: string;
|
|
24
|
+
commandName: string;
|
|
25
|
+
}
|
|
19
26
|
export interface GuildCommandReadHandler {
|
|
20
27
|
getStatus(guildId: string): Promise<GuildCommandReadStatus>;
|
|
21
28
|
requestReconciliation(input: {
|
|
@@ -79,7 +86,7 @@ export interface GuildCommandReadHandler {
|
|
|
79
86
|
scheduledGuildCount: number;
|
|
80
87
|
}>;
|
|
81
88
|
}
|
|
82
|
-
type ReadCommandMethod = "getState" | "getActiveRequest" | "getCapacity" | "ensureState" | "schedule" | "recordStatusRefresh" | "changeVisibilityProfile" | "setMigrationHold" | "listHistory" | "getHealth";
|
|
89
|
+
type ReadCommandMethod = "getState" | "getActiveRequest" | "getCapacity" | "ensureState" | "schedule" | "recordStatusRefresh" | "changeVisibilityProfile" | "setMigrationHold" | "listHistory" | "getHealth" | "getRootMapping" | "isRetiredRootCommandId";
|
|
83
90
|
export interface GuildCommandReadRepositories {
|
|
84
91
|
commands: Pick<GuildCommandRepository, ReadCommandMethod> & Pick<MysqlGuildCommandRepository, ReadCommandMethod>;
|
|
85
92
|
installations: Pick<InstallationRepository, "listActiveGuildIdsWithEnabledModule"> & Pick<MysqlInstallationRepository, "listActiveGuildIdsWithEnabledModule">;
|
|
@@ -94,6 +101,8 @@ export declare class GuildCommandReadService implements GuildCommandReadHandler
|
|
|
94
101
|
private readonly writeAllGuilds;
|
|
95
102
|
private readonly modules;
|
|
96
103
|
constructor(databaseOrRepositories: Pool | GuildCommandReadRepositories, applicationId: string, workerHealth?: (() => Promise<GuildCommandWorkerHealth> | undefined) | undefined, discordToken?: string | undefined, guildCommandWritesEnabled?: boolean, writeGuildIds?: readonly string[], writeAllGuilds?: boolean, modules?: readonly ModuleDefinition[]);
|
|
104
|
+
/** Resolve only Discord-observed guild roots; desired settings never alias. */
|
|
105
|
+
resolveInteractionCommand(input: GuildCommandInteractionRoute): Promise<string | null>;
|
|
97
106
|
previewFirstTimeSetup(moduleIds: string[]): Promise<{
|
|
98
107
|
selectedModuleIds: string[];
|
|
99
108
|
rootCount: number;
|
|
@@ -31,6 +31,43 @@ export class GuildCommandReadService {
|
|
|
31
31
|
this.#repository = repositories.commands;
|
|
32
32
|
this.#installations = repositories.installations;
|
|
33
33
|
}
|
|
34
|
+
/** Resolve only Discord-observed guild roots; desired settings never alias. */
|
|
35
|
+
async resolveInteractionCommand(input) {
|
|
36
|
+
if (input.applicationId !== this.applicationId)
|
|
37
|
+
return null;
|
|
38
|
+
if (!input.guildId)
|
|
39
|
+
return input.commandName === "nexus" ? null : input.commandName;
|
|
40
|
+
if (typeof this.#repository.getRootMapping !== "function" ||
|
|
41
|
+
typeof this.#repository.isRetiredRootCommandId !== "function")
|
|
42
|
+
throw new Error("Guild command routing requires root mapping and retired ID capabilities");
|
|
43
|
+
const mapping = await this.#repository.getRootMapping(this.applicationId, input.guildId, "nexus");
|
|
44
|
+
if (mapping &&
|
|
45
|
+
(mapping.applicationId !== this.applicationId ||
|
|
46
|
+
mapping.guildId !== input.guildId ||
|
|
47
|
+
mapping.canonicalRoot !== "nexus"))
|
|
48
|
+
throw new Error("Guild command routing mapping has an invalid scope");
|
|
49
|
+
if (mapping && input.commandName === mapping.observedRoot) {
|
|
50
|
+
return mapping.observedCommandId &&
|
|
51
|
+
input.commandId === mapping.observedCommandId &&
|
|
52
|
+
input.commandGuildId === input.guildId
|
|
53
|
+
? "nexus"
|
|
54
|
+
: null;
|
|
55
|
+
}
|
|
56
|
+
// A Discord ID retained by an in-place rename still belongs to Nexus;
|
|
57
|
+
// a stale name cannot send that same ID to a newly registered owner.
|
|
58
|
+
if (mapping && input.commandId === mapping.observedCommandId)
|
|
59
|
+
return null;
|
|
60
|
+
// Only the exact active observed name/ID is accepted ahead of retirement.
|
|
61
|
+
// Reusing an old root name for another contribution cannot revive its ID.
|
|
62
|
+
if (mapping &&
|
|
63
|
+
(input.commandName === "nexus" ||
|
|
64
|
+
input.commandName === mapping.desiredRoot))
|
|
65
|
+
return null;
|
|
66
|
+
if (input.commandGuildId === input.guildId &&
|
|
67
|
+
(await this.#repository.isRetiredRootCommandId(this.applicationId, input.guildId, input.commandId)))
|
|
68
|
+
return null;
|
|
69
|
+
return input.commandName;
|
|
70
|
+
}
|
|
34
71
|
previewFirstTimeSetup(moduleIds) {
|
|
35
72
|
const requested = new Set(moduleIds);
|
|
36
73
|
const byId = new Map(this.modules.map((module) => [module.manifest.id, module]));
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { GuildCommandRepository, InstallationRepository, ModuleAvailabilityRepository, type GuildCommandHealth, type GuildCommandRequestRecord } from "@helyx/database";
|
|
2
2
|
import { type GuildCommandRepository as MysqlGuildCommandRepository, type InstallationRepository as MysqlInstallationRepository, type ModuleAvailabilityRepository as MysqlModuleAvailabilityRepository } from "@helyx/database-mysql";
|
|
3
3
|
import type { Logger, ModuleDefinition } from "@helyx/sdk";
|
|
4
|
+
import type { CommandRestrictionRecovery } from "@helyx/platform";
|
|
5
|
+
import type { CommandPolicyDeliveryGate } from "@helyx/database-contracts";
|
|
4
6
|
import type { Pool } from "pg";
|
|
5
7
|
import { type GuildCommandDiff, type GuildCommandProjection } from "./guild-command-projection.js";
|
|
6
8
|
import type { GuildCommandDiscordClient } from "./guild-command-discord-client.js";
|
|
@@ -10,7 +12,14 @@ export interface GuildCommandWorkerHealth extends GuildCommandHealth {
|
|
|
10
12
|
workerRunning: boolean;
|
|
11
13
|
activeCount: number;
|
|
12
14
|
}
|
|
13
|
-
|
|
15
|
+
export interface GuildCommandCataloguePort {
|
|
16
|
+
recheck(limit?: number): Promise<{
|
|
17
|
+
examined: number;
|
|
18
|
+
reset: number;
|
|
19
|
+
}>;
|
|
20
|
+
getReservedCommandNames(): Promise<readonly string[]>;
|
|
21
|
+
}
|
|
22
|
+
type WorkerCommandRepository = Pick<GuildCommandRepository, "claimDue" | "getHealth" | "heartbeat" | "getState" | "listRootMappings" | "completeDryRun" | "defer" | "markBlocked" | "markFailed" | "completeLive" | "isLeaseCurrent" | "reserveCreations" | "settleCreation" | "retireRootObservation" | "isRetiredRootCommandId"> & Pick<MysqlGuildCommandRepository, "claimDue" | "getHealth" | "heartbeat" | "getState" | "listRootMappings" | "completeDryRun" | "defer" | "markBlocked" | "markFailed" | "completeLive" | "isLeaseCurrent" | "reserveCreations" | "settleCreation" | "retireRootObservation" | "isRetiredRootCommandId">;
|
|
14
23
|
export interface GuildCommandWorkerRepositories {
|
|
15
24
|
commands: WorkerCommandRepository;
|
|
16
25
|
installations: Pick<InstallationRepository, "listEnabledModules"> & Pick<MysqlInstallationRepository, "listEnabledModules">;
|
|
@@ -27,10 +36,15 @@ export declare class GuildCommandWorker {
|
|
|
27
36
|
#private;
|
|
28
37
|
constructor(input: {
|
|
29
38
|
modules: readonly ModuleDefinition[];
|
|
39
|
+
commandRestrictions?: Pick<CommandRestrictionRecovery, "getPolicy" | "recheck">;
|
|
40
|
+
commandCatalogue?: GuildCommandCataloguePort;
|
|
41
|
+
commandPolicyDelivery?: {
|
|
42
|
+
readGate(): Promise<CommandPolicyDeliveryGate>;
|
|
43
|
+
};
|
|
30
44
|
logger: Logger;
|
|
31
45
|
workerId?: string;
|
|
32
46
|
fencingToken: bigint;
|
|
33
|
-
discord?: Pick<GuildCommandDiscordClient, "canWrite" | "observe" | "replace">;
|
|
47
|
+
discord?: Pick<GuildCommandDiscordClient, "canWrite" | "observe" | "replace" | "remove">;
|
|
34
48
|
internalGuildId?: string;
|
|
35
49
|
pollIntervalMs?: number;
|
|
36
50
|
leaseMs?: number;
|
|
@@ -43,10 +57,10 @@ export declare class GuildCommandWorker {
|
|
|
43
57
|
stop(): Promise<void>;
|
|
44
58
|
getHealth(): Promise<GuildCommandWorkerHealth>;
|
|
45
59
|
}
|
|
46
|
-
type LiveRepository = Pick<GuildCommandRepository, "completeLive" | "isLeaseCurrent" | "reserveCreations" | "settleCreation"> & Pick<MysqlGuildCommandRepository, "completeLive" | "isLeaseCurrent" | "reserveCreations" | "settleCreation">;
|
|
60
|
+
type LiveRepository = Pick<GuildCommandRepository, "completeLive" | "isLeaseCurrent" | "reserveCreations" | "settleCreation" | "retireRootObservation" | "isRetiredRootCommandId"> & Pick<MysqlGuildCommandRepository, "completeLive" | "isLeaseCurrent" | "reserveCreations" | "settleCreation" | "retireRootObservation" | "isRetiredRootCommandId">;
|
|
47
61
|
export declare function reconcileLiveGuildCommands(input: {
|
|
48
62
|
repository: LiveRepository;
|
|
49
|
-
discord: Pick<GuildCommandDiscordClient, "observe" | "replace">;
|
|
63
|
+
discord: Pick<GuildCommandDiscordClient, "observe" | "replace" | "remove">;
|
|
50
64
|
request: GuildCommandRequestRecord;
|
|
51
65
|
projection: GuildCommandProjection;
|
|
52
66
|
workerId: string;
|
|
@@ -54,6 +68,7 @@ export declare function reconcileLiveGuildCommands(input: {
|
|
|
54
68
|
leaseMs: number;
|
|
55
69
|
verificationDelayMs?: number;
|
|
56
70
|
signal?: AbortSignal;
|
|
71
|
+
validateWrite?(): Promise<void>;
|
|
57
72
|
}): Promise<{
|
|
58
73
|
outcome: "completed" | "stale" | "fenced";
|
|
59
74
|
diff: GuildCommandDiff;
|