@helyx/bot 0.4.15 → 0.4.17
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 +20 -0
- package/dist/events.d.ts +1 -22
- package/dist/events.js +0 -656
- package/dist/index.js +2 -3
- package/dist/shard-supervisor.js +5 -0
- package/dist/shard-worker.js +2 -3
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.17
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Remove the legacy Verification automatic setup interfaces and obsolete configuration field.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @helyx/database@0.7.0
|
|
10
|
+
- @helyx/verification-contracts@0.2.0
|
|
11
|
+
- @helyx/sdk@0.6.0
|
|
12
|
+
- @helyx/platform@0.4.1
|
|
13
|
+
- @helyx/core@0.1.13
|
|
14
|
+
- @helyx/framework@0.1.13
|
|
15
|
+
|
|
16
|
+
## 0.4.16
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Pass hosted Verification configuration into sharded worker processes so the
|
|
21
|
+
Verification service is available when shard mode is enabled.
|
|
22
|
+
|
|
3
23
|
## 0.4.15
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/events.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { DiscordChannelAudienceInspection, DiscordChannelInspection, DiscordEmojiInspection, DiscordMessageInspection, DiscordGuildCapabilityInspection, DiscordGuildChannelAudienceInspection, DiscordResourceInspectionService, DiscordRoleInspection, DiscordMessageService, MemberEnforcementService, MemberRoleService, ModuleDefinition, ServiceAccess, VerificationMemberService
|
|
2
|
-
import type { VerificationSetupRepository } from "@helyx/database";
|
|
1
|
+
import type { DiscordChannelAudienceInspection, DiscordChannelInspection, DiscordEmojiInspection, DiscordMessageInspection, DiscordGuildCapabilityInspection, DiscordGuildChannelAudienceInspection, DiscordResourceInspectionService, DiscordRoleInspection, DiscordMessageService, MemberEnforcementService, MemberRoleService, ModuleDefinition, ServiceAccess, VerificationMemberService } from "@helyx/sdk";
|
|
3
2
|
import { type Client, type MessageReaction, type PartialMessageReaction } from "discord.js";
|
|
4
3
|
import { type InteractionLogger } from "./interactions.js";
|
|
5
4
|
export declare function installModuleEvents(client: Client, modules: readonly ModuleDefinition[], logger: InteractionLogger, services: ServiceAccess): ModuleEventHandle;
|
|
@@ -35,26 +34,6 @@ export declare class DiscordVerificationMemberService implements VerificationMem
|
|
|
35
34
|
captureSnapshot(input: Parameters<VerificationMemberService["captureSnapshot"]>[0]): ReturnType<VerificationMemberService["captureSnapshot"]>;
|
|
36
35
|
isCurrentlyBanned(input: Parameters<VerificationMemberService["isCurrentlyBanned"]>[0]): ReturnType<VerificationMemberService["isCurrentlyBanned"]>;
|
|
37
36
|
}
|
|
38
|
-
/**
|
|
39
|
-
* The single Discord mutation boundary for Verification setup. It deliberately
|
|
40
|
-
* exposes a preview/apply protocol rather than raw role or overwrite writes.
|
|
41
|
-
*/
|
|
42
|
-
export declare class DiscordVerificationSetupService implements VerificationSetupService {
|
|
43
|
-
#private;
|
|
44
|
-
private readonly client;
|
|
45
|
-
private readonly persistence;
|
|
46
|
-
constructor(client: Client, persistence: VerificationSetupPersistence);
|
|
47
|
-
inspect(input: {
|
|
48
|
-
guildId: string;
|
|
49
|
-
}): Promise<VerificationSetupGuildInspection>;
|
|
50
|
-
preview(input: VerificationSetupRequest): Promise<VerificationSetupPreview>;
|
|
51
|
-
apply(input: VerificationSetupRequest & {
|
|
52
|
-
previewFingerprint: string;
|
|
53
|
-
confirmed: true;
|
|
54
|
-
}): Promise<Awaited<ReturnType<VerificationSetupService["apply"]>>>;
|
|
55
|
-
hideVerificationChannelForVerifiedMember(input: Parameters<VerificationSetupService["hideVerificationChannelForVerifiedMember"]>[0]): ReturnType<VerificationSetupService["hideVerificationChannelForVerifiedMember"]>;
|
|
56
|
-
}
|
|
57
|
-
export type VerificationSetupPersistence = Pick<VerificationSetupRepository, "begin" | "checkpointResources" | "checkpointOverwrites" | "complete" | "abort">;
|
|
58
37
|
export declare class DiscordMemberRoleService implements MemberRoleService {
|
|
59
38
|
private readonly client;
|
|
60
39
|
constructor(client: Client);
|
package/dist/events.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { HELYX_SERVICE_NAMES } from "@helyx/sdk";
|
|
2
|
-
import { VerificationSetupLeaseLostError } from "@helyx/database";
|
|
3
2
|
import { ChannelType, Events, GatewayIntentBits, GuildMemberFlags, GuildOnboardingMode, PermissionFlagsBits, RESTJSONErrorCodes, UserFlags, } from "discord.js";
|
|
4
3
|
import { toReplyOptions } from "./interactions.js";
|
|
5
4
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -918,661 +917,6 @@ export class DiscordVerificationMemberService {
|
|
|
918
917
|
}
|
|
919
918
|
}
|
|
920
919
|
}
|
|
921
|
-
const verificationSetupMaximumAccessTargets = 50;
|
|
922
|
-
const verificationSetupLeaseMs = 120_000;
|
|
923
|
-
const verificationRoleNameMaximum = 100;
|
|
924
|
-
const verificationChannelNamePattern = /^[a-z0-9][a-z0-9-_]{0,99}$/u;
|
|
925
|
-
const verificationMembershipScreeningFeature = "MEMBER_VERIFICATION_GATE_ENABLED";
|
|
926
|
-
/**
|
|
927
|
-
* The single Discord mutation boundary for Verification setup. It deliberately
|
|
928
|
-
* exposes a preview/apply protocol rather than raw role or overwrite writes.
|
|
929
|
-
*/
|
|
930
|
-
export class DiscordVerificationSetupService {
|
|
931
|
-
client;
|
|
932
|
-
persistence;
|
|
933
|
-
#guildLocks = new Map();
|
|
934
|
-
constructor(client, persistence) {
|
|
935
|
-
this.client = client;
|
|
936
|
-
this.persistence = persistence;
|
|
937
|
-
}
|
|
938
|
-
async inspect(input) {
|
|
939
|
-
validateSnowflake(input.guildId, "guild");
|
|
940
|
-
const guild = await this.client.guilds.fetch(input.guildId);
|
|
941
|
-
if (guild.id !== input.guildId)
|
|
942
|
-
throw new Error("Discord guild validation failed");
|
|
943
|
-
const me = guild.members.me ?? (await guild.members.fetchMe());
|
|
944
|
-
const permissions = {
|
|
945
|
-
viewChannel: me.permissions.has(PermissionFlagsBits.ViewChannel),
|
|
946
|
-
sendMessages: me.permissions.has(PermissionFlagsBits.SendMessages),
|
|
947
|
-
embedLinks: me.permissions.has(PermissionFlagsBits.EmbedLinks),
|
|
948
|
-
manageRoles: me.permissions.has(PermissionFlagsBits.ManageRoles),
|
|
949
|
-
manageChannels: me.permissions.has(PermissionFlagsBits.ManageChannels),
|
|
950
|
-
kickMembers: me.permissions.has(PermissionFlagsBits.KickMembers),
|
|
951
|
-
banMembers: me.permissions.has(PermissionFlagsBits.BanMembers),
|
|
952
|
-
administrator: me.permissions.has(PermissionFlagsBits.Administrator),
|
|
953
|
-
};
|
|
954
|
-
const membershipScreeningEnabled = guild.features.includes(verificationMembershipScreeningFeature);
|
|
955
|
-
try {
|
|
956
|
-
const onboarding = await guild.fetchOnboarding();
|
|
957
|
-
return {
|
|
958
|
-
guildId: guild.id,
|
|
959
|
-
permissions,
|
|
960
|
-
onboarding: {
|
|
961
|
-
status: onboarding.enabled ? "enabled" : "disabled",
|
|
962
|
-
mode: onboarding.mode === GuildOnboardingMode.OnboardingDefault
|
|
963
|
-
? "default"
|
|
964
|
-
: onboarding.mode === GuildOnboardingMode.OnboardingAdvanced
|
|
965
|
-
? "advanced"
|
|
966
|
-
: "unknown",
|
|
967
|
-
membershipScreeningEnabled,
|
|
968
|
-
defaultChannelIds: [...onboarding.defaultChannels.keys()]
|
|
969
|
-
.slice(0, verificationSetupMaximumAccessTargets)
|
|
970
|
-
.sort((left, right) => left.localeCompare(right, "en")),
|
|
971
|
-
unverifiedInteractionChannelRecommended: onboarding.enabled || membershipScreeningEnabled,
|
|
972
|
-
},
|
|
973
|
-
};
|
|
974
|
-
}
|
|
975
|
-
catch {
|
|
976
|
-
return {
|
|
977
|
-
guildId: guild.id,
|
|
978
|
-
permissions,
|
|
979
|
-
onboarding: {
|
|
980
|
-
status: "unavailable",
|
|
981
|
-
mode: "unknown",
|
|
982
|
-
membershipScreeningEnabled,
|
|
983
|
-
defaultChannelIds: [],
|
|
984
|
-
unverifiedInteractionChannelRecommended: membershipScreeningEnabled,
|
|
985
|
-
},
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
async preview(input) {
|
|
990
|
-
validateVerificationSetupRequest(input);
|
|
991
|
-
const guild = await this.client.guilds.fetch(input.guildId);
|
|
992
|
-
if (guild.id !== input.guildId)
|
|
993
|
-
throw new Error("Discord guild validation failed");
|
|
994
|
-
const me = guild.members.me ?? (await guild.members.fetchMe());
|
|
995
|
-
const [inspection, verifiedRole, verificationChannel] = await Promise.all([
|
|
996
|
-
this.inspect({ guildId: guild.id }),
|
|
997
|
-
resolveSetupRole(guild, me, input.verifiedRole),
|
|
998
|
-
resolveSetupChannel(guild, me, input.verificationChannel),
|
|
999
|
-
]);
|
|
1000
|
-
const accessOverwrites = await Promise.all(input.accessTargetIds.map(async (targetId) => {
|
|
1001
|
-
const channel = await fetchVerificationAccessTarget(guild, targetId);
|
|
1002
|
-
const current = verifiedRole.role
|
|
1003
|
-
? viewChannelOverwrite(channel, verifiedRole.role.id)
|
|
1004
|
-
: null;
|
|
1005
|
-
return {
|
|
1006
|
-
targetId: channel.id,
|
|
1007
|
-
targetType: verificationAccessTargetType(channel),
|
|
1008
|
-
action: current === true
|
|
1009
|
-
? "unchanged"
|
|
1010
|
-
: "set_verified_view",
|
|
1011
|
-
};
|
|
1012
|
-
}));
|
|
1013
|
-
const missingPermissions = verificationSetupMissingPermissions({
|
|
1014
|
-
inspection,
|
|
1015
|
-
me,
|
|
1016
|
-
verificationChannel,
|
|
1017
|
-
needsManageChannels: verificationChannel.action === "create" ||
|
|
1018
|
-
accessOverwrites.some(({ action }) => action !== "unchanged"),
|
|
1019
|
-
});
|
|
1020
|
-
const unsigned = {
|
|
1021
|
-
inspection,
|
|
1022
|
-
missingPermissions,
|
|
1023
|
-
verifiedRole: {
|
|
1024
|
-
action: verifiedRole.action,
|
|
1025
|
-
name: verifiedRole.name,
|
|
1026
|
-
...(verifiedRole.role ? { roleId: verifiedRole.role.id } : {}),
|
|
1027
|
-
manageable: verifiedRole.manageable,
|
|
1028
|
-
},
|
|
1029
|
-
verificationChannel: {
|
|
1030
|
-
action: verificationChannel.action,
|
|
1031
|
-
name: verificationChannel.name,
|
|
1032
|
-
...(verificationChannel.channel
|
|
1033
|
-
? { channelId: verificationChannel.channel.id }
|
|
1034
|
-
: {}),
|
|
1035
|
-
usable: verificationChannel.usable,
|
|
1036
|
-
},
|
|
1037
|
-
accessOverwrites,
|
|
1038
|
-
};
|
|
1039
|
-
return {
|
|
1040
|
-
fingerprint: verificationSetupFingerprint(input, unsigned),
|
|
1041
|
-
...unsigned,
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
async apply(input) {
|
|
1045
|
-
if (input.confirmed !== true)
|
|
1046
|
-
throw new Error("Verification setup requires explicit confirmation");
|
|
1047
|
-
if (!/^[a-f0-9]{64}$/u.test(input.previewFingerprint))
|
|
1048
|
-
throw new Error("Verification setup preview fingerprint is invalid");
|
|
1049
|
-
return this.#withGuildLock(input.guildId, async () => {
|
|
1050
|
-
const request = {
|
|
1051
|
-
guildId: input.guildId,
|
|
1052
|
-
verifiedRole: input.verifiedRole,
|
|
1053
|
-
verificationChannel: input.verificationChannel,
|
|
1054
|
-
accessTargetIds: input.accessTargetIds,
|
|
1055
|
-
};
|
|
1056
|
-
const preview = await this.preview(request);
|
|
1057
|
-
if (preview.fingerprint !== input.previewFingerprint)
|
|
1058
|
-
throw new Error("Verification setup changed after preview; review the new plan");
|
|
1059
|
-
if (preview.missingPermissions.length > 0)
|
|
1060
|
-
throw new Error(`Verification setup is missing permissions: ${preview.missingPermissions.join(", ")}`);
|
|
1061
|
-
if (!preview.verifiedRole.manageable)
|
|
1062
|
-
throw new Error("The verified role cannot be managed safely by Helyx");
|
|
1063
|
-
if (!preview.verificationChannel.usable)
|
|
1064
|
-
throw new Error("The verification channel is not usable by Helyx");
|
|
1065
|
-
const guild = await this.client.guilds.fetch(input.guildId);
|
|
1066
|
-
const reason = "Helyx Verification: confirmed setup plan";
|
|
1067
|
-
const leaseOwner = `hosted-bot:${randomUUID()}`;
|
|
1068
|
-
for (let claimAttempt = 0; claimAttempt < 2; claimAttempt += 1) {
|
|
1069
|
-
const claim = await this.persistence.begin({
|
|
1070
|
-
guildId: input.guildId,
|
|
1071
|
-
fingerprint: input.previewFingerprint,
|
|
1072
|
-
selectedTargetIds: input.accessTargetIds,
|
|
1073
|
-
leaseOwner,
|
|
1074
|
-
leaseMs: verificationSetupLeaseMs,
|
|
1075
|
-
});
|
|
1076
|
-
if (claim.kind === "applied")
|
|
1077
|
-
return claim.result;
|
|
1078
|
-
if (claim.kind === "busy")
|
|
1079
|
-
throw new Error("Another Verification setup operation is in progress");
|
|
1080
|
-
if (claim.kind === "recover") {
|
|
1081
|
-
await this.#recoverSetup(guild, claim.state, reason);
|
|
1082
|
-
await this.persistence.abort(claim.state);
|
|
1083
|
-
continue;
|
|
1084
|
-
}
|
|
1085
|
-
return this.#applyClaimedSetup(guild, preview, claim.state, reason);
|
|
1086
|
-
}
|
|
1087
|
-
throw new Error("Verification setup recovery did not converge");
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
async #applyClaimedSetup(guild, preview, initialState, reason) {
|
|
1091
|
-
let state = initialState;
|
|
1092
|
-
let uncheckpointedRole = null;
|
|
1093
|
-
let uncheckpointedChannel = null;
|
|
1094
|
-
try {
|
|
1095
|
-
let role = state.roleId ? await guild.roles.fetch(state.roleId) : null;
|
|
1096
|
-
if (!role) {
|
|
1097
|
-
if (preview.verifiedRole.action === "create") {
|
|
1098
|
-
role = await findPendingVerificationRole(guild, state.requestedFingerprint);
|
|
1099
|
-
if (!role)
|
|
1100
|
-
try {
|
|
1101
|
-
role = await guild.roles.create({
|
|
1102
|
-
name: verificationPendingRoleName(state.requestedFingerprint),
|
|
1103
|
-
permissions: [],
|
|
1104
|
-
reason,
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
catch (error) {
|
|
1108
|
-
role = await findPendingVerificationRole(guild, state.requestedFingerprint);
|
|
1109
|
-
if (!role)
|
|
1110
|
-
throw error;
|
|
1111
|
-
}
|
|
1112
|
-
uncheckpointedRole = role;
|
|
1113
|
-
state = await this.persistence.checkpointResources(state, { roleId: role.id, createdRole: true }, verificationSetupLeaseMs);
|
|
1114
|
-
uncheckpointedRole = null;
|
|
1115
|
-
if (role.name !== preview.verifiedRole.name)
|
|
1116
|
-
role = await role.setName(preview.verifiedRole.name, reason);
|
|
1117
|
-
}
|
|
1118
|
-
else {
|
|
1119
|
-
role = await guild.roles.fetch(preview.verifiedRole.roleId);
|
|
1120
|
-
if (role)
|
|
1121
|
-
state = await this.persistence.checkpointResources(state, { roleId: role.id, createdRole: false }, verificationSetupLeaseMs);
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
if (!role || role.guild.id !== guild.id)
|
|
1125
|
-
throw new Error("The verified role became unavailable during setup");
|
|
1126
|
-
let channel = state.channelId
|
|
1127
|
-
? await fetchVerificationTextChannel(guild, state.channelId)
|
|
1128
|
-
: null;
|
|
1129
|
-
if (!channel) {
|
|
1130
|
-
if (preview.verificationChannel.action === "create") {
|
|
1131
|
-
channel = await findPendingVerificationChannel(guild, state.requestedFingerprint);
|
|
1132
|
-
if (!channel)
|
|
1133
|
-
try {
|
|
1134
|
-
channel = await guild.channels.create({
|
|
1135
|
-
name: verificationPendingChannelName(state.requestedFingerprint),
|
|
1136
|
-
type: ChannelType.GuildText,
|
|
1137
|
-
reason,
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
catch (error) {
|
|
1141
|
-
channel = await findPendingVerificationChannel(guild, state.requestedFingerprint);
|
|
1142
|
-
if (!channel)
|
|
1143
|
-
throw error;
|
|
1144
|
-
}
|
|
1145
|
-
uncheckpointedChannel = channel;
|
|
1146
|
-
state = await this.persistence.checkpointResources(state, { channelId: channel.id, createdChannel: true }, verificationSetupLeaseMs);
|
|
1147
|
-
uncheckpointedChannel = null;
|
|
1148
|
-
if (channel.name !== preview.verificationChannel.name)
|
|
1149
|
-
channel = await channel.setName(preview.verificationChannel.name, reason);
|
|
1150
|
-
}
|
|
1151
|
-
else {
|
|
1152
|
-
channel = await fetchVerificationTextChannel(guild, preview.verificationChannel.channelId);
|
|
1153
|
-
if (channel)
|
|
1154
|
-
state = await this.persistence.checkpointResources(state, { channelId: channel.id, createdChannel: false }, verificationSetupLeaseMs);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
if (!channel || channel.guild.id !== guild.id)
|
|
1158
|
-
throw new Error("The verification channel became unavailable during setup");
|
|
1159
|
-
const desiredKeys = new Set(state.selectedTargetIds.map((targetId) => verificationManagedOverwriteKey(targetId, role.id)));
|
|
1160
|
-
const removesPreviousManagedOverwrite = state.managedOverwrites.some((overwrite) => !desiredKeys.has(verificationManagedOverwriteKey(overwrite.targetId, overwrite.roleId)));
|
|
1161
|
-
await assertVerificationSetupStillSafe(guild, role, channel, {
|
|
1162
|
-
needsManageChannels: state.createdChannel ||
|
|
1163
|
-
removesPreviousManagedOverwrite ||
|
|
1164
|
-
preview.accessOverwrites.some(({ action }) => action !== "unchanged"),
|
|
1165
|
-
});
|
|
1166
|
-
for (const overwrite of [...state.managedOverwrites]) {
|
|
1167
|
-
const key = verificationManagedOverwriteKey(overwrite.targetId, overwrite.roleId);
|
|
1168
|
-
if (desiredKeys.has(key))
|
|
1169
|
-
continue;
|
|
1170
|
-
state = await this.#checkpointOverwriteState(state, {
|
|
1171
|
-
...overwrite,
|
|
1172
|
-
status: "restoring",
|
|
1173
|
-
});
|
|
1174
|
-
await restoreVerificationViewOverwrite(guild, overwrite, reason);
|
|
1175
|
-
state = await this.#removeCheckpointedOverwrite(state, key);
|
|
1176
|
-
}
|
|
1177
|
-
for (const targetId of state.selectedTargetIds) {
|
|
1178
|
-
const target = await fetchVerificationAccessTarget(guild, targetId);
|
|
1179
|
-
const key = verificationManagedOverwriteKey(target.id, role.id);
|
|
1180
|
-
let tracked = state.managedOverwrites.find((overwrite) => verificationManagedOverwriteKey(overwrite.targetId, overwrite.roleId) === key);
|
|
1181
|
-
const current = viewChannelOverwrite(target, role.id);
|
|
1182
|
-
if (!tracked && current === true)
|
|
1183
|
-
continue;
|
|
1184
|
-
if (!tracked) {
|
|
1185
|
-
tracked = {
|
|
1186
|
-
targetId: target.id,
|
|
1187
|
-
roleId: role.id,
|
|
1188
|
-
previousView: current,
|
|
1189
|
-
status: "planned",
|
|
1190
|
-
};
|
|
1191
|
-
state = await this.#checkpointOverwriteState(state, tracked);
|
|
1192
|
-
}
|
|
1193
|
-
else if (tracked.status !== "planned" && current !== true) {
|
|
1194
|
-
tracked = { ...tracked, status: "planned" };
|
|
1195
|
-
state = await this.#checkpointOverwriteState(state, tracked);
|
|
1196
|
-
}
|
|
1197
|
-
if (current !== true) {
|
|
1198
|
-
await target.permissionOverwrites.edit(role, { ViewChannel: true }, { reason });
|
|
1199
|
-
}
|
|
1200
|
-
tracked = { ...tracked, status: "applied" };
|
|
1201
|
-
state = await this.#checkpointOverwriteState(state, tracked, current === true ? undefined : target.id);
|
|
1202
|
-
}
|
|
1203
|
-
return this.persistence.complete(state, {
|
|
1204
|
-
verifiedRoleId: role.id,
|
|
1205
|
-
verificationChannelId: channel.id,
|
|
1206
|
-
createdRole: state.createdRole,
|
|
1207
|
-
createdChannel: state.createdChannel,
|
|
1208
|
-
changedAccessTargetIds: state.changedTargetIds,
|
|
1209
|
-
});
|
|
1210
|
-
}
|
|
1211
|
-
catch (error) {
|
|
1212
|
-
if (error instanceof VerificationSetupLeaseLostError)
|
|
1213
|
-
throw error;
|
|
1214
|
-
const rollbackFailures = [];
|
|
1215
|
-
for (const resource of [uncheckpointedChannel, uncheckpointedRole]) {
|
|
1216
|
-
if (!resource)
|
|
1217
|
-
continue;
|
|
1218
|
-
try {
|
|
1219
|
-
await resource.delete(`${reason} rollback`);
|
|
1220
|
-
}
|
|
1221
|
-
catch (rollbackError) {
|
|
1222
|
-
rollbackFailures.push(rollbackError);
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
try {
|
|
1226
|
-
await this.#recoverSetup(guild, state, `${reason} rollback`);
|
|
1227
|
-
await this.persistence.abort(state);
|
|
1228
|
-
}
|
|
1229
|
-
catch (rollbackError) {
|
|
1230
|
-
rollbackFailures.push(rollbackError);
|
|
1231
|
-
}
|
|
1232
|
-
if (rollbackFailures.length > 0)
|
|
1233
|
-
throw new AggregateError(rollbackFailures, "Verification setup failed and rollback was incomplete", { cause: error });
|
|
1234
|
-
throw error;
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
async #recoverSetup(guild, state, reason) {
|
|
1238
|
-
const applied = new Map(state.appliedManagedOverwrites.map((overwrite) => [
|
|
1239
|
-
verificationManagedOverwriteKey(overwrite.targetId, overwrite.roleId),
|
|
1240
|
-
overwrite,
|
|
1241
|
-
]));
|
|
1242
|
-
for (const pending of state.managedOverwrites) {
|
|
1243
|
-
const key = verificationManagedOverwriteKey(pending.targetId, pending.roleId);
|
|
1244
|
-
if (applied.has(key)) {
|
|
1245
|
-
await setVerificationViewOverwrite(guild, pending.targetId, pending.roleId, true, reason);
|
|
1246
|
-
applied.delete(key);
|
|
1247
|
-
}
|
|
1248
|
-
else {
|
|
1249
|
-
await restoreVerificationViewOverwrite(guild, pending, reason);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
for (const previous of applied.values()) {
|
|
1253
|
-
await setVerificationViewOverwrite(guild, previous.targetId, previous.roleId, true, reason);
|
|
1254
|
-
}
|
|
1255
|
-
const appliedResult = state.appliedResult;
|
|
1256
|
-
if (state.createdChannel &&
|
|
1257
|
-
state.channelId &&
|
|
1258
|
-
state.channelId !== appliedResult?.verificationChannelId) {
|
|
1259
|
-
const createdChannel = await guild.channels.fetch(state.channelId);
|
|
1260
|
-
if (createdChannel)
|
|
1261
|
-
await createdChannel.delete(reason);
|
|
1262
|
-
}
|
|
1263
|
-
if (state.createdRole &&
|
|
1264
|
-
state.roleId &&
|
|
1265
|
-
state.roleId !== appliedResult?.verifiedRoleId) {
|
|
1266
|
-
const createdRole = await guild.roles.fetch(state.roleId);
|
|
1267
|
-
if (createdRole)
|
|
1268
|
-
await createdRole.delete(reason);
|
|
1269
|
-
}
|
|
1270
|
-
const pendingChannel = await findPendingVerificationChannel(guild, state.requestedFingerprint);
|
|
1271
|
-
if (pendingChannel &&
|
|
1272
|
-
pendingChannel.id !== appliedResult?.verificationChannelId)
|
|
1273
|
-
await pendingChannel.delete(reason);
|
|
1274
|
-
const pendingRole = await findPendingVerificationRole(guild, state.requestedFingerprint);
|
|
1275
|
-
if (pendingRole && pendingRole.id !== appliedResult?.verifiedRoleId)
|
|
1276
|
-
await pendingRole.delete(reason);
|
|
1277
|
-
}
|
|
1278
|
-
async #checkpointOverwriteState(state, overwrite, changedTargetId) {
|
|
1279
|
-
const key = verificationManagedOverwriteKey(overwrite.targetId, overwrite.roleId);
|
|
1280
|
-
const next = state.managedOverwrites.filter((existing) => verificationManagedOverwriteKey(existing.targetId, existing.roleId) !==
|
|
1281
|
-
key);
|
|
1282
|
-
next.push(overwrite);
|
|
1283
|
-
const changed = changedTargetId
|
|
1284
|
-
? [...new Set([...state.changedTargetIds, changedTargetId])]
|
|
1285
|
-
: state.changedTargetIds;
|
|
1286
|
-
return this.persistence.checkpointOverwrites(state, next, changed, verificationSetupLeaseMs);
|
|
1287
|
-
}
|
|
1288
|
-
#removeCheckpointedOverwrite(state, key) {
|
|
1289
|
-
return this.persistence.checkpointOverwrites(state, state.managedOverwrites.filter((overwrite) => verificationManagedOverwriteKey(overwrite.targetId, overwrite.roleId) !== key), state.changedTargetIds, verificationSetupLeaseMs);
|
|
1290
|
-
}
|
|
1291
|
-
async hideVerificationChannelForVerifiedMember(input) {
|
|
1292
|
-
validateMutationMetadata({
|
|
1293
|
-
guildId: input.guildId,
|
|
1294
|
-
memberUserId: input.memberUserId,
|
|
1295
|
-
roleId: input.verifiedRoleId,
|
|
1296
|
-
moduleId: input.moduleId,
|
|
1297
|
-
reason: input.reason,
|
|
1298
|
-
});
|
|
1299
|
-
validateSnowflake(input.channelId, "channel");
|
|
1300
|
-
const guild = await this.client.guilds.fetch(input.guildId);
|
|
1301
|
-
const [member, role, fetchedChannel] = await Promise.all([
|
|
1302
|
-
guild.members.fetch(input.memberUserId),
|
|
1303
|
-
guild.roles.fetch(input.verifiedRoleId),
|
|
1304
|
-
guild.channels.fetch(input.channelId),
|
|
1305
|
-
]);
|
|
1306
|
-
if (!role || role.guild.id !== guild.id)
|
|
1307
|
-
throw new Error("The verified role is unavailable");
|
|
1308
|
-
if (!fetchedChannel ||
|
|
1309
|
-
fetchedChannel.guild.id !== guild.id ||
|
|
1310
|
-
fetchedChannel.type !== ChannelType.GuildText)
|
|
1311
|
-
throw new Error("The verification channel is unavailable");
|
|
1312
|
-
if (!member.roles.cache.has(role.id))
|
|
1313
|
-
throw new Error("The member does not hold the verified role");
|
|
1314
|
-
const me = guild.members.me ?? (await guild.members.fetchMe());
|
|
1315
|
-
if (!me.permissions.has(PermissionFlagsBits.ManageChannels))
|
|
1316
|
-
throw new Error("Helyx requires Manage Channels to hide this channel");
|
|
1317
|
-
if (!verificationRoleManageable(role, guild, me))
|
|
1318
|
-
throw new Error("The verified role cannot be managed safely by Helyx");
|
|
1319
|
-
if (viewChannelOverwrite(fetchedChannel, role.id) === false)
|
|
1320
|
-
return { changed: false };
|
|
1321
|
-
await fetchedChannel.permissionOverwrites.edit(role, { ViewChannel: false }, { reason: discordAuditReason(input) });
|
|
1322
|
-
return { changed: true };
|
|
1323
|
-
}
|
|
1324
|
-
async #withGuildLock(guildId, operation) {
|
|
1325
|
-
validateSnowflake(guildId, "guild");
|
|
1326
|
-
const previous = this.#guildLocks.get(guildId) ?? Promise.resolve();
|
|
1327
|
-
let release;
|
|
1328
|
-
const gate = new Promise((resolve) => {
|
|
1329
|
-
release = resolve;
|
|
1330
|
-
});
|
|
1331
|
-
const current = previous.catch(() => undefined).then(() => gate);
|
|
1332
|
-
this.#guildLocks.set(guildId, current);
|
|
1333
|
-
await previous.catch(() => undefined);
|
|
1334
|
-
try {
|
|
1335
|
-
return await operation();
|
|
1336
|
-
}
|
|
1337
|
-
finally {
|
|
1338
|
-
release();
|
|
1339
|
-
if (this.#guildLocks.get(guildId) === current)
|
|
1340
|
-
this.#guildLocks.delete(guildId);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
async function resolveSetupRole(guild, me, selection) {
|
|
1345
|
-
if (selection.mode === "create") {
|
|
1346
|
-
const role = selection.trackedRoleId
|
|
1347
|
-
? await guild.roles.fetch(selection.trackedRoleId)
|
|
1348
|
-
: null;
|
|
1349
|
-
if (!role)
|
|
1350
|
-
return {
|
|
1351
|
-
action: "create",
|
|
1352
|
-
name: selection.name,
|
|
1353
|
-
role: null,
|
|
1354
|
-
manageable: me.permissions.has(PermissionFlagsBits.ManageRoles),
|
|
1355
|
-
};
|
|
1356
|
-
return {
|
|
1357
|
-
action: "reuse",
|
|
1358
|
-
name: role.name,
|
|
1359
|
-
role,
|
|
1360
|
-
manageable: verificationRoleManageable(role, guild, me),
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
const role = await guild.roles.fetch(selection.roleId);
|
|
1364
|
-
if (!role || role.guild.id !== guild.id)
|
|
1365
|
-
throw new Error("The selected verified role is unavailable");
|
|
1366
|
-
return {
|
|
1367
|
-
action: "select",
|
|
1368
|
-
name: role.name,
|
|
1369
|
-
role,
|
|
1370
|
-
manageable: verificationRoleManageable(role, guild, me),
|
|
1371
|
-
};
|
|
1372
|
-
}
|
|
1373
|
-
async function resolveSetupChannel(guild, me, selection) {
|
|
1374
|
-
if (selection.mode === "create") {
|
|
1375
|
-
const fetched = selection.trackedChannelId
|
|
1376
|
-
? await guild.channels.fetch(selection.trackedChannelId)
|
|
1377
|
-
: null;
|
|
1378
|
-
if (!fetched)
|
|
1379
|
-
return {
|
|
1380
|
-
action: "create",
|
|
1381
|
-
name: selection.name,
|
|
1382
|
-
channel: null,
|
|
1383
|
-
usable: me.permissions.has(PermissionFlagsBits.ViewChannel) &&
|
|
1384
|
-
me.permissions.has(PermissionFlagsBits.SendMessages) &&
|
|
1385
|
-
me.permissions.has(PermissionFlagsBits.EmbedLinks) &&
|
|
1386
|
-
me.permissions.has(PermissionFlagsBits.ManageChannels),
|
|
1387
|
-
};
|
|
1388
|
-
if (fetched.type !== ChannelType.GuildText)
|
|
1389
|
-
throw new Error("The tracked verification channel is not a text channel");
|
|
1390
|
-
return {
|
|
1391
|
-
action: "reuse",
|
|
1392
|
-
name: fetched.name,
|
|
1393
|
-
channel: fetched,
|
|
1394
|
-
usable: verificationChannelUsable(fetched, me),
|
|
1395
|
-
};
|
|
1396
|
-
}
|
|
1397
|
-
const fetched = await guild.channels.fetch(selection.channelId);
|
|
1398
|
-
if (!fetched || fetched.guild.id !== guild.id)
|
|
1399
|
-
throw new Error("The selected verification channel is unavailable");
|
|
1400
|
-
if (fetched.type !== ChannelType.GuildText)
|
|
1401
|
-
throw new Error("The selected verification channel is not a text channel");
|
|
1402
|
-
return {
|
|
1403
|
-
action: "select",
|
|
1404
|
-
name: fetched.name,
|
|
1405
|
-
channel: fetched,
|
|
1406
|
-
usable: verificationChannelUsable(fetched, me),
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
function verificationChannelUsable(channel, me) {
|
|
1410
|
-
const effective = channel.permissionsFor(me);
|
|
1411
|
-
return Boolean(effective?.has(PermissionFlagsBits.ViewChannel) &&
|
|
1412
|
-
effective.has(PermissionFlagsBits.SendMessages) &&
|
|
1413
|
-
effective.has(PermissionFlagsBits.EmbedLinks));
|
|
1414
|
-
}
|
|
1415
|
-
function verificationRoleManageable(role, guild, me) {
|
|
1416
|
-
return (role.guild.id === guild.id &&
|
|
1417
|
-
role.id !== guild.id &&
|
|
1418
|
-
!role.managed &&
|
|
1419
|
-
!role.permissions.has(PermissionFlagsBits.Administrator) &&
|
|
1420
|
-
me.permissions.has(PermissionFlagsBits.ManageRoles) &&
|
|
1421
|
-
role.comparePositionTo(me.roles.highest) < 0);
|
|
1422
|
-
}
|
|
1423
|
-
async function fetchVerificationAccessTarget(guild, targetId) {
|
|
1424
|
-
const channel = await guild.channels.fetch(targetId);
|
|
1425
|
-
if (!channel || channel.guild.id !== guild.id)
|
|
1426
|
-
throw new Error("A selected verification access target is unavailable");
|
|
1427
|
-
if (channel.type !== ChannelType.GuildText &&
|
|
1428
|
-
channel.type !== ChannelType.GuildAnnouncement &&
|
|
1429
|
-
channel.type !== ChannelType.GuildCategory)
|
|
1430
|
-
throw new Error("Verification access targets must be text channels or categories");
|
|
1431
|
-
return channel;
|
|
1432
|
-
}
|
|
1433
|
-
async function fetchVerificationTextChannel(guild, channelId) {
|
|
1434
|
-
const channel = await guild.channels.fetch(channelId);
|
|
1435
|
-
return channel?.guild.id === guild.id &&
|
|
1436
|
-
channel.type === ChannelType.GuildText
|
|
1437
|
-
? channel
|
|
1438
|
-
: null;
|
|
1439
|
-
}
|
|
1440
|
-
function verificationPendingRoleName(fingerprint) {
|
|
1441
|
-
return `Helyx verify pending ${fingerprint.slice(0, 12)}`;
|
|
1442
|
-
}
|
|
1443
|
-
function verificationPendingChannelName(fingerprint) {
|
|
1444
|
-
return `helyx-verify-pending-${fingerprint.slice(0, 12)}`;
|
|
1445
|
-
}
|
|
1446
|
-
async function findPendingVerificationRole(guild, fingerprint) {
|
|
1447
|
-
const expectedName = verificationPendingRoleName(fingerprint);
|
|
1448
|
-
const roles = await guild.roles.fetch();
|
|
1449
|
-
return roles.find((role) => role.name === expectedName) ?? null;
|
|
1450
|
-
}
|
|
1451
|
-
async function findPendingVerificationChannel(guild, fingerprint) {
|
|
1452
|
-
const expectedName = verificationPendingChannelName(fingerprint);
|
|
1453
|
-
const channels = await guild.channels.fetch();
|
|
1454
|
-
const channel = channels.find((candidate) => candidate !== null &&
|
|
1455
|
-
candidate.type === ChannelType.GuildText &&
|
|
1456
|
-
candidate.name === expectedName);
|
|
1457
|
-
return channel?.type === ChannelType.GuildText ? channel : null;
|
|
1458
|
-
}
|
|
1459
|
-
function verificationManagedOverwriteKey(targetId, roleId) {
|
|
1460
|
-
return `${targetId}:${roleId}`;
|
|
1461
|
-
}
|
|
1462
|
-
async function restoreVerificationViewOverwrite(guild, overwrite, reason) {
|
|
1463
|
-
await setVerificationViewOverwrite(guild, overwrite.targetId, overwrite.roleId, overwrite.previousView, reason);
|
|
1464
|
-
}
|
|
1465
|
-
async function setVerificationViewOverwrite(guild, targetId, roleId, viewChannel, reason) {
|
|
1466
|
-
const [fetched, role] = await Promise.all([
|
|
1467
|
-
guild.channels.fetch(targetId),
|
|
1468
|
-
guild.roles.fetch(roleId),
|
|
1469
|
-
]);
|
|
1470
|
-
if (!fetched || !role)
|
|
1471
|
-
return;
|
|
1472
|
-
if (fetched.guild.id !== guild.id ||
|
|
1473
|
-
(fetched.type !== ChannelType.GuildText &&
|
|
1474
|
-
fetched.type !== ChannelType.GuildAnnouncement &&
|
|
1475
|
-
fetched.type !== ChannelType.GuildCategory))
|
|
1476
|
-
throw new Error("A tracked verification access target is invalid");
|
|
1477
|
-
if (viewChannelOverwrite(fetched, roleId) === viewChannel)
|
|
1478
|
-
return;
|
|
1479
|
-
await fetched.permissionOverwrites.edit(roleId, { ViewChannel: viewChannel }, { reason });
|
|
1480
|
-
}
|
|
1481
|
-
function verificationAccessTargetType(channel) {
|
|
1482
|
-
if (channel.type === ChannelType.GuildCategory)
|
|
1483
|
-
return "category";
|
|
1484
|
-
if (channel.type === ChannelType.GuildAnnouncement)
|
|
1485
|
-
return "announcement";
|
|
1486
|
-
return "text";
|
|
1487
|
-
}
|
|
1488
|
-
function viewChannelOverwrite(channel, roleId) {
|
|
1489
|
-
const overwrite = channel.permissionOverwrites.cache.get(roleId);
|
|
1490
|
-
if (!overwrite)
|
|
1491
|
-
return null;
|
|
1492
|
-
if (overwrite.allow.has(PermissionFlagsBits.ViewChannel))
|
|
1493
|
-
return true;
|
|
1494
|
-
if (overwrite.deny.has(PermissionFlagsBits.ViewChannel))
|
|
1495
|
-
return false;
|
|
1496
|
-
return null;
|
|
1497
|
-
}
|
|
1498
|
-
function verificationSetupMissingPermissions(input) {
|
|
1499
|
-
const missing = [];
|
|
1500
|
-
const effective = input.verificationChannel.channel?.permissionsFor(input.me);
|
|
1501
|
-
const has = (permission, guildFallback) => effective ? effective.has(permission) : guildFallback;
|
|
1502
|
-
if (!has(PermissionFlagsBits.ViewChannel, input.inspection.permissions.viewChannel))
|
|
1503
|
-
missing.push("ViewChannel");
|
|
1504
|
-
if (!has(PermissionFlagsBits.SendMessages, input.inspection.permissions.sendMessages))
|
|
1505
|
-
missing.push("SendMessages");
|
|
1506
|
-
if (!has(PermissionFlagsBits.EmbedLinks, input.inspection.permissions.embedLinks))
|
|
1507
|
-
missing.push("EmbedLinks");
|
|
1508
|
-
if (!input.inspection.permissions.manageRoles)
|
|
1509
|
-
missing.push("ManageRoles");
|
|
1510
|
-
if (input.needsManageChannels && !input.inspection.permissions.manageChannels)
|
|
1511
|
-
missing.push("ManageChannels");
|
|
1512
|
-
return missing;
|
|
1513
|
-
}
|
|
1514
|
-
async function assertVerificationSetupStillSafe(guild, role, channel, input) {
|
|
1515
|
-
const me = guild.members.me ?? (await guild.members.fetchMe());
|
|
1516
|
-
if (!verificationRoleManageable(role, guild, me))
|
|
1517
|
-
throw new Error("The verified role is no longer manageable by Helyx");
|
|
1518
|
-
if (!verificationChannelUsable(channel, me))
|
|
1519
|
-
throw new Error("The verification channel is no longer usable by Helyx");
|
|
1520
|
-
if (input.needsManageChannels &&
|
|
1521
|
-
!me.permissions.has(PermissionFlagsBits.ManageChannels))
|
|
1522
|
-
throw new Error("Helyx no longer has Manage Channels");
|
|
1523
|
-
}
|
|
1524
|
-
function validateVerificationSetupRequest(input) {
|
|
1525
|
-
validateSnowflake(input.guildId, "guild");
|
|
1526
|
-
if (input.verifiedRole.mode === "existing")
|
|
1527
|
-
validateSnowflake(input.verifiedRole.roleId, "verified role");
|
|
1528
|
-
else {
|
|
1529
|
-
validateVerificationRoleName(input.verifiedRole.name);
|
|
1530
|
-
if (input.verifiedRole.trackedRoleId)
|
|
1531
|
-
validateSnowflake(input.verifiedRole.trackedRoleId, "tracked role");
|
|
1532
|
-
}
|
|
1533
|
-
if (input.verificationChannel.mode === "existing")
|
|
1534
|
-
validateSnowflake(input.verificationChannel.channelId, "verification channel");
|
|
1535
|
-
else {
|
|
1536
|
-
if (!verificationChannelNamePattern.test(input.verificationChannel.name))
|
|
1537
|
-
throw new Error("Verification channel name is invalid");
|
|
1538
|
-
if (input.verificationChannel.trackedChannelId)
|
|
1539
|
-
validateSnowflake(input.verificationChannel.trackedChannelId, "tracked channel");
|
|
1540
|
-
}
|
|
1541
|
-
if (input.accessTargetIds.length > verificationSetupMaximumAccessTargets ||
|
|
1542
|
-
new Set(input.accessTargetIds).size !== input.accessTargetIds.length)
|
|
1543
|
-
throw new Error("Verification access targets must be unique and bounded");
|
|
1544
|
-
for (const targetId of input.accessTargetIds)
|
|
1545
|
-
validateSnowflake(targetId, "access target");
|
|
1546
|
-
}
|
|
1547
|
-
function validateVerificationRoleName(name) {
|
|
1548
|
-
const normalized = name.trim();
|
|
1549
|
-
if (normalized.length === 0 ||
|
|
1550
|
-
normalized.length > verificationRoleNameMaximum ||
|
|
1551
|
-
/[\r\n]/u.test(normalized) ||
|
|
1552
|
-
normalized === "@everyone" ||
|
|
1553
|
-
normalized === "@here")
|
|
1554
|
-
throw new Error("Verification role name is invalid");
|
|
1555
|
-
}
|
|
1556
|
-
function verificationSetupFingerprint(request, preview) {
|
|
1557
|
-
return createHash("sha256")
|
|
1558
|
-
.update(stableVerificationSetupJson({
|
|
1559
|
-
protocol: "helyx-verification-setup-v1",
|
|
1560
|
-
request,
|
|
1561
|
-
preview,
|
|
1562
|
-
}))
|
|
1563
|
-
.digest("hex");
|
|
1564
|
-
}
|
|
1565
|
-
function stableVerificationSetupJson(value) {
|
|
1566
|
-
if (value === null || typeof value !== "object")
|
|
1567
|
-
return JSON.stringify(value);
|
|
1568
|
-
if (Array.isArray(value))
|
|
1569
|
-
return `[${value.map(stableVerificationSetupJson).join(",")}]`;
|
|
1570
|
-
const record = value;
|
|
1571
|
-
return `{${Object.keys(record)
|
|
1572
|
-
.sort((left, right) => left.localeCompare(right, "en"))
|
|
1573
|
-
.map((key) => `${JSON.stringify(key)}:${stableVerificationSetupJson(record[key])}`)
|
|
1574
|
-
.join(",")}}`;
|
|
1575
|
-
}
|
|
1576
920
|
export class DiscordMemberRoleService {
|
|
1577
921
|
client;
|
|
1578
922
|
constructor(client) {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseBotEnvironment } from "@helyx/config";
|
|
2
2
|
import { safeError, ServiceRegistry } from "@helyx/core";
|
|
3
|
-
import { checkDatabaseConnection, createDatabasePool, AuditRepository, InteractionSessionRepository, RateLimitRepository, runCoreMigrations, runConfiguredModuleMigrations,
|
|
3
|
+
import { checkDatabaseConnection, createDatabasePool, AuditRepository, InteractionSessionRepository, RateLimitRepository, runCoreMigrations, runConfiguredModuleMigrations, } from "@helyx/database";
|
|
4
4
|
import { createRuntime } from "@helyx/framework";
|
|
5
5
|
import { createPlatformServices, PostgresPrivacyProviderExecutor, } from "@helyx/platform";
|
|
6
6
|
import { HELYX_SERVICE_NAMES, } from "@helyx/sdk";
|
|
@@ -18,7 +18,7 @@ import { loadConfiguredModulePackages, platformServiceOptions, } from "./modules
|
|
|
18
18
|
import { resolveModulePackageSpecifiers } from "./module-configuration.js";
|
|
19
19
|
import { createPermissionsModule } from "./permissions-module.js";
|
|
20
20
|
import { createManagementModule } from "./management-module.js";
|
|
21
|
-
import { DiscordMessageDeliveryService, DiscordMemberEnforcementService, DiscordMemberRoleService, DiscordVerificationMemberService,
|
|
21
|
+
import { DiscordMessageDeliveryService, DiscordMemberEnforcementService, DiscordMemberRoleService, DiscordVerificationMemberService, DiscordResourceInspection, installModuleEvents, } from "./events.js";
|
|
22
22
|
import { DiscordModuleLoggingService } from "./module-logging.js";
|
|
23
23
|
import { BotControlService, createBotControlServer, DiscordGuildResourceDirectory, } from "./control-server.js";
|
|
24
24
|
import { HttpVerificationService } from "./verification-service.js";
|
|
@@ -256,7 +256,6 @@ async function startUnshardedBot(processEnvironment) {
|
|
|
256
256
|
publicSigningKeys: environment.HELYX_VERIFICATION_SIGNING_PUBLIC_KEYS,
|
|
257
257
|
}));
|
|
258
258
|
platformServices.set(HELYX_SERVICE_NAMES.verificationMembers, new DiscordVerificationMemberService(client));
|
|
259
|
-
platformServices.set(HELYX_SERVICE_NAMES.verificationSetup, new DiscordVerificationSetupService(client, new VerificationSetupRepository(database)));
|
|
260
259
|
}
|
|
261
260
|
const numericWriteBehind = createLocalNumericWriteBehind(platformServices, publicModules);
|
|
262
261
|
platformServices.set(HELYX_SERVICE_NAMES.numericWriteBehind, numericWriteBehind);
|
package/dist/shard-supervisor.js
CHANGED
|
@@ -1380,6 +1380,11 @@ export function buildShardWorkerEnvironment(source, identity, restartCount) {
|
|
|
1380
1380
|
"HELYX_MODULE_CATALOGUE_PATH",
|
|
1381
1381
|
"HELYX_CLOUD_CONNECT_ENABLED",
|
|
1382
1382
|
"HELYX_OWNER_USER_IDS",
|
|
1383
|
+
"HELYX_VERIFICATION_ENABLED",
|
|
1384
|
+
"HELYX_VERIFICATION_INSTALLATION_ID",
|
|
1385
|
+
"HELYX_VERIFICATION_URL",
|
|
1386
|
+
"HELYX_VERIFICATION_INTERNAL_SECRET",
|
|
1387
|
+
"HELYX_VERIFICATION_SIGNING_PUBLIC_KEYS",
|
|
1383
1388
|
"APPROVED_ROLES",
|
|
1384
1389
|
"RAILWAY_GIT_COMMIT_SHA",
|
|
1385
1390
|
"HELYX_SHARD_MODE",
|
package/dist/shard-worker.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseBotEnvironment } from "@helyx/config";
|
|
2
2
|
import { safeError, ServiceRegistry } from "@helyx/core";
|
|
3
|
-
import { checkDatabaseConnection, createDatabasePool
|
|
3
|
+
import { checkDatabaseConnection, createDatabasePool } from "@helyx/database";
|
|
4
4
|
import { createRuntime } from "@helyx/framework";
|
|
5
5
|
import { createPlatformServices } from "@helyx/platform";
|
|
6
6
|
import { HELYX_SERVICE_NAMES } from "@helyx/sdk";
|
|
@@ -10,7 +10,7 @@ import pino from "pino";
|
|
|
10
10
|
import { createCloudManagementModule } from "./cloud-management-module.js";
|
|
11
11
|
import { BotControlService, DiscordGuildResourceDirectory, mapBotControlError, } from "./control-server.js";
|
|
12
12
|
import { HttpVerificationService } from "./verification-service.js";
|
|
13
|
-
import { DiscordMessageDeliveryService, DiscordMemberEnforcementService, DiscordMemberRoleService, DiscordVerificationMemberService,
|
|
13
|
+
import { DiscordMessageDeliveryService, DiscordMemberEnforcementService, DiscordMemberRoleService, DiscordVerificationMemberService, DiscordResourceInspection, installModuleEvents, } from "./events.js";
|
|
14
14
|
import { installGuildTracking, } from "./guilds.js";
|
|
15
15
|
import { installInteractions, } from "./interactions.js";
|
|
16
16
|
import { createManagementModule } from "./management-module.js";
|
|
@@ -181,7 +181,6 @@ export async function startShardWorker(processEnvironment = process.env, identit
|
|
|
181
181
|
publicSigningKeys: environment.HELYX_VERIFICATION_SIGNING_PUBLIC_KEYS,
|
|
182
182
|
}));
|
|
183
183
|
platformServices.set(HELYX_SERVICE_NAMES.verificationMembers, new DiscordVerificationMemberService(client));
|
|
184
|
-
platformServices.set(HELYX_SERVICE_NAMES.verificationSetup, new DiscordVerificationSetupService(client, new VerificationSetupRepository(database)));
|
|
185
184
|
}
|
|
186
185
|
numericWriteBehind =
|
|
187
186
|
identity.scope === "coordinated"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helyx/bot",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.17",
|
|
4
4
|
"description": "Production Discord runtime for the modular Helyx platform.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"helyx",
|
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@helyx/config": "0.5.0",
|
|
52
52
|
"@helyx/control-protocol": "0.3.2",
|
|
53
|
-
"@helyx/core": "0.1.
|
|
54
|
-
"@helyx/database": "0.
|
|
55
|
-
"@helyx/framework": "0.1.
|
|
53
|
+
"@helyx/core": "0.1.13",
|
|
54
|
+
"@helyx/database": "0.7.0",
|
|
55
|
+
"@helyx/framework": "0.1.13",
|
|
56
56
|
"@helyx/module-manifest": "0.6.0",
|
|
57
|
-
"@helyx/platform": "0.4.
|
|
58
|
-
"@helyx/sdk": "0.
|
|
59
|
-
"@helyx/verification-contracts": "0.
|
|
57
|
+
"@helyx/platform": "0.4.1",
|
|
58
|
+
"@helyx/sdk": "0.6.0",
|
|
59
|
+
"@helyx/verification-contracts": "0.2.0",
|
|
60
60
|
"discord.js": "14.27.0",
|
|
61
61
|
"fastify": "5.10.0",
|
|
62
62
|
"pino": "10.3.1",
|