@voltro/plugin-chat 0.0.0-stage → 0.87.0
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 +24329 -0
- package/LICENSE +61 -0
- package/README.md +516 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +14931 -0
- package/dist/admissions.entity.js +11 -0
- package/dist/channels.entity.js +20 -0
- package/dist/chat-app/events/chat.mentioned.event.ts +1 -0
- package/dist/chat-app/events/chat.messageChanged.event.ts +1 -0
- package/dist/chat-app/events/chat.typing.event.ts +1 -0
- package/dist/chat-app/schedules/chat.retention.cron.tsx +16 -0
- package/dist/chat-app/subscribers/chat.messages.subscribe.ts +4 -0
- package/dist/components.js +432 -0
- package/dist/contract.js +92 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +21 -0
- package/dist/eventProducer.d.ts +18 -0
- package/dist/eventProducer.js +46 -0
- package/dist/events.d.ts +38 -0
- package/dist/events.js +36 -0
- package/dist/evidence.entity.js +25 -0
- package/dist/index.d.ts +623 -0
- package/dist/index.js +181 -0
- package/dist/inspect.js +38 -0
- package/dist/media.entity.js +15 -0
- package/dist/members.entity.js +22 -0
- package/dist/mentionDraft.js +21 -0
- package/dist/mentionNotifications.js +110 -0
- package/dist/messages.entity.js +28 -0
- package/dist/reportEvidence.js +16 -0
- package/dist/retention.entity.js +11 -0
- package/dist/rpc.d.ts +295 -0
- package/dist/rpc.js +267 -0
- package/dist/rpcRoutes.js +97 -0
- package/dist/server.d.ts +200 -0
- package/dist/server.js +7 -0
- package/dist/service.js +1412 -0
- package/dist/strategies.d.ts +148 -0
- package/dist/strategies.js +90 -0
- package/dist/testing.d.ts +139 -0
- package/dist/testing.js +111 -0
- package/dist/typing.js +88 -0
- package/dist/typingInvalidation.js +86 -0
- package/dist/typingLease.js +59 -0
- package/dist/typingPublisher.js +59 -0
- package/dist/useChatTypingPublisher.js +33 -0
- package/dist/useTyping.js +24 -0
- package/dist/web.d.ts +354 -0
- package/dist/web.js +19 -0
- package/package.json +98 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
import { ColumnBuilder } from '@voltro/database';
|
|
2
|
+
import { DataStore } from '@voltro/database';
|
|
3
|
+
import { Effect } from 'effect';
|
|
4
|
+
import { EventClientPolicy } from '@voltro/protocol';
|
|
5
|
+
import { FieldDefinitions } from '@voltro/database';
|
|
6
|
+
import { PluginPrivacyTarget } from '@voltro/protocol';
|
|
7
|
+
import { RateLimitStore } from '@voltro/plugin-ratelimit';
|
|
8
|
+
import { RedisStoreOptions } from '@voltro/plugin-ratelimit';
|
|
9
|
+
import { Schema } from 'effect';
|
|
10
|
+
import { Scope } from 'effect/Scope';
|
|
11
|
+
import { Subject } from '@voltro/protocol';
|
|
12
|
+
import { Table } from '@voltro/database';
|
|
13
|
+
import { VoltroPlugin } from '@voltro/protocol';
|
|
14
|
+
import { YieldableError } from 'effect/Cause';
|
|
15
|
+
|
|
16
|
+
/** Server integrations supply verified membership and transcripts, never browser rows. */
|
|
17
|
+
declare interface ArchiveMatchInput {
|
|
18
|
+
readonly tenantId: string;
|
|
19
|
+
readonly matchId: string;
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly members: CreateChatChannelInput['members'];
|
|
22
|
+
readonly messages: ReadonlyArray<{
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly authorId: string;
|
|
25
|
+
readonly body: string;
|
|
26
|
+
readonly at: number;
|
|
27
|
+
}>;
|
|
28
|
+
readonly retentionMs?: number | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare const CHANNEL_KINDS: readonly ["global", "lobby", "party", "guild", "match", "dm", "custom"];
|
|
32
|
+
|
|
33
|
+
declare const channelChatRetention: (channel: ChatChannel) => number | null;
|
|
34
|
+
|
|
35
|
+
/** Message versions are SQL INT columns; edits stop below this and redaction saturates at it. */
|
|
36
|
+
export declare const CHAT_MAX_MESSAGE_VERSION = 2147483647;
|
|
37
|
+
|
|
38
|
+
/** Upper bound of media rows one sweep step reads; storage deletes happen outside SQL. */
|
|
39
|
+
export declare const CHAT_MEDIA_SWEEP_BATCH_SIZE = 50;
|
|
40
|
+
|
|
41
|
+
export declare const CHAT_RETENTION_BATCH_SIZE = 200;
|
|
42
|
+
|
|
43
|
+
export declare const CHAT_RETENTION_RUN_BATCHES = 10;
|
|
44
|
+
|
|
45
|
+
/** Durable identity admission and redacted erasure tombstone. Never deleted by history retention. */
|
|
46
|
+
export declare const chatAdmissionsTable: Table<"_voltro_chat_admissions", FieldDefinitions<{
|
|
47
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
48
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
49
|
+
readonly subjectId: ColumnBuilder<string | null, "text", boolean>;
|
|
50
|
+
readonly admission: ColumnBuilder<number, "integer", boolean>;
|
|
51
|
+
readonly erased: ColumnBuilder<boolean, "boolean", boolean>;
|
|
52
|
+
}>, true, never>;
|
|
53
|
+
|
|
54
|
+
export declare type ChatAuthorProjection = typeof ChatAuthorProjectionSchema.Type;
|
|
55
|
+
|
|
56
|
+
/** Roster-only identity; displayName already includes the Players tag. */
|
|
57
|
+
declare const ChatAuthorProjectionSchema: Schema.Struct<{
|
|
58
|
+
readonly subjectId: Schema.String;
|
|
59
|
+
readonly displayName: Schema.String;
|
|
60
|
+
readonly avatar: Schema.NullOr<Schema.String>;
|
|
61
|
+
}>;
|
|
62
|
+
|
|
63
|
+
export declare interface ChatAuthorsInput {
|
|
64
|
+
readonly channelId: string;
|
|
65
|
+
readonly subjectIds: ReadonlyArray<string>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export declare type ChatChannel = typeof ChatChannelSchema.Type;
|
|
69
|
+
|
|
70
|
+
declare const ChatChannelSchema: Schema.Struct<{
|
|
71
|
+
readonly id: Schema.String;
|
|
72
|
+
readonly kind: Schema.Literals<readonly ["global", "lobby", "party", "guild", "match", "dm", "custom"]>;
|
|
73
|
+
readonly refId: Schema.String;
|
|
74
|
+
readonly name: Schema.String;
|
|
75
|
+
readonly slowModeMs: Schema.Number;
|
|
76
|
+
readonly retentionMs: Schema.NullOr<Schema.Number>;
|
|
77
|
+
readonly maxMembers: Schema.Number;
|
|
78
|
+
readonly frozen: Schema.Boolean;
|
|
79
|
+
readonly createdAt: Schema.Number;
|
|
80
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
81
|
+
}>;
|
|
82
|
+
|
|
83
|
+
export declare const chatChannelsTable: Table<"_voltro_chat_channels", FieldDefinitions<{
|
|
84
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
85
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
86
|
+
readonly kind: ColumnBuilder<"custom" | "match" | "global" | "lobby" | "party" | "guild" | "dm", "text", boolean>;
|
|
87
|
+
readonly refId: ColumnBuilder<string, "text", boolean>;
|
|
88
|
+
readonly name: ColumnBuilder<string, "text", boolean>;
|
|
89
|
+
readonly slowModeMs: ColumnBuilder<number, "integer", boolean>;
|
|
90
|
+
readonly retentionMs: ColumnBuilder<number | null, "integer", boolean>;
|
|
91
|
+
readonly maxMembers: ColumnBuilder<number, "integer", boolean>;
|
|
92
|
+
readonly frozen: ColumnBuilder<boolean, "boolean", boolean>;
|
|
93
|
+
readonly createdAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
94
|
+
readonly admission: ColumnBuilder<number, "integer", boolean>;
|
|
95
|
+
readonly creationKey: ColumnBuilder<string, "text", boolean>;
|
|
96
|
+
readonly metadata: ColumnBuilder<unknown, "json", boolean>;
|
|
97
|
+
}>, true, never>;
|
|
98
|
+
|
|
99
|
+
export declare class ChatError extends ChatError_base {
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
declare const ChatError_base: Schema.Class<ChatError, Schema.TaggedStruct<"ChatError", {
|
|
103
|
+
readonly code: Schema.Literals<readonly ["identity_required", "invalid_input", "not_found", "forbidden", "blocked", "sanctioned", "muted", "slow_mode", "rate_limited", "content_rejected", "conflict", "frozen", "member_limit", "unavailable", "export_limit"]>;
|
|
104
|
+
}>, YieldableError>;
|
|
105
|
+
|
|
106
|
+
declare interface ChatEvidenceSnapshot {
|
|
107
|
+
readonly id: string;
|
|
108
|
+
readonly channelId: string;
|
|
109
|
+
readonly messageId: string;
|
|
110
|
+
readonly messageVersion: number;
|
|
111
|
+
readonly kind: string;
|
|
112
|
+
readonly authorId: string | null;
|
|
113
|
+
readonly body: string | null;
|
|
114
|
+
readonly originalBody: string | null;
|
|
115
|
+
readonly createdAt: number;
|
|
116
|
+
readonly editedAt: number | null;
|
|
117
|
+
readonly deletedAt: number | null;
|
|
118
|
+
readonly capturedAt: number;
|
|
119
|
+
readonly expiresAt: number;
|
|
120
|
+
readonly erasedAt: number | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Private immutable content captures. Cases contain references, never copies of this text. */
|
|
124
|
+
export declare const chatEvidenceTable: Table<"_voltro_chat_evidence", FieldDefinitions<{
|
|
125
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
126
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
127
|
+
readonly channelId: ColumnBuilder<string, "text", boolean>;
|
|
128
|
+
readonly messageId: ColumnBuilder<string, "text", boolean>;
|
|
129
|
+
readonly messageVersion: ColumnBuilder<number, "integer", boolean>;
|
|
130
|
+
readonly kind: ColumnBuilder<string, "text", boolean>;
|
|
131
|
+
readonly authorId: ColumnBuilder<string | null, "text", boolean>;
|
|
132
|
+
readonly body: ColumnBuilder<string, "text", boolean>;
|
|
133
|
+
readonly originalBody: ColumnBuilder<string, "text", boolean>;
|
|
134
|
+
readonly messageCreatedAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
135
|
+
readonly messageEditedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
136
|
+
readonly messageDeletedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
137
|
+
readonly capturedAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
138
|
+
readonly expiresAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
139
|
+
readonly erasedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
140
|
+
}>, true, never>;
|
|
141
|
+
|
|
142
|
+
export declare type ChatMediaAttachment = typeof ChatMediaAttachmentSchema.Type;
|
|
143
|
+
|
|
144
|
+
/** Server-verified attachment facts copied into `payload.media`; bytes stay in plugin-storage. */
|
|
145
|
+
declare const ChatMediaAttachmentSchema: Schema.Struct<{
|
|
146
|
+
readonly id: Schema.String;
|
|
147
|
+
readonly contentType: Schema.String;
|
|
148
|
+
readonly size: Schema.Number;
|
|
149
|
+
readonly width: Schema.NullOr<Schema.Number>;
|
|
150
|
+
readonly height: Schema.NullOr<Schema.Number>;
|
|
151
|
+
}>;
|
|
152
|
+
|
|
153
|
+
export declare interface ChatMediaInput {
|
|
154
|
+
readonly subject: Subject;
|
|
155
|
+
/** Facts read from plugin-storage for a ref the sender owns in this tenant. */
|
|
156
|
+
readonly ref: {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
readonly contentType: string;
|
|
159
|
+
readonly size: number;
|
|
160
|
+
readonly width: number | null;
|
|
161
|
+
readonly height: number | null;
|
|
162
|
+
};
|
|
163
|
+
readonly contentTypes: ReadonlyArray<string>;
|
|
164
|
+
readonly maxBytes: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
declare interface ChatMediaSweep {
|
|
168
|
+
readonly removed: number;
|
|
169
|
+
readonly failed: number;
|
|
170
|
+
readonly remaining: boolean;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** One row per media message. `deleting` rows wait for the bounded storage sweep; the blob is never deleted inside SQL. */
|
|
174
|
+
export declare const chatMediaTable: Table<"_voltro_chat_media", FieldDefinitions<{
|
|
175
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
176
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
177
|
+
readonly channelId: ColumnBuilder<string, "text", boolean>;
|
|
178
|
+
readonly messageId: ColumnBuilder<string, "text", boolean>;
|
|
179
|
+
readonly storageId: ColumnBuilder<string, "text", boolean>;
|
|
180
|
+
readonly ownerId: ColumnBuilder<string | null, "text", boolean>;
|
|
181
|
+
readonly state: ColumnBuilder<"active" | "deleting", "text", boolean>;
|
|
182
|
+
readonly createdAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
183
|
+
}>, true, never>;
|
|
184
|
+
|
|
185
|
+
export declare type ChatMediaUrl = typeof ChatMediaUrlSchema.Type;
|
|
186
|
+
|
|
187
|
+
declare const ChatMediaUrlSchema: Schema.Struct<{
|
|
188
|
+
readonly url: Schema.String;
|
|
189
|
+
readonly expiresAt: Schema.Number;
|
|
190
|
+
}>;
|
|
191
|
+
|
|
192
|
+
export declare interface ChatMediaVerdict {
|
|
193
|
+
readonly allowed: boolean;
|
|
194
|
+
readonly flagged: boolean;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export declare type ChatMember = typeof ChatMemberSchema.Type;
|
|
198
|
+
|
|
199
|
+
declare const ChatMemberSchema: Schema.Struct<{
|
|
200
|
+
readonly id: Schema.String;
|
|
201
|
+
readonly channelId: Schema.String;
|
|
202
|
+
readonly subjectId: Schema.String;
|
|
203
|
+
readonly role: Schema.Literals<readonly ["member", "mod", "owner"]>;
|
|
204
|
+
readonly mutedUntil: Schema.NullOr<Schema.Number>;
|
|
205
|
+
readonly lastReadAt: Schema.Number;
|
|
206
|
+
readonly lastReadId: Schema.NullOr<Schema.String>;
|
|
207
|
+
readonly notify: Schema.Boolean;
|
|
208
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
209
|
+
}>;
|
|
210
|
+
|
|
211
|
+
export declare const chatMembersTable: Table<"_voltro_chat_members", FieldDefinitions<{
|
|
212
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
213
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
214
|
+
readonly channelId: ColumnBuilder<string, "text", boolean>;
|
|
215
|
+
readonly subjectId: ColumnBuilder<string, "text", boolean>;
|
|
216
|
+
readonly role: ColumnBuilder<"member" | "owner" | "mod", "text", boolean>;
|
|
217
|
+
readonly mutedUntil: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
218
|
+
readonly lastReadAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
219
|
+
readonly lastReadId: ColumnBuilder<string | null, "text", boolean>;
|
|
220
|
+
readonly lastSentAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
221
|
+
readonly notify: ColumnBuilder<boolean, "boolean", boolean>;
|
|
222
|
+
readonly metadata: ColumnBuilder<unknown, "json", boolean>;
|
|
223
|
+
}>, true, never>;
|
|
224
|
+
|
|
225
|
+
export declare type ChatMentionCandidates = typeof ChatMentionCandidatesSchema.Type;
|
|
226
|
+
|
|
227
|
+
export declare interface ChatMentionCandidatesInput {
|
|
228
|
+
readonly channelId: string;
|
|
229
|
+
readonly after?: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
declare const ChatMentionCandidatesSchema: Schema.Struct<{
|
|
233
|
+
readonly authors: Schema.$Array<Schema.Struct<{
|
|
234
|
+
readonly subjectId: Schema.String;
|
|
235
|
+
readonly displayName: Schema.String;
|
|
236
|
+
readonly avatar: Schema.NullOr<Schema.String>;
|
|
237
|
+
}>>;
|
|
238
|
+
readonly after: Schema.NullOr<Schema.String>;
|
|
239
|
+
}>;
|
|
240
|
+
|
|
241
|
+
declare interface ChatMentionDeliveryInput {
|
|
242
|
+
readonly tenantId: string;
|
|
243
|
+
readonly channelId: string;
|
|
244
|
+
readonly messageId: string;
|
|
245
|
+
readonly recipientId: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
declare interface ChatMentionInput {
|
|
249
|
+
readonly body: string;
|
|
250
|
+
readonly subject: Subject;
|
|
251
|
+
readonly maxMentions?: number;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export declare type ChatMessage = typeof ChatMessageSchema.Type;
|
|
255
|
+
|
|
256
|
+
export declare type ChatMessagePage = typeof ChatMessagePageSchema.Type;
|
|
257
|
+
|
|
258
|
+
declare const ChatMessagePageSchema: Schema.Struct<{
|
|
259
|
+
readonly messages: Schema.$Array<Schema.Struct<{
|
|
260
|
+
readonly id: Schema.String;
|
|
261
|
+
readonly channelId: Schema.String;
|
|
262
|
+
readonly authorId: Schema.NullOr<Schema.String>;
|
|
263
|
+
readonly kind: Schema.Literals<readonly ["text", "emote", "system", "media"]>;
|
|
264
|
+
readonly body: Schema.String;
|
|
265
|
+
readonly payload: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
266
|
+
readonly replyToId: Schema.NullOr<Schema.String>;
|
|
267
|
+
readonly editedAt: Schema.NullOr<Schema.Number>;
|
|
268
|
+
readonly deletedAt: Schema.NullOr<Schema.Number>;
|
|
269
|
+
readonly flagged: Schema.Boolean;
|
|
270
|
+
readonly createdAt: Schema.Number;
|
|
271
|
+
readonly version: Schema.Number;
|
|
272
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
273
|
+
}>>;
|
|
274
|
+
readonly before: Schema.NullOr<Schema.Struct<{
|
|
275
|
+
readonly at: Schema.Number;
|
|
276
|
+
readonly id: Schema.String;
|
|
277
|
+
}>>;
|
|
278
|
+
}>;
|
|
279
|
+
|
|
280
|
+
declare const ChatMessageSchema: Schema.Struct<{
|
|
281
|
+
readonly id: Schema.String;
|
|
282
|
+
readonly channelId: Schema.String;
|
|
283
|
+
readonly authorId: Schema.NullOr<Schema.String>;
|
|
284
|
+
readonly kind: Schema.Literals<readonly ["text", "emote", "system", "media"]>;
|
|
285
|
+
readonly body: Schema.String;
|
|
286
|
+
readonly payload: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
287
|
+
readonly replyToId: Schema.NullOr<Schema.String>;
|
|
288
|
+
readonly editedAt: Schema.NullOr<Schema.Number>;
|
|
289
|
+
readonly deletedAt: Schema.NullOr<Schema.Number>;
|
|
290
|
+
readonly flagged: Schema.Boolean;
|
|
291
|
+
readonly createdAt: Schema.Number;
|
|
292
|
+
readonly version: Schema.Number;
|
|
293
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
294
|
+
}>;
|
|
295
|
+
|
|
296
|
+
export declare const chatMessagesTable: Table<"_voltro_chat_messages", FieldDefinitions<{
|
|
297
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
298
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
299
|
+
readonly channelId: ColumnBuilder<string, "text", boolean>;
|
|
300
|
+
readonly authorId: ColumnBuilder<string | null, "text", boolean>;
|
|
301
|
+
readonly requestKey: ColumnBuilder<string, "text", boolean>;
|
|
302
|
+
readonly kind: ColumnBuilder<"text" | "system" | "emote" | "media", "text", boolean>;
|
|
303
|
+
readonly body: ColumnBuilder<string, "text", boolean>;
|
|
304
|
+
readonly originalBody: ColumnBuilder<string, "text", boolean>;
|
|
305
|
+
readonly payload: ColumnBuilder<unknown, "json", boolean>;
|
|
306
|
+
readonly replyToId: ColumnBuilder<string | null, "text", boolean>;
|
|
307
|
+
readonly editedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
308
|
+
readonly deletedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
309
|
+
readonly flagged: ColumnBuilder<boolean, "boolean", boolean>;
|
|
310
|
+
readonly createdAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
311
|
+
readonly version: ColumnBuilder<number, "integer", boolean>;
|
|
312
|
+
readonly metadata: ColumnBuilder<unknown, "json", boolean>;
|
|
313
|
+
}>, true, never>;
|
|
314
|
+
|
|
315
|
+
export declare interface ChatModerationInput {
|
|
316
|
+
readonly body: string;
|
|
317
|
+
readonly denyWords: ReadonlyArray<string>;
|
|
318
|
+
readonly action: 'block' | 'flag';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export declare interface ChatModerationResult {
|
|
322
|
+
readonly body: string;
|
|
323
|
+
readonly flagged: boolean;
|
|
324
|
+
readonly allowed: boolean;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export declare interface ChatOptions {
|
|
328
|
+
readonly maxBodyLength?: number;
|
|
329
|
+
readonly pageSize?: number;
|
|
330
|
+
readonly maxMembers?: number;
|
|
331
|
+
readonly maxChannelsPerSubject?: number;
|
|
332
|
+
readonly retentionMs?: number | null;
|
|
333
|
+
readonly evidenceRetentionMs?: number;
|
|
334
|
+
readonly perChannelRate?: number;
|
|
335
|
+
readonly globalRate?: number;
|
|
336
|
+
readonly maxMentions?: number;
|
|
337
|
+
readonly maxExportRows?: number;
|
|
338
|
+
readonly denyWords?: ReadonlyArray<string>;
|
|
339
|
+
readonly moderationAction?: 'block' | 'flag';
|
|
340
|
+
readonly strategies?: Partial<ChatStrategies>;
|
|
341
|
+
readonly mediaContentTypes?: ReadonlyArray<string>;
|
|
342
|
+
readonly maxMediaBytes?: number;
|
|
343
|
+
readonly mediaUrlTtlSec?: number;
|
|
344
|
+
readonly rateLimit?: RedisStoreOptions;
|
|
345
|
+
readonly now?: () => number;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export declare type ChatOriginal = typeof ChatOriginalSchema.Type;
|
|
349
|
+
|
|
350
|
+
declare const ChatOriginalSchema: Schema.Struct<{
|
|
351
|
+
readonly message: Schema.Struct<{
|
|
352
|
+
readonly id: Schema.String;
|
|
353
|
+
readonly channelId: Schema.String;
|
|
354
|
+
readonly authorId: Schema.NullOr<Schema.String>;
|
|
355
|
+
readonly kind: Schema.Literals<readonly ["text", "emote", "system", "media"]>;
|
|
356
|
+
readonly body: Schema.String;
|
|
357
|
+
readonly payload: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
358
|
+
readonly replyToId: Schema.NullOr<Schema.String>;
|
|
359
|
+
readonly editedAt: Schema.NullOr<Schema.Number>;
|
|
360
|
+
readonly deletedAt: Schema.NullOr<Schema.Number>;
|
|
361
|
+
readonly flagged: Schema.Boolean;
|
|
362
|
+
readonly createdAt: Schema.Number;
|
|
363
|
+
readonly version: Schema.Number;
|
|
364
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
365
|
+
}>;
|
|
366
|
+
readonly originalBody: Schema.String;
|
|
367
|
+
}>;
|
|
368
|
+
|
|
369
|
+
export declare const chatPlugin: (input?: ChatOptions) => VoltroPlugin;
|
|
370
|
+
|
|
371
|
+
export declare interface ChatRateInput {
|
|
372
|
+
readonly channel: ChatChannel;
|
|
373
|
+
readonly perChannel: number;
|
|
374
|
+
readonly global: number;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
declare interface ChatReportContextEvidence {
|
|
378
|
+
readonly kind: 'chat.context';
|
|
379
|
+
readonly channelId: string;
|
|
380
|
+
readonly anchorMessageId: string;
|
|
381
|
+
readonly observedAt: number;
|
|
382
|
+
readonly messages: ReadonlyArray<{
|
|
383
|
+
readonly evidenceId: string | null;
|
|
384
|
+
readonly messageId: string;
|
|
385
|
+
readonly version: number;
|
|
386
|
+
readonly createdAt: number;
|
|
387
|
+
readonly deletedAt: number | null;
|
|
388
|
+
}>;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
declare interface ChatReportContextInput {
|
|
392
|
+
readonly channelId: string;
|
|
393
|
+
readonly messageId: string;
|
|
394
|
+
readonly targetId: string;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
declare interface ChatRetentionBatch {
|
|
398
|
+
readonly deleted: number;
|
|
399
|
+
readonly evidenceDeleted: number;
|
|
400
|
+
readonly channelId: string | null;
|
|
401
|
+
readonly remainingInChannel: boolean;
|
|
402
|
+
readonly evidenceRemainingInChannel: boolean;
|
|
403
|
+
readonly cycleComplete: boolean;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** App-owned sweep progress, not a player's profile/history record. */
|
|
407
|
+
export declare const chatRetentionTable: Table<"_voltro_chat_retention", FieldDefinitions<{
|
|
408
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
409
|
+
readonly tenantId: ColumnBuilder<string | null, "text", boolean>;
|
|
410
|
+
readonly afterChannelId: ColumnBuilder<string | null, "text", boolean>;
|
|
411
|
+
readonly admission: ColumnBuilder<number, "integer", boolean>;
|
|
412
|
+
readonly updatedAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
413
|
+
}>, true, never>;
|
|
414
|
+
|
|
415
|
+
export declare interface ChatService {
|
|
416
|
+
readonly mentionCandidates: (subject: Subject, input: ChatMentionCandidatesInput) => Effect.Effect<ChatMentionCandidates, ChatError>;
|
|
417
|
+
readonly authors: (subject: Subject, input: ChatAuthorsInput) => Effect.Effect<ReadonlyArray<ChatAuthorProjection>, ChatError>;
|
|
418
|
+
readonly prepareTyping: (subject: Subject, input: SetChatTypingInput) => Effect.Effect<ChatTyping, ChatError>;
|
|
419
|
+
readonly dm: (subject: Subject, otherId: string) => Effect.Effect<ChatChannel, ChatError>;
|
|
420
|
+
readonly send: (subject: Subject, input: SendChatInput) => Effect.Effect<ChatMessage, ChatError>;
|
|
421
|
+
readonly edit: (subject: Subject, input: EditChatInput) => Effect.Effect<ChatMessage, ChatError>;
|
|
422
|
+
readonly remove: (subject: Subject, input: DeleteChatInput) => Effect.Effect<ChatMessage, ChatError>;
|
|
423
|
+
readonly messages: (subject: Subject, input: {
|
|
424
|
+
readonly channelId: string;
|
|
425
|
+
readonly before?: {
|
|
426
|
+
readonly at: number;
|
|
427
|
+
readonly id: string;
|
|
428
|
+
} | undefined;
|
|
429
|
+
}) => Effect.Effect<ChatMessagePage, ChatError>;
|
|
430
|
+
readonly channel: (subject: Subject, channelId: string) => Effect.Effect<ChatChannel, ChatError>;
|
|
431
|
+
readonly membership: (subject: Subject, channelId: string) => Effect.Effect<ChatMember, ChatError>;
|
|
432
|
+
readonly channels: (subject: Subject) => Effect.Effect<ReadonlyArray<ChatChannel>, ChatError>;
|
|
433
|
+
readonly unread: (subject: Subject) => Effect.Effect<ReadonlyArray<ChatUnread>, ChatError>;
|
|
434
|
+
readonly original: (subject: Subject, messageId: string) => Effect.Effect<ChatOriginal, ChatError>;
|
|
435
|
+
/** Short-lived storage URL for one retained media message the caller may read. */
|
|
436
|
+
readonly mediaUrl: (subject: Subject, messageId: string) => Effect.Effect<ChatMediaUrl, ChatError>;
|
|
437
|
+
readonly markRead: (subject: Subject, channelId: string, messageId: string) => Effect.Effect<ChatMember, ChatError>;
|
|
438
|
+
readonly moderateMember: (subject: Subject, input: {
|
|
439
|
+
readonly channelId: string;
|
|
440
|
+
readonly subjectId: string;
|
|
441
|
+
readonly mutedUntil: number | null;
|
|
442
|
+
}) => Effect.Effect<ChatMember, ChatError>;
|
|
443
|
+
readonly configure: (subject: Subject, input: {
|
|
444
|
+
readonly channelId: string;
|
|
445
|
+
readonly slowModeMs?: number | undefined;
|
|
446
|
+
readonly frozen?: boolean | undefined;
|
|
447
|
+
}) => Effect.Effect<ChatChannel, ChatError>;
|
|
448
|
+
/** Self-service membership for open `global` channels only; other kinds stay server-administered. */
|
|
449
|
+
readonly join: (subject: Subject, channelId: string) => Effect.Effect<ChatMember, ChatError>;
|
|
450
|
+
readonly leave: (subject: Subject, channelId: string) => Effect.Effect<void, ChatError>;
|
|
451
|
+
readonly transferOwnership: (subject: Subject, channelId: string, targetId: string) => Effect.Effect<void, ChatError>;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export declare interface ChatStrategies {
|
|
455
|
+
readonly moderate: typeof keywordChatModeration;
|
|
456
|
+
readonly rateLimit: typeof fixedChatRateBudgets;
|
|
457
|
+
readonly mentionResolver: typeof playerChatMentions;
|
|
458
|
+
readonly retention: typeof channelChatRetention;
|
|
459
|
+
readonly moderateMedia: typeof typedChatMedia;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export declare const chatSystemContract: {
|
|
463
|
+
readonly slots: {
|
|
464
|
+
readonly moderate: {
|
|
465
|
+
readonly defaultExport: "keywordChatModeration";
|
|
466
|
+
readonly fixtureExport: "chatModerationFixture";
|
|
467
|
+
};
|
|
468
|
+
readonly rateLimit: {
|
|
469
|
+
readonly defaultExport: "fixedChatRateBudgets";
|
|
470
|
+
readonly fixtureExport: "chatRateLimitFixture";
|
|
471
|
+
};
|
|
472
|
+
readonly mentionResolver: {
|
|
473
|
+
readonly defaultExport: "playerChatMentions";
|
|
474
|
+
readonly fixtureExport: "chatMentionResolverFixture";
|
|
475
|
+
};
|
|
476
|
+
readonly retention: {
|
|
477
|
+
readonly defaultExport: "channelChatRetention";
|
|
478
|
+
readonly fixtureExport: "chatRetentionFixture";
|
|
479
|
+
};
|
|
480
|
+
readonly moderateMedia: {
|
|
481
|
+
readonly defaultExport: "typedChatMedia";
|
|
482
|
+
readonly fixtureExport: "chatMediaModerationFixture";
|
|
483
|
+
};
|
|
484
|
+
};
|
|
485
|
+
readonly ports: {};
|
|
486
|
+
readonly events: readonly ["chat.messageChanged", "chat.mentioned", "chat.typing"];
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
export declare type ChatTyping = typeof ChatTypingSchema.Type;
|
|
490
|
+
|
|
491
|
+
declare const ChatTypingSchema: Schema.Struct<{
|
|
492
|
+
readonly subjectId: Schema.NonEmptyString;
|
|
493
|
+
readonly active: Schema.Boolean;
|
|
494
|
+
readonly expiresAt: Schema.Number;
|
|
495
|
+
}>;
|
|
496
|
+
|
|
497
|
+
export declare type ChatUnread = typeof ChatUnreadSchema.Type;
|
|
498
|
+
|
|
499
|
+
declare const ChatUnreadSchema: Schema.Struct<{
|
|
500
|
+
readonly channelId: Schema.String;
|
|
501
|
+
readonly count: Schema.Number;
|
|
502
|
+
readonly truncated: Schema.Boolean;
|
|
503
|
+
}>;
|
|
504
|
+
|
|
505
|
+
export declare interface CreateChatChannelInput {
|
|
506
|
+
readonly tenantId: string;
|
|
507
|
+
readonly kind: typeof CHANNEL_KINDS[number];
|
|
508
|
+
readonly refId: string;
|
|
509
|
+
readonly name: string;
|
|
510
|
+
readonly members: ReadonlyArray<{
|
|
511
|
+
readonly subjectId: string;
|
|
512
|
+
readonly role: ChatMember['role'];
|
|
513
|
+
}>;
|
|
514
|
+
readonly slowModeMs?: number;
|
|
515
|
+
readonly retentionMs?: number | null;
|
|
516
|
+
readonly maxMembers?: number;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export declare const dataStoreChat: (store: DataStore, options: ResolvedChatOptions, limiter: RateLimitStore) => {
|
|
520
|
+
service: ChatService;
|
|
521
|
+
typingPolicy: {
|
|
522
|
+
id: string;
|
|
523
|
+
admit: (value: Parameters< EventClientPolicy["admit"]>[0]) => Effect.Effect<boolean, never, never>;
|
|
524
|
+
deliver: (value: Parameters< EventClientPolicy["deliver"]>[0]) => Effect.Effect<"allow" | "drop" | "deny", never, never>;
|
|
525
|
+
monitor: (value: Parameters< EventClientPolicy["admit"]>[0]) => Effect.Effect<Effect.Effect<void, never, never>, ChatError, Scope>;
|
|
526
|
+
};
|
|
527
|
+
disposeTyping: () => void;
|
|
528
|
+
readReportEvidence: (subject: Subject, input: {
|
|
529
|
+
readonly tenantId: string;
|
|
530
|
+
readonly evidenceIds: ReadonlyArray<string>;
|
|
531
|
+
}) => Effect.Effect<ReadonlyArray< ChatEvidenceSnapshot>, ChatError>;
|
|
532
|
+
collectReportContext: (subject: Subject, input: ChatReportContextInput) => Effect.Effect< ChatReportContextEvidence, ChatError>;
|
|
533
|
+
prune: (subject: Subject) => Effect.Effect< ChatRetentionBatch, ChatError>;
|
|
534
|
+
sweepMedia: (subject: Subject) => Effect.Effect< ChatMediaSweep, ChatError>;
|
|
535
|
+
canNotifyMention: (subject: Subject, input: ChatMentionDeliveryInput) => Effect.Effect<boolean, ChatError>;
|
|
536
|
+
createChannel: (identity: Subject, intention: CreateChatChannelInput) => Effect.Effect<ChatChannel, ChatError>;
|
|
537
|
+
addMember: (subject: Subject, input: {
|
|
538
|
+
readonly tenantId: string;
|
|
539
|
+
readonly channelId: string;
|
|
540
|
+
readonly subjectId: string;
|
|
541
|
+
readonly role: "member" | "mod";
|
|
542
|
+
}) => Effect.Effect<ChatMember, ChatError>;
|
|
543
|
+
removeMember: (subject: Subject, input: {
|
|
544
|
+
readonly tenantId: string;
|
|
545
|
+
readonly channelId: string;
|
|
546
|
+
readonly subjectId: string;
|
|
547
|
+
}) => Effect.Effect<void, ChatError>;
|
|
548
|
+
archiveMatch: (subject: Subject, input: ArchiveMatchInput) => Effect.Effect<ChatChannel, ChatError>;
|
|
549
|
+
exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, ChatError, never>;
|
|
550
|
+
eraseSubject: (input: PluginPrivacyTarget) => Effect.Effect<void, ChatError, never>;
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
export declare const defaultChatStrategies: ChatStrategies;
|
|
554
|
+
|
|
555
|
+
export declare interface DeleteChatInput {
|
|
556
|
+
readonly messageId: string;
|
|
557
|
+
readonly baseVersion: number;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export declare interface EditChatInput {
|
|
561
|
+
readonly messageId: string;
|
|
562
|
+
readonly baseVersion: number;
|
|
563
|
+
readonly body: string;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
declare const fixedChatRateBudgets: (input: ChatRateInput) => {
|
|
567
|
+
readonly perChannel: number;
|
|
568
|
+
readonly global: number;
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
/** Composition over the existing moderation provider, not another classifier. */
|
|
572
|
+
declare const keywordChatModeration: (input: ChatModerationInput) => Effect.Effect<ChatModerationResult, ChatError>;
|
|
573
|
+
|
|
574
|
+
/** Exact Name#Tag claims from Players; Chat still admits every result against its channel. */
|
|
575
|
+
declare const playerChatMentions: (input: ChatMentionInput) => Effect.Effect<ReadonlyArray<string>, ChatError>;
|
|
576
|
+
|
|
577
|
+
export declare const resolveChatOptions: (options?: ChatOptions) => Readonly<{
|
|
578
|
+
maxBodyLength: number;
|
|
579
|
+
pageSize: number;
|
|
580
|
+
maxMembers: number;
|
|
581
|
+
evidenceRetentionMs: number;
|
|
582
|
+
maxChannelsPerSubject: number;
|
|
583
|
+
retentionMs: number | null;
|
|
584
|
+
perChannelRate: number;
|
|
585
|
+
globalRate: number;
|
|
586
|
+
maxMentions: number;
|
|
587
|
+
maxExportRows: number;
|
|
588
|
+
denyWords: readonly string[];
|
|
589
|
+
moderationAction: "flag" | "block";
|
|
590
|
+
mediaContentTypes: readonly string[];
|
|
591
|
+
maxMediaBytes: number;
|
|
592
|
+
mediaUrlTtlSec: number;
|
|
593
|
+
strategies: Readonly<{
|
|
594
|
+
moderate: typeof keywordChatModeration;
|
|
595
|
+
rateLimit: typeof fixedChatRateBudgets;
|
|
596
|
+
mentionResolver: typeof playerChatMentions;
|
|
597
|
+
retention: typeof channelChatRetention;
|
|
598
|
+
moderateMedia: typeof typedChatMedia;
|
|
599
|
+
}>;
|
|
600
|
+
rateLimit: RedisStoreOptions | undefined;
|
|
601
|
+
now: () => number;
|
|
602
|
+
}>;
|
|
603
|
+
|
|
604
|
+
declare type ResolvedChatOptions = ReturnType<typeof resolveChatOptions>;
|
|
605
|
+
|
|
606
|
+
/** `mediaId` names a `_voltro_storage_refs` row the sender uploaded; the body is then an optional caption. */
|
|
607
|
+
export declare interface SendChatInput {
|
|
608
|
+
readonly channelId: string;
|
|
609
|
+
readonly requestId: string;
|
|
610
|
+
readonly body: string;
|
|
611
|
+
readonly replyToId?: string | undefined;
|
|
612
|
+
readonly mediaId?: string | undefined;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
export declare interface SetChatTypingInput {
|
|
616
|
+
readonly channelId: string;
|
|
617
|
+
readonly active: boolean;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/** Declared type and size bounds only. Image classification is an integration: replace this slot to call a provider. */
|
|
621
|
+
declare const typedChatMedia: (input: ChatMediaInput) => Effect.Effect<ChatMediaVerdict, ChatError>;
|
|
622
|
+
|
|
623
|
+
export { }
|