@helyx/module-account-gate 1.0.14 → 1.1.1

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 (69) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +55 -90
  3. package/dist/challenge-interactions.d.ts +12 -0
  4. package/dist/challenge-interactions.js +238 -0
  5. package/dist/commands.js +3 -2
  6. package/dist/contracts.d.ts +1 -1
  7. package/dist/contracts.js +1 -1
  8. package/dist/expiry-workflows.d.ts +32 -0
  9. package/dist/expiry-workflows.js +281 -0
  10. package/dist/gateway-interactions.d.ts +5 -0
  11. package/dist/gateway-interactions.js +124 -0
  12. package/dist/health.d.ts +10 -0
  13. package/dist/health.js +55 -0
  14. package/dist/index.d.ts +8 -19
  15. package/dist/index.js +35 -3157
  16. package/dist/member-lifecycle.d.ts +21 -0
  17. package/dist/member-lifecycle.js +305 -0
  18. package/dist/member-resource.js +14 -74
  19. package/dist/member-restart.d.ts +4 -0
  20. package/dist/member-restart.js +76 -0
  21. package/dist/member-revocation.d.ts +21 -0
  22. package/dist/member-revocation.js +127 -0
  23. package/dist/member-start.d.ts +5 -0
  24. package/dist/member-start.js +199 -0
  25. package/dist/member-summary.d.ts +47 -0
  26. package/dist/member-summary.js +200 -0
  27. package/dist/panel-maintenance.d.ts +26 -0
  28. package/dist/panel-maintenance.js +143 -0
  29. package/dist/panel-model.d.ts +47 -0
  30. package/dist/panel-model.js +128 -0
  31. package/dist/panel-mutations.d.ts +24 -0
  32. package/dist/panel-mutations.js +89 -0
  33. package/dist/panel-presentation.d.ts +8 -0
  34. package/dist/panel-presentation.js +67 -0
  35. package/dist/panel-resource.d.ts +2 -13
  36. package/dist/panel-resource.js +122 -310
  37. package/dist/panel-runtime.d.ts +8 -0
  38. package/dist/panel-runtime.js +34 -0
  39. package/dist/records.d.ts +42 -2
  40. package/dist/records.js +31 -0
  41. package/dist/review-decisions.d.ts +3 -0
  42. package/dist/review-decisions.js +274 -0
  43. package/dist/review-delivery.d.ts +34 -0
  44. package/dist/review-delivery.js +252 -0
  45. package/dist/review-presentation.d.ts +3 -0
  46. package/dist/review-presentation.js +28 -0
  47. package/dist/review-store.d.ts +4 -0
  48. package/dist/review-store.js +94 -0
  49. package/dist/role-recovery.d.ts +23 -0
  50. package/dist/role-recovery.js +176 -0
  51. package/dist/runtime-dependencies.d.ts +32 -0
  52. package/dist/runtime-dependencies.js +27 -0
  53. package/dist/runtime-support.d.ts +19 -0
  54. package/dist/runtime-support.js +74 -0
  55. package/dist/setup-presentation.d.ts +15 -0
  56. package/dist/setup-presentation.js +378 -0
  57. package/dist/strict-mode.d.ts +17 -0
  58. package/dist/strict-mode.js +154 -0
  59. package/dist/task-contributions.d.ts +4 -0
  60. package/dist/task-contributions.js +113 -0
  61. package/dist/task-scheduling.d.ts +12 -0
  62. package/dist/task-scheduling.js +79 -0
  63. package/dist/terminal-finalization.d.ts +12 -0
  64. package/dist/terminal-finalization.js +238 -0
  65. package/dist/workflow-fences.d.ts +6 -0
  66. package/dist/workflow-fences.js +73 -0
  67. package/manifest.json +9 -2
  68. package/migrations/0002_panel_mutation_claims.sql +34 -0
  69. package/package.json +5 -4
@@ -0,0 +1,94 @@
1
+ import { randomUUID, HELYX_SERVICE_NAMES, ACCOUNT_GATE_IDENTITY, isAccountGateWorkSuppressed, emitLog, REVIEW_DELIVERY_TASK, RETENTION_MS, } from "./runtime-dependencies.js";
2
+ import { loadMemberSummary } from "./member-summary.js";
3
+ import { dateValue, numberValue, stringValue } from "./runtime-support.js";
4
+ import { armRecordRetention, scheduleReviewDelivery, } from "./task-scheduling.js";
5
+ export async function createReview(services, guildId, memberUserId, reasonCode, state, expectedJoinGeneration, boundedChallengeTypes, workCreatedAtOverride) {
6
+ const records = services.get(HELYX_SERVICE_NAMES.records);
7
+ const summary = await loadMemberSummary(records, guildId, memberUserId);
8
+ if (!summary)
9
+ return;
10
+ const joinGeneration = numberValue(summary.join_generation);
11
+ if (expectedJoinGeneration !== undefined &&
12
+ joinGeneration !== expectedJoinGeneration)
13
+ return;
14
+ const workCreatedAt = workCreatedAtOverride ?? (state ? new Date(state.startedAt) : new Date());
15
+ if (await isAccountGateWorkSuppressed(services, guildId, memberUserId, workCreatedAt))
16
+ return;
17
+ const now = new Date();
18
+ const retentionUntil = new Date(now.getTime() + RETENTION_MS);
19
+ const reviewId = randomUUID();
20
+ const created = await records.appendUnique({
21
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
22
+ collection: "reviews",
23
+ uniqueBy: ["pending_key"],
24
+ values: {
25
+ review_id: reviewId,
26
+ pending_key: `pending:${guildId}:${memberUserId}`,
27
+ guild_id: guildId,
28
+ member_user_id: memberUserId,
29
+ join_generation: joinGeneration,
30
+ status: "pending",
31
+ delivery_status: "pending",
32
+ reason_code: reasonCode,
33
+ challenge_types_json: JSON.stringify(boundedChallengeTypes ?? state?.chain.map(({ type }) => type) ?? []),
34
+ failed_attempts: 0,
35
+ expired_attempts: 0,
36
+ revision: 1,
37
+ retention_until: retentionUntil,
38
+ created_at: now,
39
+ updated_at: now,
40
+ },
41
+ schedule: {
42
+ taskKind: REVIEW_DELIVERY_TASK,
43
+ guildId,
44
+ idempotencyKey: `${guildId}:${reviewId}:delivery`,
45
+ payload: { guildId, reviewId },
46
+ scheduledFor: now,
47
+ },
48
+ });
49
+ if (created.created)
50
+ await armRecordRetention(records, guildId, "reviews", "review_id", reviewId, retentionUntil);
51
+ const pending = created.created
52
+ ? { review_id: reviewId }
53
+ : await records.findOne({
54
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
55
+ collection: "reviews",
56
+ select: ["review_id", "delivery_status"],
57
+ where: { pending_key: `pending:${guildId}:${memberUserId}` },
58
+ });
59
+ if (!created.created && pending && pending.delivery_status !== "sent")
60
+ await scheduleReviewDelivery(services, guildId, stringValue(pending.review_id), now);
61
+ await emitLog(services, guildId, {
62
+ eventId: "account-gate-review-created",
63
+ summary: "An Access Control check requires staff review.",
64
+ details: [
65
+ { label: "Member ID", value: memberUserId },
66
+ { label: "Reason", value: reasonCode },
67
+ ],
68
+ });
69
+ }
70
+ export async function finalizeReviewClaim(records, guildId, reviewId, claimRevision, status, row, expiredOnly = true) {
71
+ const now = new Date();
72
+ return (await records.updateOne({
73
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
74
+ collection: "reviews",
75
+ where: { guild_id: guildId, review_id: reviewId },
76
+ expected: { field: "revision", value: claimRevision },
77
+ ...(expiredOnly
78
+ ? { dateAtOrBeforeNow: { field: "claim_expires_at" } }
79
+ : {}),
80
+ values: {
81
+ pending_key: `resolved:${reviewId}`,
82
+ status,
83
+ claim_action: "",
84
+ claim_expires_at: new Date(0),
85
+ decided_by_user_id: typeof row.decided_by_user_id === "string"
86
+ ? row.decided_by_user_id
87
+ : "system",
88
+ decided_at: dateValue(row.decided_at) ?? now,
89
+ revision: claimRevision + 1,
90
+ updated_at: now,
91
+ },
92
+ })).updated;
93
+ }
94
+ //# sourceMappingURL=review-store.js.map
@@ -0,0 +1,23 @@
1
+ import type { RuntimeContext, ScheduledTaskPayload, ServiceAccess } from "./runtime-dependencies.js";
2
+ export declare function validateRoleRetryPayload(input: unknown): ScheduledTaskPayload;
3
+ export declare function retryRoleTransition(context: RuntimeContext, task: {
4
+ payload: ScheduledTaskPayload;
5
+ }): Promise<{
6
+ outcome: "completed";
7
+ safeCode?: never;
8
+ delayMs?: never;
9
+ } | {
10
+ outcome: "requires_review";
11
+ safeCode: string;
12
+ delayMs?: never;
13
+ } | {
14
+ outcome: "deferred";
15
+ delayMs: number;
16
+ safeCode: string;
17
+ } | {
18
+ outcome: "retry";
19
+ delayMs: number;
20
+ safeCode: string;
21
+ }>;
22
+ export declare function persistPartialTransition(services: ServiceAccess, guildId: string, memberUserId: string, verifiedRoleId: string, pendingRoleIds: readonly string[], workCreatedAt?: Date): Promise<void>;
23
+ //# sourceMappingURL=role-recovery.d.ts.map
@@ -0,0 +1,176 @@
1
+ import { randomUUID, HELYX_SERVICE_NAMES, ACCOUNT_GATE_IDENTITY, applyRoleTransition, accountGateRecords, isAccountGateWorkSuppressed, ROLE_RETRY_TASK, } from "./runtime-dependencies.js";
2
+ import { roleRetryStillCurrent } from "./workflow-fences.js";
3
+ import { dateValue, numberValue, stringValue } from "./runtime-support.js";
4
+ export function validateRoleRetryPayload(input) {
5
+ if (!input || typeof input !== "object" || Array.isArray(input))
6
+ throw new Error("Account Gate role retry payload is invalid");
7
+ const value = input;
8
+ if (typeof value.guildId !== "string" ||
9
+ typeof value.transitionId !== "string" ||
10
+ value.transitionId.length > 100)
11
+ throw new Error("Account Gate role retry payload is invalid");
12
+ return { guildId: value.guildId, transitionId: value.transitionId };
13
+ }
14
+ export async function retryRoleTransition(context, task) {
15
+ const records = context.services.get(HELYX_SERVICE_NAMES.records);
16
+ const row = await records.findOne({
17
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
18
+ collection: "role_transitions",
19
+ select: accountGateRecords.role_transitions.readableFields,
20
+ where: {
21
+ guild_id: task.payload.guildId,
22
+ transition_id: task.payload.transitionId,
23
+ },
24
+ });
25
+ if (!row || row.status === "completed")
26
+ return { outcome: "completed" };
27
+ if (row.status === "review")
28
+ return {
29
+ outcome: "requires_review",
30
+ safeCode: "role-transition-blocked",
31
+ };
32
+ if (await isAccountGateWorkSuppressed(context.services, stringValue(row.guild_id), stringValue(row.member_user_id), dateValue(row.created_at) ?? new Date(0)))
33
+ return { outcome: "completed" };
34
+ const now = new Date();
35
+ const nextRetryAt = dateValue(row.next_retry_at);
36
+ if (nextRetryAt && nextRetryAt.getTime() > now.getTime())
37
+ return {
38
+ outcome: "deferred",
39
+ delayMs: Math.max(100, nextRetryAt.getTime() - now.getTime()),
40
+ safeCode: "role-transition-not-due",
41
+ };
42
+ const revision = numberValue(row.revision);
43
+ const claimExpiresAt = new Date(now.getTime() + 2 * 60_000);
44
+ const claimed = await records.updateOne({
45
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
46
+ collection: "role_transitions",
47
+ where: { transition_id: task.payload.transitionId },
48
+ expected: { field: "revision", value: revision },
49
+ ...(nextRetryAt ? { dateAtOrBeforeNow: { field: "next_retry_at" } } : {}),
50
+ values: {
51
+ status: "pending",
52
+ revision: revision + 1,
53
+ next_retry_at: claimExpiresAt,
54
+ updated_at: now,
55
+ },
56
+ });
57
+ if (!claimed.updated)
58
+ return {
59
+ outcome: "retry",
60
+ delayMs: 5_000,
61
+ safeCode: "role-transition-claim-conflict",
62
+ };
63
+ const claimRevision = revision + 1;
64
+ const transition = await applyRoleTransition({
65
+ guildId: stringValue(row.guild_id),
66
+ memberUserId: stringValue(row.member_user_id),
67
+ verifiedRoleId: stringValue(row.verified_role_id),
68
+ temporaryRoleIds: JSON.parse(stringValue(row.pending_remove_role_ids_json)),
69
+ resources: context.services.get(HELYX_SERVICE_NAMES.discordResources),
70
+ roles: context.services.get(HELYX_SERVICE_NAMES.memberRoles),
71
+ revalidate: () => roleRetryStillCurrent(context.services, stringValue(row.guild_id), stringValue(row.member_user_id), dateValue(row.created_at) ?? new Date(0)),
72
+ });
73
+ const finishedAt = new Date();
74
+ const finalized = await records.updateOne({
75
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
76
+ collection: "role_transitions",
77
+ where: { transition_id: task.payload.transitionId },
78
+ expected: { field: "revision", value: claimRevision },
79
+ values: {
80
+ pending_remove_role_ids_json: JSON.stringify(transition.pendingRoleIds),
81
+ status: ["completed", "stale"].includes(transition.outcome)
82
+ ? "completed"
83
+ : transition.outcome === "blocked"
84
+ ? "review"
85
+ : "partial",
86
+ revision: claimRevision + 1,
87
+ next_retry_at: transition.outcome === "partial"
88
+ ? new Date(finishedAt.getTime() + 30_000)
89
+ : new Date(0),
90
+ completed_at: ["completed", "stale"].includes(transition.outcome)
91
+ ? finishedAt
92
+ : new Date(0),
93
+ updated_at: finishedAt,
94
+ },
95
+ });
96
+ if (!finalized.updated)
97
+ return {
98
+ outcome: "retry",
99
+ delayMs: 5_000,
100
+ safeCode: "role-transition-finalize-conflict",
101
+ };
102
+ return transition.outcome === "partial"
103
+ ? {
104
+ outcome: "retry",
105
+ delayMs: 30_000,
106
+ safeCode: "role-removal-pending",
107
+ }
108
+ : transition.outcome === "blocked"
109
+ ? {
110
+ outcome: "requires_review",
111
+ safeCode: "role-transition-blocked",
112
+ }
113
+ : { outcome: "completed" };
114
+ }
115
+ export async function persistPartialTransition(services, guildId, memberUserId, verifiedRoleId, pendingRoleIds, workCreatedAt = new Date()) {
116
+ if (await isAccountGateWorkSuppressed(services, guildId, memberUserId, workCreatedAt))
117
+ return;
118
+ const now = new Date();
119
+ const records = services.get(HELYX_SERVICE_NAMES.records);
120
+ const existing = await records.findOne({
121
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
122
+ collection: "role_transitions",
123
+ select: accountGateRecords.role_transitions.readableFields,
124
+ where: { guild_id: guildId, member_user_id: memberUserId },
125
+ });
126
+ const id = existing ? stringValue(existing.transition_id) : randomUUID();
127
+ const revision = existing ? numberValue(existing.revision) + 1 : 1;
128
+ const scheduledFor = new Date(now.getTime() + 30_000);
129
+ const schedule = {
130
+ taskKind: ROLE_RETRY_TASK,
131
+ guildId,
132
+ idempotencyKey: `${guildId}:${memberUserId}:role-transition:${revision}`,
133
+ payload: { guildId, transitionId: id },
134
+ scheduledFor,
135
+ };
136
+ const stored = existing
137
+ ? await records.updateOne({
138
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
139
+ collection: "role_transitions",
140
+ where: { guild_id: guildId, transition_id: id },
141
+ expected: {
142
+ field: "revision",
143
+ value: numberValue(existing.revision),
144
+ },
145
+ values: {
146
+ verified_role_id: verifiedRoleId,
147
+ pending_remove_role_ids_json: JSON.stringify(pendingRoleIds),
148
+ status: "partial",
149
+ revision,
150
+ next_retry_at: scheduledFor,
151
+ updated_at: now,
152
+ },
153
+ schedule,
154
+ })
155
+ : await records.appendUnique({
156
+ moduleId: ACCOUNT_GATE_IDENTITY.moduleId,
157
+ collection: "role_transitions",
158
+ uniqueBy: ["guild_id", "member_user_id"],
159
+ values: {
160
+ transition_id: id,
161
+ guild_id: guildId,
162
+ member_user_id: memberUserId,
163
+ verified_role_id: verifiedRoleId,
164
+ pending_remove_role_ids_json: JSON.stringify(pendingRoleIds),
165
+ status: "partial",
166
+ revision,
167
+ next_retry_at: scheduledFor,
168
+ created_at: now,
169
+ updated_at: now,
170
+ },
171
+ schedule,
172
+ });
173
+ if (!("updated" in stored ? stored.updated : stored.created))
174
+ return;
175
+ }
176
+ //# sourceMappingURL=role-recovery.js.map
@@ -0,0 +1,32 @@
1
+ import { randomUUID } from "node:crypto";
2
+ export { randomUUID };
3
+ export { DashboardActionValidationError, HELYX_SERVICE_NAMES, } from "@helyx/sdk";
4
+ export type { CommandInteractionContext, DiscordResourceInspectionService, DiscordMessageService, DirectMessageOutcome, InteractionSessionService, InstallationService, MemberEnforcementService, MemberEnforcementOutcome, MemberRoleService, MessageReactionAddContext, MessageResponse, ModalCapableInteractionContext, ModalInteractionContext, ModuleConfigurationService, ModuleRecordService, ModuleRecordValue, PrivilegedMessageCreateContext, ResourceAuthorizationService, RuntimeContext, ScheduledTaskPayload, ScheduledTaskService, SecureRandomService, ServiceAccess, } from "@helyx/sdk";
5
+ export { generateChallengeChain, validateServerQuestion, } from "./challenges.js";
6
+ export { ACCOUNT_GATE_COMPONENTS, ACCOUNT_GATE_IDENTITY, ACCOUNT_GATE_SESSION_PURPOSE, } from "./contracts.js";
7
+ export type { AccountGateSessionState, Challenge, RandomSource, ServerQuestion, } from "./contracts.js";
8
+ export { generatedChallengePool, isStrictModeActive, parseAccountGateConfiguration, validateRuntimeCapabilities, } from "./configuration.js";
9
+ export type { AccountGateConfiguration } from "./configuration.js";
10
+ export { applyRoleTransition, neutralKickDirectMessage, } from "./enforcement.js";
11
+ export type { RoleTransitionResult } from "./enforcement.js";
12
+ export { verifyPasswordEntry } from "./password-entry.js";
13
+ export { accountGateRecords } from "./records.js";
14
+ export { getGatePanelRuntime, hasPasswordGatePanel } from "./panel-resource.js";
15
+ export { isAccountGateWorkSuppressed } from "./privacy.js";
16
+ export { applyChallengeAction, createAccountGateSessionState, parseAccountGateSessionState, rerollForAccessibility, } from "./workflow.js";
17
+ export type { ChallengeAction, WorkflowResult } from "./workflow.js";
18
+ export { emitAccountGateCompletedLog, emitAccountGateKickLog, emitLog, successfulKickOutcome, } from "./logging.js";
19
+ export declare const VIOLET = 8141549;
20
+ export declare const GREEN = 1483594;
21
+ export declare const RED = 14427686;
22
+ export declare const STRICT_EXPIRY_TASK = "account-gate.strict-expiry";
23
+ export declare const ROLE_RETRY_TASK = "account-gate.role-transition-retry";
24
+ export declare const JOIN_DEADLINE_TASK = "account-gate.join-deadline";
25
+ export declare const SESSION_EXPIRY_TASK = "account-gate.session-expiry";
26
+ export declare const REVIEW_DELIVERY_TASK = "account-gate.review-delivery";
27
+ export declare const REVIEW_CLAIM_RECOVERY_TASK = "account-gate.review-claim-recovery";
28
+ export declare const TERMINAL_FINALIZATION_TASK = "account-gate.terminal-finalization";
29
+ export declare const LEAVE_RETENTION_TASK = "account-gate.leave-retention";
30
+ export declare const REVOCATION_RECONCILE_TASK = "account-gate.revocation-reconcile";
31
+ export declare const RETENTION_MS: number;
32
+ //# sourceMappingURL=runtime-dependencies.d.ts.map
@@ -0,0 +1,27 @@
1
+ import { randomUUID } from "node:crypto";
2
+ export { randomUUID };
3
+ export { DashboardActionValidationError, HELYX_SERVICE_NAMES, } from "@helyx/sdk";
4
+ export { generateChallengeChain, validateServerQuestion, } from "./challenges.js";
5
+ export { ACCOUNT_GATE_COMPONENTS, ACCOUNT_GATE_IDENTITY, ACCOUNT_GATE_SESSION_PURPOSE, } from "./contracts.js";
6
+ export { generatedChallengePool, isStrictModeActive, parseAccountGateConfiguration, validateRuntimeCapabilities, } from "./configuration.js";
7
+ export { applyRoleTransition, neutralKickDirectMessage, } from "./enforcement.js";
8
+ export { verifyPasswordEntry } from "./password-entry.js";
9
+ export { accountGateRecords } from "./records.js";
10
+ export { getGatePanelRuntime, hasPasswordGatePanel } from "./panel-resource.js";
11
+ export { isAccountGateWorkSuppressed } from "./privacy.js";
12
+ export { applyChallengeAction, createAccountGateSessionState, parseAccountGateSessionState, rerollForAccessibility, } from "./workflow.js";
13
+ export { emitAccountGateCompletedLog, emitAccountGateKickLog, emitLog, successfulKickOutcome, } from "./logging.js";
14
+ export const VIOLET = 0x7c3aed;
15
+ export const GREEN = 0x16a34a;
16
+ export const RED = 0xdc2626;
17
+ export const STRICT_EXPIRY_TASK = "account-gate.strict-expiry";
18
+ export const ROLE_RETRY_TASK = "account-gate.role-transition-retry";
19
+ export const JOIN_DEADLINE_TASK = "account-gate.join-deadline";
20
+ export const SESSION_EXPIRY_TASK = "account-gate.session-expiry";
21
+ export const REVIEW_DELIVERY_TASK = "account-gate.review-delivery";
22
+ export const REVIEW_CLAIM_RECOVERY_TASK = "account-gate.review-claim-recovery";
23
+ export const TERMINAL_FINALIZATION_TASK = "account-gate.terminal-finalization";
24
+ export const LEAVE_RETENTION_TASK = "account-gate.leave-retention";
25
+ export const REVOCATION_RECONCILE_TASK = "account-gate.revocation-reconcile";
26
+ export const RETENTION_MS = 90 * 24 * 60 * 60 * 1_000;
27
+ //# sourceMappingURL=runtime-dependencies.js.map
@@ -0,0 +1,19 @@
1
+ import type { MessageResponse, ServiceAccess, RandomSource } from "./runtime-dependencies.js";
2
+ export declare function secureRandom(services: ServiceAccess): RandomSource;
3
+ export declare function replyError(context: {
4
+ reply(response: MessageResponse): Promise<void>;
5
+ }, description: string): Promise<void>;
6
+ export declare function stringValue(value: unknown): string;
7
+ export declare function numberValue(value: unknown): number;
8
+ export declare function dateValue(value: unknown): Date | null;
9
+ export declare function canonicalEmojiKey(value: string): string;
10
+ export interface ComponentBinding {
11
+ sessionId: string;
12
+ version: bigint;
13
+ step: number;
14
+ value?: string;
15
+ }
16
+ export declare function boundComponentId(prefix: string, binding: ComponentBinding): string;
17
+ export declare function parseComponentBinding(customId: string | undefined, prefix: string): ComponentBinding | null;
18
+ export declare function staticResumeMessage(guildId: string, gateChannelId: string): MessageResponse;
19
+ //# sourceMappingURL=runtime-support.d.ts.map
@@ -0,0 +1,74 @@
1
+ import { HELYX_SERVICE_NAMES, VIOLET, RED } from "./runtime-dependencies.js";
2
+ export function secureRandom(services) {
3
+ const random = services.get(HELYX_SERVICE_NAMES.secureRandom);
4
+ return {
5
+ integer(maximumExclusive, operationContext) {
6
+ return random.boundedInteger({ maximumExclusive, operationContext })
7
+ .value;
8
+ },
9
+ };
10
+ }
11
+ export async function replyError(context, description) {
12
+ await context.reply({
13
+ ephemeral: true,
14
+ componentsV2: {
15
+ accentColor: RED,
16
+ text: [
17
+ { content: "## Account gate unavailable" },
18
+ { content: description, markdown: false },
19
+ ],
20
+ },
21
+ });
22
+ }
23
+ export function stringValue(value) {
24
+ if (typeof value !== "string")
25
+ throw new Error("Account Gate record is invalid");
26
+ return value;
27
+ }
28
+ export function numberValue(value) {
29
+ if (typeof value !== "number" || !Number.isSafeInteger(value))
30
+ throw new Error("Account Gate record is invalid");
31
+ return value;
32
+ }
33
+ export function dateValue(value) {
34
+ return value instanceof Date ? value : null;
35
+ }
36
+ export function canonicalEmojiKey(value) {
37
+ if (/^(?:custom|unicode):/u.test(value))
38
+ return value.normalize("NFKC");
39
+ const custom = /^([A-Za-z0-9_]{2,32}):(\d{17,20})$/u.exec(value);
40
+ return custom ? `custom:${custom[2]}` : `unicode:${value.normalize("NFKC")}`;
41
+ }
42
+ export function boundComponentId(prefix, binding) {
43
+ return `${prefix}${binding.sessionId}:${String(binding.version)}:${binding.step}${binding.value === undefined ? "" : `:${binding.value}`}`;
44
+ }
45
+ export function parseComponentBinding(customId, prefix) {
46
+ if (!customId?.startsWith(prefix))
47
+ return null;
48
+ const [sessionId, version, step, value] = customId
49
+ .slice(prefix.length)
50
+ .split(":");
51
+ if (!sessionId ||
52
+ !version ||
53
+ !/^\d+$/u.test(version) ||
54
+ !step ||
55
+ !/^\d+$/u.test(step))
56
+ return null;
57
+ return {
58
+ sessionId,
59
+ version: BigInt(version),
60
+ step: Number(step),
61
+ ...(value === undefined ? {} : { value }),
62
+ };
63
+ }
64
+ export function staticResumeMessage(guildId, gateChannelId) {
65
+ return {
66
+ embed: {
67
+ title: "Continue your Access Control check",
68
+ description: `Your existing check for Discord server ${guildId} is ready to continue. Return to <#${gateChannelId}> and press **Start check** to resume it.`,
69
+ color: VIOLET,
70
+ },
71
+ allowedUserMentionIds: [],
72
+ };
73
+ }
74
+ //# sourceMappingURL=runtime-support.js.map
@@ -0,0 +1,15 @@
1
+ import type { MessageResponse, ServiceAccess, AccountGateSessionState, ServerQuestion, AccountGateConfiguration } from "./runtime-dependencies.js";
2
+ export declare function configurationForPanel(configuration: AccountGateConfiguration, accessType: "challenges" | "password" | "emoji"): AccountGateConfiguration;
3
+ export declare function reviewMessage(memberUserId: string, reasonCode: string): MessageResponse;
4
+ export declare function validateAccountGateSetup(services: ServiceAccess, guildId: string, configuration: AccountGateConfiguration, throwOnError?: boolean, allowMissingPanel?: boolean): Promise<readonly string[]>;
5
+ export declare function challengeMessage(state: AccountGateSessionState, binding: {
6
+ sessionId: string;
7
+ version: bigint;
8
+ }, options?: {
9
+ redactRecallCode?: boolean;
10
+ }): MessageResponse;
11
+ export declare function loadQuestions(services: ServiceAccess, guildId: string): Promise<readonly ServerQuestion[]>;
12
+ export declare function currentStrictMode(services: ServiceAccess, guildId: string): Promise<boolean>;
13
+ export declare function getConfiguration(services: ServiceAccess, guildId: string): Promise<AccountGateConfiguration | null>;
14
+ export declare function requiredRuntimeConfiguration(services: ServiceAccess, guildId: string): Promise<AccountGateConfiguration>;
15
+ //# sourceMappingURL=setup-presentation.d.ts.map