@helyx/bot 0.4.31 → 0.4.33

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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.33
4
+
5
+ ### Patch Changes
6
+
7
+ - Add versioned OAuth consumer cleanup contracts, durable and resumable
8
+ revocation state, least-privilege provider scopes, and Creator Connections
9
+ cleanup dispatch. Promote the hosted-only Creator Connections module to live
10
+ availability with clear OAuth activation validation. Ignore shard responses
11
+ that finish after shutdown has already detached their worker.
12
+
13
+ ## 0.4.32
14
+
15
+ ### Patch Changes
16
+
17
+ - Add the live Server Health inspection runtime, OAuth service wiring, and faster control-request permission handling.
18
+
19
+ ### Updated Dependencies
20
+
21
+ - @helyx/config@0.5.4
22
+ - @helyx/database@0.8.1
23
+ - @helyx/platform@0.5.1
24
+
3
25
  ## 0.4.31
4
26
 
5
27
  ### Patch Changes
@@ -0,0 +1,38 @@
1
+ import type { ModuleDefinition, PermissionPolicy } from "@helyx/sdk";
2
+ export interface DashboardPermissionPolicy {
3
+ preset: "everyone" | "moderators" | "administrators" | "custom";
4
+ allowedRoleIds: string[];
5
+ deniedRoleIds: string[];
6
+ }
7
+ export interface DashboardPermissionState {
8
+ version: number;
9
+ module: DashboardPermissionPolicy;
10
+ commands: Array<{
11
+ commandId: string;
12
+ version: number;
13
+ enabled: boolean;
14
+ policy: DashboardPermissionPolicy;
15
+ }>;
16
+ }
17
+ export interface PermissionPolicyTarget {
18
+ moduleId: string;
19
+ commandId?: string;
20
+ }
21
+ export interface ResolvedPermissionPolicy extends PermissionPolicyTarget {
22
+ policy: PermissionPolicy;
23
+ version: bigint | null;
24
+ inherited: boolean;
25
+ }
26
+ export type ManagedResourceOperation = "list" | "read" | "preview" | "create" | "update" | "delete" | "action";
27
+ export declare function declaredManagedResourcePermission(module: ModuleDefinition, resourceType: string, operation: ManagedResourceOperation): string | undefined;
28
+ export declare function dashboardActionPermissionId(module: ModuleDefinition, actionId: string): string;
29
+ export declare function managedResourcePermissionId(module: ModuleDefinition, resourceType: string, operation: ManagedResourceOperation, actionId?: string, declaredPermissionId?: string): string;
30
+ export declare function permissionPolicyKey(target: PermissionPolicyTarget): string;
31
+ export declare function toDashboardPolicy(policy: PermissionPolicy): DashboardPermissionPolicy;
32
+ export declare function fromDashboardPolicy(input: DashboardPermissionPolicy, current: PermissionPolicy): PermissionPolicy;
33
+ export declare function emptyPolicy(): PermissionPolicy;
34
+ export declare function permissionPoliciesEqual(left: PermissionPolicy, right: PermissionPolicy): boolean;
35
+ export declare function safeVersion(version: bigint): number;
36
+ export declare function safeOptionalVersion(version: bigint | null): number;
37
+ export declare function assertVersion(actual: bigint | null, requested: number): void;
38
+ //# sourceMappingURL=control-permissions.d.ts.map
@@ -0,0 +1,139 @@
1
+ import { OptimisticConcurrencyError } from "@helyx/database";
2
+ export function declaredManagedResourcePermission(module, resourceType, operation) {
3
+ if (operation === "action")
4
+ return undefined;
5
+ return module.manifest.dashboard?.resources?.find(({ id }) => id === resourceType)?.permissions?.[operation];
6
+ }
7
+ export function dashboardActionPermissionId(module, actionId) {
8
+ const namespace = modulePermissionNamespace(module);
9
+ return selectDeclaredPermission(module, [
10
+ `${namespace}.${actionId.replaceAll("-", ".")}`,
11
+ `${namespace}.configure`,
12
+ ]);
13
+ }
14
+ export function managedResourcePermissionId(module, resourceType, operation, actionId, declaredPermissionId) {
15
+ if (declaredPermissionId)
16
+ return declaredPermissionId;
17
+ const namespace = modulePermissionNamespace(module);
18
+ const resourcePermission = `resource.${resourceType}`;
19
+ const candidates = operation === "create" || operation === "preview"
20
+ ? [
21
+ `${resourcePermission}.create`,
22
+ `${namespace}.create`,
23
+ `${namespace}.manage`,
24
+ ]
25
+ : operation === "update"
26
+ ? [
27
+ `${resourcePermission}.update`,
28
+ `${namespace}.edit`,
29
+ `${namespace}.manage`,
30
+ ]
31
+ : operation === "delete"
32
+ ? [
33
+ `${resourcePermission}.delete`,
34
+ `${namespace}.delete`,
35
+ `${namespace}.cancel`,
36
+ `${namespace}.manage`,
37
+ ]
38
+ : operation === "action" && actionId
39
+ ? [
40
+ `${resourcePermission}.${actionId}`,
41
+ `${resourcePermission}.action.${actionId}`,
42
+ `${resourcePermission}.action`,
43
+ `${namespace}.${actionId.replaceAll("-", ".")}`,
44
+ `${namespace}.manage`,
45
+ ]
46
+ : [
47
+ `${resourcePermission}.${operation}`,
48
+ `${namespace}.read`,
49
+ `${namespace}.list`,
50
+ `${namespace}.manage`,
51
+ `${namespace}.entries.read`,
52
+ ];
53
+ return selectDeclaredPermission(module, candidates);
54
+ }
55
+ function modulePermissionNamespace(module) {
56
+ return module.manifest.id.startsWith("helyx.")
57
+ ? module.manifest.id.slice("helyx.".length)
58
+ : module.manifest.id;
59
+ }
60
+ function selectDeclaredPermission(module, candidates) {
61
+ const declared = module.defaultPermissions?.commands ?? {};
62
+ return (candidates.find((candidate) => candidate in declared) ?? candidates[0]);
63
+ }
64
+ export function permissionPolicyKey(target) {
65
+ return `${target.moduleId}\u0000${target.commandId ?? ""}`;
66
+ }
67
+ export function toDashboardPolicy(policy) {
68
+ const preset = policy.everyone
69
+ ? "everyone"
70
+ : policy.accessLevel === "administrator"
71
+ ? "administrators"
72
+ : policy.accessLevel === "moderator"
73
+ ? "moderators"
74
+ : policy.allowedRoleIds.length > 0 &&
75
+ policy.requiredPermissions.length === 0
76
+ ? "custom"
77
+ : policy.requiredPermissions.includes("ADMINISTRATOR")
78
+ ? "administrators"
79
+ : policy.requiredPermissions.includes("MANAGE_GUILD")
80
+ ? "moderators"
81
+ : "custom";
82
+ return {
83
+ preset,
84
+ allowedRoleIds: [...policy.allowedRoleIds],
85
+ deniedRoleIds: [...policy.deniedRoleIds],
86
+ };
87
+ }
88
+ export function fromDashboardPolicy(input, current) {
89
+ return {
90
+ everyone: input.preset === "everyone",
91
+ ...(input.preset === "administrators"
92
+ ? { accessLevel: "administrator" }
93
+ : input.preset === "moderators"
94
+ ? { accessLevel: "moderator" }
95
+ : {}),
96
+ requiredPermissions: [],
97
+ allowedRoleIds: input.preset === "custom" ? input.allowedRoleIds : [],
98
+ deniedRoleIds: input.deniedRoleIds,
99
+ allowedUserIds: [...current.allowedUserIds],
100
+ deniedUserIds: [...current.deniedUserIds],
101
+ };
102
+ }
103
+ export function emptyPolicy() {
104
+ return {
105
+ everyone: false,
106
+ requiredPermissions: [],
107
+ allowedRoleIds: [],
108
+ deniedRoleIds: [],
109
+ allowedUserIds: [],
110
+ deniedUserIds: [],
111
+ };
112
+ }
113
+ export function permissionPoliciesEqual(left, right) {
114
+ return (left.everyone === right.everyone &&
115
+ left.accessLevel === right.accessLevel &&
116
+ sameStrings(left.requiredPermissions, right.requiredPermissions) &&
117
+ sameStrings(left.allowedRoleIds, right.allowedRoleIds) &&
118
+ sameStrings(left.deniedRoleIds, right.deniedRoleIds) &&
119
+ sameStrings(left.allowedUserIds, right.allowedUserIds) &&
120
+ sameStrings(left.deniedUserIds, right.deniedUserIds));
121
+ }
122
+ function sameStrings(left, right) {
123
+ return (left.length === right.length &&
124
+ left.every((value, index) => value === right[index]));
125
+ }
126
+ export function safeVersion(version) {
127
+ const value = Number(version);
128
+ if (!Number.isSafeInteger(value) || value < 1)
129
+ throw new Error("Configuration version exceeded the supported range");
130
+ return value;
131
+ }
132
+ export function safeOptionalVersion(version) {
133
+ return version === null ? 0 : safeVersion(version);
134
+ }
135
+ export function assertVersion(actual, requested) {
136
+ if (safeOptionalVersion(actual) !== requested)
137
+ throw new OptimisticConcurrencyError("Permission policy");
138
+ }
139
+ //# sourceMappingURL=control-permissions.js.map
@@ -1,14 +1,10 @@
1
1
  import { type DatabasePool, type GuildShardOwnership } from "@helyx/database";
2
- import { type DashboardActionResult, type GuildAccessPolicy, type ManagedResourceCreationIntent, type ManagedResourceDetail, type ManagedResourcePage, type ManagedResourceRelationPage, type ManagedResourceValue, type MessageResponse, type ModuleDefinition, type PermissionActor, type PrivacyCapturePage, type PrivacyErasePage, type PrivacyProviderExecutor, type PublicAchievementProjectionPage, type ServiceAccess } from "@helyx/sdk";
2
+ import { type DashboardActionResult, type GuildAccessPolicy, type ManagedResourceCreationIntent, type ManagedResourceDetail, type ManagedResourcePage, type ManagedResourceRelationPage, type ManagedResourceValue, type MessageResponse, type ModuleDefinition, type OAuthConsumerCleanupResult, type PermissionActor, type PrivacyCapturePage, type PrivacyErasePage, type PrivacyProviderExecutor, type PublicAchievementProjectionPage, type ServiceAccess } from "@helyx/sdk";
3
3
  import { type ActionReceipt, type SignedAssessmentEnvelope } from "@helyx/verification-contracts";
4
4
  import { type Client } from "discord.js";
5
5
  import { type FastifyInstance } from "fastify";
6
6
  import { type ShardHealthSnapshot } from "./shard-contracts.js";
7
- interface DashboardPermissionPolicy {
8
- preset: "everyone" | "moderators" | "administrators" | "custom";
9
- allowedRoleIds: string[];
10
- deniedRoleIds: string[];
11
- }
7
+ import { type DashboardPermissionPolicy, type DashboardPermissionState } from "./control-permissions.js";
12
8
  interface DashboardCommandDefinition {
13
9
  id: string;
14
10
  name: string;
@@ -52,16 +48,6 @@ interface DashboardLoggingPolicy {
52
48
  enabled: boolean;
53
49
  version: number;
54
50
  }
55
- interface DashboardPermissionState {
56
- version: number;
57
- module: DashboardPermissionPolicy;
58
- commands: Array<{
59
- commandId: string;
60
- version: number;
61
- enabled: boolean;
62
- policy: DashboardPermissionPolicy;
63
- }>;
64
- }
65
51
  export interface BotControlGuildResources {
66
52
  channels: Array<{
67
53
  id: string;
@@ -157,6 +143,17 @@ export interface DashboardGuildAccessState extends GuildAccessPolicy {
157
143
  updatedAt: string | null;
158
144
  }
159
145
  export interface BotControlHandler {
146
+ cleanupOAuthConsumer(input: {
147
+ consumerBindingId: string;
148
+ moduleId: string;
149
+ provider: "youtube" | "twitch";
150
+ guildId: string;
151
+ resourceType: string;
152
+ resourceId: string;
153
+ subjectUserId: string;
154
+ contractVersion: number;
155
+ correlationId: string;
156
+ }): Promise<OAuthConsumerCleanupResult>;
160
157
  sendSupportNotification(input: SupportNotificationInput): Promise<void>;
161
158
  listGuildPresence(input: {
162
159
  guildIds: readonly string[];
@@ -353,6 +350,17 @@ export declare class BotControlService implements BotControlHandler {
353
350
  guildId: string;
354
351
  channelId: string;
355
352
  } | undefined, presenceOwnership?: GuildShardOwnership | undefined, presenceShardCount?: number | undefined);
353
+ cleanupOAuthConsumer(input: {
354
+ consumerBindingId: string;
355
+ moduleId: string;
356
+ provider: "youtube" | "twitch";
357
+ guildId: string;
358
+ resourceType: string;
359
+ resourceId: string;
360
+ subjectUserId: string;
361
+ contractVersion: number;
362
+ correlationId: string;
363
+ }): Promise<OAuthConsumerCleanupResult>;
356
364
  listGuildPresence(input: {
357
365
  guildIds: readonly string[];
358
366
  correlationId: string;