@helyx/bot 0.4.11 → 0.4.13
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 +33 -0
- package/dist/control-server.d.ts +38 -3
- package/dist/control-server.js +124 -5
- package/dist/events.d.ts +29 -1
- package/dist/events.js +786 -2
- package/dist/guilds.d.ts +20 -1
- package/dist/guilds.js +149 -9
- package/dist/index.js +21 -5
- package/dist/interactions.js +22 -6
- package/dist/management-module.d.ts +1 -1
- package/dist/shard-contracts.d.ts +324 -0
- package/dist/shard-contracts.js +47 -2
- package/dist/shard-router.d.ts +3 -0
- package/dist/shard-router.js +42 -0
- package/dist/shard-supervisor.d.ts +2 -0
- package/dist/shard-supervisor.js +54 -6
- package/dist/shard-worker.d.ts +6 -0
- package/dist/shard-worker.js +23 -6
- package/dist/verification-service.d.ts +50 -0
- package/dist/verification-service.js +166 -0
- package/package.json +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add the hosted-only Stage 11 Verification foundation: bounded signed challenge
|
|
8
|
+
contracts, restricted persistence and privacy traversal, shard-safe bot
|
|
9
|
+
delivery, delegated investigation permissions, verifier configuration and
|
|
10
|
+
health, and explicit exclusion from every self-hosted composition.
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @helyx/control-protocol@0.3.0
|
|
13
|
+
- @helyx/module-manifest@0.6.0
|
|
14
|
+
- @helyx/config@0.5.0
|
|
15
|
+
- @helyx/database@0.6.0
|
|
16
|
+
- @helyx/sdk@0.5.0
|
|
17
|
+
- @helyx/platform@0.4.0
|
|
18
|
+
- @helyx/core@0.1.12
|
|
19
|
+
- @helyx/framework@0.1.12
|
|
20
|
+
|
|
21
|
+
## 0.4.12
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Repair hosted guild presence after removal, restart and shard reassignment with
|
|
26
|
+
bounded fenced reconciliation and customer-safe dashboard states.
|
|
27
|
+
- Exit with failure after an unexpected coordinated-shard lease shutdown so the
|
|
28
|
+
service orchestrator replaces the stopped supervisor automatically.
|
|
29
|
+
- Retry one transient lease-renewal transport failure within the existing
|
|
30
|
+
fencing window while still failing closed on an actual ownership mismatch.
|
|
31
|
+
- Updated dependencies
|
|
32
|
+
- @helyx/config@0.4.4
|
|
33
|
+
- @helyx/database@0.5.1
|
|
34
|
+
- @helyx/platform@0.3.1
|
|
35
|
+
|
|
3
36
|
## 0.4.11
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/dist/control-server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type DatabasePool } from "@helyx/database";
|
|
1
|
+
import { type DatabasePool, type GuildShardOwnership } from "@helyx/database";
|
|
2
2
|
import { type DashboardActionResult, type ManagedResourceCreationIntent, type ManagedResourceDetail, type ManagedResourcePage, type ManagedResourceRelationPage, type ManagedResourceValue, type MessageResponse, type ModuleDefinition, type PermissionActor, type PrivacyCapturePage, type PrivacyErasePage, type PrivacyProviderExecutor, type ServiceAccess } from "@helyx/sdk";
|
|
3
|
+
import { type ActionReceipt, type SignedAssessmentEnvelope } from "@helyx/verification-contracts";
|
|
3
4
|
import { type Client } from "discord.js";
|
|
4
5
|
import { type FastifyInstance } from "fastify";
|
|
5
6
|
import { type ShardHealthSnapshot } from "./shard-contracts.js";
|
|
@@ -63,7 +64,7 @@ export interface BotControlGuildResources {
|
|
|
63
64
|
channels: Array<{
|
|
64
65
|
id: string;
|
|
65
66
|
name: string;
|
|
66
|
-
type: "guild_text" | "guild_announcement";
|
|
67
|
+
type: "guild_text" | "guild_announcement" | "guild_category";
|
|
67
68
|
}>;
|
|
68
69
|
roles: Array<{
|
|
69
70
|
id: string;
|
|
@@ -71,7 +72,14 @@ export interface BotControlGuildResources {
|
|
|
71
72
|
colour: string;
|
|
72
73
|
}>;
|
|
73
74
|
}
|
|
75
|
+
export type BotGuildPresenceState = "installed" | "not_installed" | "unknown" | "unavailable";
|
|
76
|
+
export interface BotGuildPresenceObservation {
|
|
77
|
+
guildId: string;
|
|
78
|
+
state: BotGuildPresenceState;
|
|
79
|
+
observedAt: string;
|
|
80
|
+
}
|
|
74
81
|
export interface BotControlGuildResourceDirectory {
|
|
82
|
+
listGuildPresence(guildIds: readonly string[]): Promise<BotGuildPresenceObservation[]>;
|
|
75
83
|
getGuildResources(guildId: string): Promise<BotControlGuildResources>;
|
|
76
84
|
sendToChannel(channelId: string, response: MessageResponse): Promise<{
|
|
77
85
|
messageId: string;
|
|
@@ -85,6 +93,7 @@ export interface BotControlGuildResourceDirectory {
|
|
|
85
93
|
export declare class DiscordGuildResourceDirectory implements BotControlGuildResourceDirectory {
|
|
86
94
|
private readonly client;
|
|
87
95
|
constructor(client: Client);
|
|
96
|
+
listGuildPresence(guildIds: readonly string[]): Promise<BotGuildPresenceObservation[]>;
|
|
88
97
|
getGuildResources(guildId: string): Promise<BotControlGuildResources>;
|
|
89
98
|
sendToChannel(channelId: string, response: MessageResponse): Promise<{
|
|
90
99
|
messageId: string;
|
|
@@ -120,7 +129,18 @@ export interface BotControlState {
|
|
|
120
129
|
}
|
|
121
130
|
export interface BotControlHandler {
|
|
122
131
|
sendSupportNotification(input: SupportNotificationInput): Promise<void>;
|
|
132
|
+
listGuildPresence(input: {
|
|
133
|
+
guildIds: readonly string[];
|
|
134
|
+
correlationId: string;
|
|
135
|
+
}): Promise<BotGuildPresenceObservation[]>;
|
|
123
136
|
getGuildState(guildId: string): Promise<BotControlState>;
|
|
137
|
+
canAccessManagedResource(input: {
|
|
138
|
+
guildId: string;
|
|
139
|
+
moduleId: string;
|
|
140
|
+
resourceType: string;
|
|
141
|
+
operation: "list" | "read";
|
|
142
|
+
actorUserId: string;
|
|
143
|
+
}): Promise<boolean>;
|
|
124
144
|
setModuleStatus(input: {
|
|
125
145
|
guildId: string;
|
|
126
146
|
moduleId: string;
|
|
@@ -242,6 +262,7 @@ export interface BotControlHandler {
|
|
|
242
262
|
correlationId: string;
|
|
243
263
|
actorAuthenticatedAt?: string;
|
|
244
264
|
}): Promise<ManagedResourceDetail | null>;
|
|
265
|
+
acceptVerificationResult(envelope: SignedAssessmentEnvelope): Promise<ActionReceipt>;
|
|
245
266
|
listPrivacyProviders(): Promise<readonly {
|
|
246
267
|
id: string;
|
|
247
268
|
version: number;
|
|
@@ -273,11 +294,18 @@ export declare class BotControlService implements BotControlHandler {
|
|
|
273
294
|
private readonly database;
|
|
274
295
|
private readonly resources;
|
|
275
296
|
private readonly supportNotifications?;
|
|
297
|
+
private readonly presenceOwnership?;
|
|
298
|
+
private readonly presenceShardCount?;
|
|
276
299
|
constructor(database: DatabasePool, modules: readonly ModuleDefinition[], resources: BotControlGuildResourceDirectory, services: ServiceAccess, privacyExecutor?: PrivacyProviderExecutor, supportNotifications?: {
|
|
277
300
|
guildId: string;
|
|
278
301
|
channelId: string;
|
|
279
|
-
} | undefined);
|
|
302
|
+
} | undefined, presenceOwnership?: GuildShardOwnership | undefined, presenceShardCount?: number | undefined);
|
|
303
|
+
listGuildPresence(input: {
|
|
304
|
+
guildIds: readonly string[];
|
|
305
|
+
correlationId: string;
|
|
306
|
+
}): Promise<BotGuildPresenceObservation[]>;
|
|
280
307
|
sendSupportNotification(input: SupportNotificationInput): Promise<void>;
|
|
308
|
+
acceptVerificationResult(envelopeInput: SignedAssessmentEnvelope): Promise<ActionReceipt>;
|
|
281
309
|
listPrivacyProviders(): Promise<readonly {
|
|
282
310
|
id: string;
|
|
283
311
|
version: number;
|
|
@@ -300,6 +328,13 @@ export declare class BotControlService implements BotControlHandler {
|
|
|
300
328
|
cursor?: string;
|
|
301
329
|
}): Promise<PrivacyErasePage>;
|
|
302
330
|
getGuildState(guildId: string): Promise<BotControlState>;
|
|
331
|
+
canAccessManagedResource(input: {
|
|
332
|
+
guildId: string;
|
|
333
|
+
moduleId: string;
|
|
334
|
+
resourceType: string;
|
|
335
|
+
operation: "list" | "read";
|
|
336
|
+
actorUserId: string;
|
|
337
|
+
}): Promise<boolean>;
|
|
303
338
|
setModuleStatus(input: {
|
|
304
339
|
guildId: string;
|
|
305
340
|
moduleId: string;
|
package/dist/control-server.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuditRepository, InstallationRepository, ModuleLoggingPolicyRepository, OptimisticConcurrencyError, PermissionPolicyRepository, withTransaction, } from "@helyx/database";
|
|
2
2
|
import { DashboardActionValidationError, HELYX_SERVICE_NAMES, ModuleStateValidationError, } from "@helyx/sdk";
|
|
3
|
+
import { actionReceiptSchema, signedAssessmentEnvelopeSchema, } from "@helyx/verification-contracts";
|
|
3
4
|
import { canUseCommand } from "@helyx/core";
|
|
4
5
|
import { ChannelType, PermissionFlagsBits } from "discord.js";
|
|
5
6
|
import Fastify, {} from "fastify";
|
|
@@ -49,7 +50,7 @@ const resourceCursor = z.string().min(1).max(2_048);
|
|
|
49
50
|
const resourceActionId = z.string().regex(/^[a-z][a-z0-9_-]*$/u);
|
|
50
51
|
const managedResourceFilters = z
|
|
51
52
|
.record(z.string().regex(/^[a-z][a-zA-Z0-9_]*$/u), z.string().trim().min(1).max(100))
|
|
52
|
-
.refine((value) => Object.keys(value).length <=
|
|
53
|
+
.refine((value) => Object.keys(value).length <= 8);
|
|
53
54
|
const managedResourceValue = z.custom((value) => isBoundedManagedResourceValue(value), "Managed resource value exceeds the transport limits");
|
|
54
55
|
const managedResourceObject = z
|
|
55
56
|
.record(z.string().min(1).max(100), managedResourceValue)
|
|
@@ -98,6 +99,24 @@ export class DiscordGuildResourceDirectory {
|
|
|
98
99
|
constructor(client) {
|
|
99
100
|
this.client = client;
|
|
100
101
|
}
|
|
102
|
+
listGuildPresence(guildIds) {
|
|
103
|
+
const observedAt = new Date().toISOString();
|
|
104
|
+
const ready = this.client.isReady();
|
|
105
|
+
return Promise.resolve(guildIds.map((guildId) => {
|
|
106
|
+
const guild = this.client.guilds.cache.get(guildId);
|
|
107
|
+
return {
|
|
108
|
+
guildId,
|
|
109
|
+
state: !ready
|
|
110
|
+
? "unknown"
|
|
111
|
+
: !guild
|
|
112
|
+
? "not_installed"
|
|
113
|
+
: guild.available
|
|
114
|
+
? "installed"
|
|
115
|
+
: "unavailable",
|
|
116
|
+
observedAt,
|
|
117
|
+
};
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
101
120
|
async getGuildResources(guildId) {
|
|
102
121
|
try {
|
|
103
122
|
const guild = await this.client.guilds.fetch(guildId);
|
|
@@ -108,13 +127,16 @@ export class DiscordGuildResourceDirectory {
|
|
|
108
127
|
return {
|
|
109
128
|
channels: [...channels.values()]
|
|
110
129
|
.filter((channel) => channel?.type === ChannelType.GuildText ||
|
|
111
|
-
channel?.type === ChannelType.GuildAnnouncement
|
|
130
|
+
channel?.type === ChannelType.GuildAnnouncement ||
|
|
131
|
+
channel?.type === ChannelType.GuildCategory)
|
|
112
132
|
.map((channel) => ({
|
|
113
133
|
id: channel.id,
|
|
114
134
|
name: channel.name,
|
|
115
135
|
type: channel.type === ChannelType.GuildAnnouncement
|
|
116
136
|
? "guild_announcement"
|
|
117
|
-
:
|
|
137
|
+
: channel.type === ChannelType.GuildCategory
|
|
138
|
+
? "guild_category"
|
|
139
|
+
: "guild_text",
|
|
118
140
|
}))
|
|
119
141
|
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
120
142
|
roles: [...roles.values()]
|
|
@@ -201,6 +223,8 @@ export class BotControlService {
|
|
|
201
223
|
database;
|
|
202
224
|
resources;
|
|
203
225
|
supportNotifications;
|
|
226
|
+
presenceOwnership;
|
|
227
|
+
presenceShardCount;
|
|
204
228
|
#modules;
|
|
205
229
|
#dashboardModules;
|
|
206
230
|
#configurations;
|
|
@@ -208,10 +232,12 @@ export class BotControlService {
|
|
|
208
232
|
#permissions;
|
|
209
233
|
#services;
|
|
210
234
|
#privacyProviders;
|
|
211
|
-
constructor(database, modules, resources, services, privacyExecutor, supportNotifications) {
|
|
235
|
+
constructor(database, modules, resources, services, privacyExecutor, supportNotifications, presenceOwnership, presenceShardCount) {
|
|
212
236
|
this.database = database;
|
|
213
237
|
this.resources = resources;
|
|
214
238
|
this.supportNotifications = supportNotifications;
|
|
239
|
+
this.presenceOwnership = presenceOwnership;
|
|
240
|
+
this.presenceShardCount = presenceShardCount;
|
|
215
241
|
this.#modules = new Map(modules.map((module) => [module.manifest.id, module]));
|
|
216
242
|
this.#dashboardModules = modules
|
|
217
243
|
.filter((module) => module.manifest.dashboard !== undefined)
|
|
@@ -229,6 +255,40 @@ export class BotControlService {
|
|
|
229
255
|
})
|
|
230
256
|
: []);
|
|
231
257
|
}
|
|
258
|
+
async listGuildPresence(input) {
|
|
259
|
+
const guildIds = [...new Set(input.guildIds)];
|
|
260
|
+
if (guildIds.length > 200)
|
|
261
|
+
throw new BotControlValidationError("Guild presence requests cannot exceed 200 guilds");
|
|
262
|
+
const observations = await this.resources.listGuildPresence(guildIds);
|
|
263
|
+
const returned = new Set(observations.map(({ guildId }) => guildId));
|
|
264
|
+
const complete = guildIds.map((guildId) => observations.find((item) => item.guildId === guildId) ?? {
|
|
265
|
+
guildId,
|
|
266
|
+
state: "unknown",
|
|
267
|
+
observedAt: new Date().toISOString(),
|
|
268
|
+
});
|
|
269
|
+
if (observations.some(({ guildId }) => !guildIds.includes(guildId)) ||
|
|
270
|
+
returned.size !== observations.length)
|
|
271
|
+
throw new BotControlTransportError(502, "The guild presence response was invalid");
|
|
272
|
+
const absent = complete
|
|
273
|
+
.filter(({ state }) => state === "not_installed")
|
|
274
|
+
.map(({ guildId }) => guildId);
|
|
275
|
+
if (absent.length > 0) {
|
|
276
|
+
const repository = new InstallationRepository(this.database);
|
|
277
|
+
if (this.presenceOwnership)
|
|
278
|
+
await repository.adoptGuildsForReconciliation({
|
|
279
|
+
guildIds: absent,
|
|
280
|
+
ownership: this.presenceOwnership,
|
|
281
|
+
shardCount: this.presenceShardCount,
|
|
282
|
+
});
|
|
283
|
+
await repository.markGuildsRemovedForReconciliation({
|
|
284
|
+
guildIds: absent,
|
|
285
|
+
...(this.presenceOwnership
|
|
286
|
+
? { ownership: this.presenceOwnership }
|
|
287
|
+
: {}),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return complete;
|
|
291
|
+
}
|
|
232
292
|
async sendSupportNotification(input) {
|
|
233
293
|
if (!this.supportNotifications)
|
|
234
294
|
throw new BotControlNotFoundError("The support notification channel is not configured");
|
|
@@ -263,6 +323,15 @@ export class BotControlService {
|
|
|
263
323
|
},
|
|
264
324
|
}, input.notificationId);
|
|
265
325
|
}
|
|
326
|
+
acceptVerificationResult(envelopeInput) {
|
|
327
|
+
if (!this.#services.has(HELYX_SERVICE_NAMES.verification))
|
|
328
|
+
throw new BotControlTransportError(503, "Verification result handling is unavailable");
|
|
329
|
+
const envelope = signedAssessmentEnvelopeSchema.parse(envelopeInput);
|
|
330
|
+
return this.#services
|
|
331
|
+
.get(HELYX_SERVICE_NAMES.verification)
|
|
332
|
+
.acceptResult(envelope)
|
|
333
|
+
.then((receipt) => actionReceiptSchema.parse(receipt));
|
|
334
|
+
}
|
|
266
335
|
listPrivacyProviders() {
|
|
267
336
|
return Promise.resolve([...this.#privacyProviders.values()]
|
|
268
337
|
.map((provider) => ({
|
|
@@ -345,6 +414,19 @@ export class BotControlService {
|
|
|
345
414
|
logging,
|
|
346
415
|
};
|
|
347
416
|
}
|
|
417
|
+
async canAccessManagedResource(input) {
|
|
418
|
+
try {
|
|
419
|
+
const { module } = await this.#prepareManagedResource(input);
|
|
420
|
+
this.#requireManagedResourceOperation(module, input.resourceType, input.operation);
|
|
421
|
+
await this.#authorizeAction(input.guildId, module, input.actorUserId, managedResourcePermissionId(module, input.resourceType, input.operation));
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
if (error instanceof BotControlForbiddenError)
|
|
426
|
+
return false;
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
348
430
|
async #inspectRuntimeCapabilities() {
|
|
349
431
|
if (!this.#services.has(HELYX_SERVICE_NAMES.discordResources))
|
|
350
432
|
return { messageContent: false };
|
|
@@ -894,6 +976,7 @@ export async function createBotControlServer(input) {
|
|
|
894
976
|
}
|
|
895
977
|
server.get("/health", (_request, reply) => readiness(reply));
|
|
896
978
|
server.get("/v1/health", (_request, reply) => readiness(reply));
|
|
979
|
+
server.post("/v1/verification/results", async (request) => input.service.acceptVerificationResult(signedAssessmentEnvelopeSchema.parse(request.body)));
|
|
897
980
|
server.get("/v1/shards/health", async (request, reply) => {
|
|
898
981
|
reply.header("Cache-Control", "no-store");
|
|
899
982
|
if (!input.shardHealth)
|
|
@@ -958,6 +1041,18 @@ export async function createBotControlServer(input) {
|
|
|
958
1041
|
await input.service.sendSupportNotification(body);
|
|
959
1042
|
return reply.code(204).send();
|
|
960
1043
|
});
|
|
1044
|
+
server.post("/v1/guilds/presence", async (request) => {
|
|
1045
|
+
const body = z
|
|
1046
|
+
.object({
|
|
1047
|
+
guildIds: z.array(snowflake).min(1).max(200),
|
|
1048
|
+
correlationId: z.uuid(),
|
|
1049
|
+
})
|
|
1050
|
+
.strict()
|
|
1051
|
+
.parse(request.body);
|
|
1052
|
+
return {
|
|
1053
|
+
items: await input.service.listGuildPresence(body),
|
|
1054
|
+
};
|
|
1055
|
+
});
|
|
961
1056
|
server.post("/v1/privacy/capture", async (request) => {
|
|
962
1057
|
const body = z
|
|
963
1058
|
.object({
|
|
@@ -966,11 +1061,13 @@ export async function createBotControlServer(input) {
|
|
|
966
1061
|
requestId: z.uuid(),
|
|
967
1062
|
subjectUserId: snowflake,
|
|
968
1063
|
cutoffAt: z.coerce.date(),
|
|
1064
|
+
operation: z.enum(["capture", "residual_scan"]).optional(),
|
|
969
1065
|
cursor: z.string().min(1).max(2_048).optional(),
|
|
970
1066
|
})
|
|
971
1067
|
.strict()
|
|
972
1068
|
.parse(request.body);
|
|
973
|
-
const { cursor, ...value } = body;
|
|
1069
|
+
const { cursor, operation: _operation, ...value } = body;
|
|
1070
|
+
void _operation;
|
|
974
1071
|
return input.service.capturePrivacy({
|
|
975
1072
|
...value,
|
|
976
1073
|
...(cursor ? { cursor } : {}),
|
|
@@ -998,6 +1095,28 @@ export async function createBotControlServer(input) {
|
|
|
998
1095
|
const { guildId } = z.object({ guildId: snowflake }).parse(request.params);
|
|
999
1096
|
return input.service.getGuildState(guildId);
|
|
1000
1097
|
});
|
|
1098
|
+
server.post("/v1/guilds/:guildId/modules/:moduleId/resources/:resourceType/access", async (request) => {
|
|
1099
|
+
const params = z
|
|
1100
|
+
.object({
|
|
1101
|
+
guildId: snowflake,
|
|
1102
|
+
moduleId,
|
|
1103
|
+
resourceType: z.string().regex(/^[a-z][a-z0-9-]*$/u),
|
|
1104
|
+
})
|
|
1105
|
+
.parse(request.params);
|
|
1106
|
+
const body = z
|
|
1107
|
+
.object({
|
|
1108
|
+
operation: z.enum(["list", "read"]),
|
|
1109
|
+
actorUserId: snowflake,
|
|
1110
|
+
})
|
|
1111
|
+
.strict()
|
|
1112
|
+
.parse(request.body);
|
|
1113
|
+
return {
|
|
1114
|
+
allowed: await input.service.canAccessManagedResource({
|
|
1115
|
+
...params,
|
|
1116
|
+
...body,
|
|
1117
|
+
}),
|
|
1118
|
+
};
|
|
1119
|
+
});
|
|
1001
1120
|
server.put("/v1/guilds/:guildId/modules/:moduleId/status", async (request) => {
|
|
1002
1121
|
const params = z
|
|
1003
1122
|
.object({ guildId: snowflake, moduleId })
|
package/dist/events.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { DiscordChannelAudienceInspection, DiscordChannelInspection, DiscordEmojiInspection, DiscordMessageInspection, DiscordGuildCapabilityInspection, DiscordGuildChannelAudienceInspection, DiscordResourceInspectionService, DiscordRoleInspection, DiscordMessageService, MemberEnforcementService, MemberRoleService, ModuleDefinition, ServiceAccess } from "@helyx/sdk";
|
|
1
|
+
import type { DiscordChannelAudienceInspection, DiscordChannelInspection, DiscordEmojiInspection, DiscordMessageInspection, DiscordGuildCapabilityInspection, DiscordGuildChannelAudienceInspection, DiscordResourceInspectionService, DiscordRoleInspection, DiscordMessageService, MemberEnforcementService, MemberRoleService, ModuleDefinition, ServiceAccess, VerificationMemberService, VerificationSetupGuildInspection, VerificationSetupPreview, VerificationSetupRequest, VerificationSetupService } from "@helyx/sdk";
|
|
2
|
+
import type { VerificationSetupRepository } from "@helyx/database";
|
|
2
3
|
import { type Client, type MessageReaction, type PartialMessageReaction } from "discord.js";
|
|
3
4
|
import { type InteractionLogger } from "./interactions.js";
|
|
4
5
|
export declare function installModuleEvents(client: Client, modules: readonly ModuleDefinition[], logger: InteractionLogger, services: ServiceAccess): ModuleEventHandle;
|
|
@@ -26,7 +27,34 @@ export declare class DiscordMemberEnforcementService implements MemberEnforcemen
|
|
|
26
27
|
private readonly client;
|
|
27
28
|
constructor(client: Client);
|
|
28
29
|
kick(input: Parameters<MemberEnforcementService["kick"]>[0]): ReturnType<MemberEnforcementService["kick"]>;
|
|
30
|
+
ban(input: Parameters<MemberEnforcementService["ban"]>[0]): ReturnType<MemberEnforcementService["ban"]>;
|
|
29
31
|
}
|
|
32
|
+
export declare class DiscordVerificationMemberService implements VerificationMemberService {
|
|
33
|
+
private readonly client;
|
|
34
|
+
constructor(client: Client);
|
|
35
|
+
captureSnapshot(input: Parameters<VerificationMemberService["captureSnapshot"]>[0]): ReturnType<VerificationMemberService["captureSnapshot"]>;
|
|
36
|
+
isCurrentlyBanned(input: Parameters<VerificationMemberService["isCurrentlyBanned"]>[0]): ReturnType<VerificationMemberService["isCurrentlyBanned"]>;
|
|
37
|
+
}
|
|
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">;
|
|
30
58
|
export declare class DiscordMemberRoleService implements MemberRoleService {
|
|
31
59
|
private readonly client;
|
|
32
60
|
constructor(client: Client);
|