@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.
Files changed (50) hide show
  1. package/CHANGELOG.md +24329 -0
  2. package/LICENSE +61 -0
  3. package/README.md +516 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +14931 -0
  6. package/dist/admissions.entity.js +11 -0
  7. package/dist/channels.entity.js +20 -0
  8. package/dist/chat-app/events/chat.mentioned.event.ts +1 -0
  9. package/dist/chat-app/events/chat.messageChanged.event.ts +1 -0
  10. package/dist/chat-app/events/chat.typing.event.ts +1 -0
  11. package/dist/chat-app/schedules/chat.retention.cron.tsx +16 -0
  12. package/dist/chat-app/subscribers/chat.messages.subscribe.ts +4 -0
  13. package/dist/components.js +432 -0
  14. package/dist/contract.js +92 -0
  15. package/dist/errors.d.ts +13 -0
  16. package/dist/errors.js +21 -0
  17. package/dist/eventProducer.d.ts +18 -0
  18. package/dist/eventProducer.js +46 -0
  19. package/dist/events.d.ts +38 -0
  20. package/dist/events.js +36 -0
  21. package/dist/evidence.entity.js +25 -0
  22. package/dist/index.d.ts +623 -0
  23. package/dist/index.js +181 -0
  24. package/dist/inspect.js +38 -0
  25. package/dist/media.entity.js +15 -0
  26. package/dist/members.entity.js +22 -0
  27. package/dist/mentionDraft.js +21 -0
  28. package/dist/mentionNotifications.js +110 -0
  29. package/dist/messages.entity.js +28 -0
  30. package/dist/reportEvidence.js +16 -0
  31. package/dist/retention.entity.js +11 -0
  32. package/dist/rpc.d.ts +295 -0
  33. package/dist/rpc.js +267 -0
  34. package/dist/rpcRoutes.js +97 -0
  35. package/dist/server.d.ts +200 -0
  36. package/dist/server.js +7 -0
  37. package/dist/service.js +1412 -0
  38. package/dist/strategies.d.ts +148 -0
  39. package/dist/strategies.js +90 -0
  40. package/dist/testing.d.ts +139 -0
  41. package/dist/testing.js +111 -0
  42. package/dist/typing.js +88 -0
  43. package/dist/typingInvalidation.js +86 -0
  44. package/dist/typingLease.js +59 -0
  45. package/dist/typingPublisher.js +59 -0
  46. package/dist/useChatTypingPublisher.js +33 -0
  47. package/dist/useTyping.js +24 -0
  48. package/dist/web.d.ts +354 -0
  49. package/dist/web.js +19 -0
  50. package/package.json +98 -4
package/dist/index.js ADDED
@@ -0,0 +1,181 @@
1
+ import { ChatError as e, chatError as t } from "./errors.js";
2
+ import { chatAdmissionsTable as n } from "./admissions.entity.js";
3
+ import { chatEvidenceTable as r } from "./evidence.entity.js";
4
+ import { CHAT_MAX_MESSAGE_VERSION as i, CHAT_MEDIA_SWEEP_BATCH_SIZE as a, CHAT_RETENTION_BATCH_SIZE as o, CHAT_RETENTION_RUN_BATCHES as s } from "./contract.js";
5
+ import { chatMediaTable as c } from "./media.entity.js";
6
+ import { chatRetentionTable as l } from "./retention.entity.js";
7
+ import { mentioned as u, messageChanged as d, typing as f } from "./events.js";
8
+ import { chatChannelsTable as p } from "./channels.entity.js";
9
+ import { chatMembersTable as m } from "./members.entity.js";
10
+ import { chatMessagesTable as h } from "./messages.entity.js";
11
+ import { dataStoreChat as g } from "./service.js";
12
+ import { BASE_NAME as _, chatRpcClientImports as v } from "./rpc.js";
13
+ import { chatRpcRoutes as y } from "./rpcRoutes.js";
14
+ import { defaultChatStrategies as b, resolveChatOptions as x } from "./strategies.js";
15
+ import { chatStatus as S } from "./inspect.js";
16
+ import { ChatAdministration as C } from "./server.js";
17
+ import { defineLicensedGamePlugin as w } from "@voltro/plugin-licensing/gate";
18
+ import { Effect as T, Layer as E } from "effect";
19
+ import { fileURLToPath as D } from "node:url";
20
+ import { replicaEvidence as O } from "@voltro/protocol/identity";
21
+ import { redisStore as k } from "@voltro/plugin-ratelimit";
22
+ //#region src/index.ts
23
+ var A = {
24
+ slots: {
25
+ moderate: {
26
+ defaultExport: "keywordChatModeration",
27
+ fixtureExport: "chatModerationFixture"
28
+ },
29
+ rateLimit: {
30
+ defaultExport: "fixedChatRateBudgets",
31
+ fixtureExport: "chatRateLimitFixture"
32
+ },
33
+ mentionResolver: {
34
+ defaultExport: "playerChatMentions",
35
+ fixtureExport: "chatMentionResolverFixture"
36
+ },
37
+ retention: {
38
+ defaultExport: "channelChatRetention",
39
+ fixtureExport: "chatRetentionFixture"
40
+ },
41
+ moderateMedia: {
42
+ defaultExport: "typedChatMedia",
43
+ fixtureExport: "chatMediaModerationFixture"
44
+ }
45
+ },
46
+ ports: {},
47
+ events: [
48
+ d.name,
49
+ u.name,
50
+ f.name
51
+ ]
52
+ }, j = (i = {}) => {
53
+ let a = x(i), o = k(a.rateLimit), s, u, d = !1, b = (e) => T.suspend(() => u === void 0 ? T.fail(t("unavailable")) : e(u)), A = (e, n, r) => {
54
+ try {
55
+ let t = structuredClone(e), i = structuredClone(n);
56
+ return b((e) => r(e, t, i));
57
+ } catch {
58
+ return T.fail(t("invalid_input"));
59
+ }
60
+ };
61
+ return w({
62
+ name: _,
63
+ description: "Membership-filtered durable chat with replaceable rule slots.",
64
+ eventClientPolicies: [{
65
+ id: f.clientPolicy,
66
+ admit: (e) => b((t) => t.typingPolicy.admit(e)),
67
+ deliver: (e) => b((t) => t.typingPolicy.deliver(e)),
68
+ monitor: (e) => b((t) => t.typingPolicy.monitor(e))
69
+ }],
70
+ services: E.succeed(C, {
71
+ readReportEvidence: (e, t) => A(e, t, (e, t, n) => e.readReportEvidence(t, n)),
72
+ collectReportContext: (e, t) => A(e, t, (e, t, n) => e.collectReportContext(t, n)),
73
+ prune: (e) => A(e, null, (e, t) => e.prune(t)),
74
+ sweepMedia: (e) => A(e, null, (e, t) => e.sweepMedia(t)),
75
+ canNotifyMention: (e, t) => A(e, t, (e, t, n) => e.canNotifyMention(t, n)),
76
+ createChannel: (e, t) => A(e, t, (e, t, n) => e.createChannel(t, n)),
77
+ addMember: (e, t) => A(e, t, (e, t, n) => e.addMember(t, n)),
78
+ removeMember: (e, t) => A(e, t, (e, t, n) => e.removeMember(t, n)),
79
+ archiveMatch: (e, t) => A(e, t, (e, t, n) => e.archiveMatch(t, n))
80
+ }),
81
+ permissions: ["store:write", "inspect:read"],
82
+ routes: y({
83
+ mentionCandidates: (e, t) => A(e, t, (e, t, n) => e.service.mentionCandidates(t, n)),
84
+ authors: (e, t) => A(e, t, (e, t, n) => e.service.authors(t, n)),
85
+ prepareTyping: (e, t) => b((n) => n.service.prepareTyping(e, t)),
86
+ dm: (e, t) => b((n) => n.service.dm(e, t)),
87
+ send: (e, t) => b((n) => n.service.send(e, t)),
88
+ edit: (e, t) => b((n) => n.service.edit(e, t)),
89
+ remove: (e, t) => b((n) => n.service.remove(e, t)),
90
+ messages: (e, t) => b((n) => n.service.messages(e, t)),
91
+ channel: (e, t) => b((n) => n.service.channel(e, t)),
92
+ membership: (e, t) => b((n) => n.service.membership(e, t)),
93
+ unread: (e) => b((t) => t.service.unread(e)),
94
+ original: (e, t) => b((n) => n.service.original(e, t)),
95
+ mediaUrl: (e, t) => b((n) => n.service.mediaUrl(e, t)),
96
+ channels: (e) => b((t) => t.service.channels(e)),
97
+ markRead: (e, t, n) => b((r) => r.service.markRead(e, t, n)),
98
+ moderateMember: (e, t) => b((n) => n.service.moderateMember(e, t)),
99
+ configure: (e, t) => b((n) => n.service.configure(e, t)),
100
+ join: (e, t) => b((n) => n.service.join(e, t)),
101
+ leave: (e, t) => b((n) => n.service.leave(e, t)),
102
+ transferOwnership: (e, t, n) => b((r) => r.service.transferOwnership(e, t, n))
103
+ }),
104
+ rpcClientDescriptors: v,
105
+ sources: D(new URL("./chat-app", "" + import.meta.url)),
106
+ errorSchemas: [{
107
+ schema: e,
108
+ import: {
109
+ module: "@voltro/plugin-chat/errors",
110
+ name: "ChatError"
111
+ }
112
+ }],
113
+ extendSchema: { tables: [
114
+ p,
115
+ m,
116
+ h,
117
+ l,
118
+ r,
119
+ n,
120
+ c
121
+ ] },
122
+ subjectPrivacy: {
123
+ tables: [
124
+ p.tableName,
125
+ m.tableName,
126
+ h.tableName,
127
+ l.tableName,
128
+ r.tableName,
129
+ n.tableName,
130
+ c.tableName
131
+ ],
132
+ kinds: ["user", "guest"]
133
+ },
134
+ inspectEndpoints: [{
135
+ method: "GET",
136
+ path: "/status",
137
+ scope: "process",
138
+ description: "Declared chat budgets and process binding; no channel/message/body enumeration.",
139
+ handler: () => T.try({
140
+ try: () => ({
141
+ kind: "json",
142
+ data: S(a, u !== void 0, d)
143
+ }),
144
+ catch: () => t("unavailable")
145
+ })
146
+ }],
147
+ bindDataStore: (e) => {
148
+ if (s !== void 0 && s !== e) throw Error("Chat plugin instance cannot cross app stores");
149
+ s = e, u ??= g(e, a, o);
150
+ },
151
+ onActivate: (e) => T.tryPromise({
152
+ try: async () => {
153
+ if (a.rateLimit?.hotStore !== void 0 && O(e.env) !== null) throw t("unavailable");
154
+ await o.activate(e.env, e.connectionRegistry), d = !0;
155
+ },
156
+ catch: () => t("unavailable")
157
+ }),
158
+ onExport: (e, t) => b((n) => n.exportSubject({
159
+ subjectId: e,
160
+ tenantId: t.tenantId,
161
+ kind: t.kind
162
+ })),
163
+ onErase: (e, t) => b((n) => n.eraseSubject({
164
+ subjectId: e,
165
+ tenantId: t.tenantId,
166
+ kind: t.kind
167
+ })),
168
+ onDeactivate: () => T.tryPromise({
169
+ try: async () => {
170
+ try {
171
+ u?.disposeTyping();
172
+ } finally {
173
+ u = void 0, s = void 0, d = !1, await o.deactivate();
174
+ }
175
+ },
176
+ catch: () => t("unavailable")
177
+ })
178
+ });
179
+ };
180
+ //#endregion
181
+ export { i as CHAT_MAX_MESSAGE_VERSION, a as CHAT_MEDIA_SWEEP_BATCH_SIZE, o as CHAT_RETENTION_BATCH_SIZE, s as CHAT_RETENTION_RUN_BATCHES, e as ChatError, n as chatAdmissionsTable, p as chatChannelsTable, r as chatEvidenceTable, c as chatMediaTable, m as chatMembersTable, h as chatMessagesTable, j as chatPlugin, l as chatRetentionTable, A as chatSystemContract, g as dataStoreChat, b as defaultChatStrategies, x as resolveChatOptions };
@@ -0,0 +1,38 @@
1
+ import { chatError as e } from "./errors.js";
2
+ import { defaultChatStrategies as t } from "./strategies.js";
3
+ //#region src/inspect.ts
4
+ var n = (n, r, i) => {
5
+ let a = n.now();
6
+ if (!Number.isSafeInteger(a) || a < 0 || a > 864e13) throw e("unavailable");
7
+ return {
8
+ observedAt: a,
9
+ bound: r,
10
+ rateActive: i,
11
+ maxBodyLength: n.maxBodyLength,
12
+ pageSize: n.pageSize,
13
+ maxMembers: n.maxMembers,
14
+ maxChannelsPerSubject: n.maxChannelsPerSubject,
15
+ retentionMs: n.retentionMs,
16
+ evidenceRetentionMs: n.evidenceRetentionMs,
17
+ perChannelRate: n.perChannelRate,
18
+ globalRate: n.globalRate,
19
+ maxMentions: n.maxMentions,
20
+ moderationAction: n.moderationAction,
21
+ denyWordCount: n.denyWords.length,
22
+ mediaContentTypes: n.mediaContentTypes,
23
+ maxMediaBytes: n.maxMediaBytes,
24
+ mediaUrlTtlSec: n.mediaUrlTtlSec,
25
+ slots: Object.fromEntries(Object.entries(t).map(([e, t]) => [e, n.strategies[e] === t ? "default" : "custom"])),
26
+ tables: [
27
+ "_voltro_chat_channels",
28
+ "_voltro_chat_members",
29
+ "_voltro_chat_messages",
30
+ "_voltro_chat_retention",
31
+ "_voltro_chat_evidence",
32
+ "_voltro_chat_admissions",
33
+ "_voltro_chat_media"
34
+ ]
35
+ };
36
+ };
37
+ //#endregion
38
+ export { n as chatStatus };
@@ -0,0 +1,15 @@
1
+ import { MEDIA_TABLE as e } from "./contract.js";
2
+ import { id as t, table as n, text as r, timestamp as i } from "@voltro/database";
3
+ //#region src/media.entity.ts
4
+ var a = n(e, {
5
+ id: t({ prefix: "cmed" }),
6
+ tenantId: r().maxLength(256).externalId().serverOnly(),
7
+ channelId: r().maxLength(64).serverOnly(),
8
+ messageId: r().maxLength(64).serverOnly(),
9
+ storageId: r().maxLength(256).serverOnly(),
10
+ ownerId: r().maxLength(256).nullable().externalId().sensitive("pii").serverOnly(),
11
+ state: r().maxLength(16).oneOf(["active", "deleting"]).serverOnly(),
12
+ createdAt: i().serverOnly()
13
+ }).index(["tenantId", "ownerId"]).index(["state", "id"]).index(["tenantId", "storageId"]);
14
+ //#endregion
15
+ export { a as chatMediaTable };
@@ -0,0 +1,22 @@
1
+ import { MEMBERS_TABLE as e } from "./contract.js";
2
+ import { boolean as t, id as n, json as r, table as i, text as a, timestamp as o } from "@voltro/database";
3
+ //#region src/members.entity.ts
4
+ var s = i(e, {
5
+ id: n({ prefix: "cmem" }),
6
+ tenantId: a().maxLength(256).externalId().sensitive("pii"),
7
+ channelId: a().maxLength(64).safe(),
8
+ subjectId: a().maxLength(256).externalId().sensitive("pii"),
9
+ role: a().maxLength(16).oneOf([
10
+ "member",
11
+ "mod",
12
+ "owner"
13
+ ]).safe(),
14
+ mutedUntil: o().nullable().safe(),
15
+ lastReadAt: o().safe(),
16
+ lastReadId: a().maxLength(64).nullable().safe(),
17
+ lastSentAt: o().nullable().serverOnly(),
18
+ notify: t().safe(),
19
+ metadata: r().sensitive("pii")
20
+ }).index(["tenantId", "subjectId"]).index(["channelId"]);
21
+ //#endregion
22
+ export { s as chatMembersTable };
@@ -0,0 +1,21 @@
1
+ //#region src/mentionDraft.ts
2
+ var e = (e, t, n) => {
3
+ if (t !== n || !Number.isSafeInteger(t) || t < 0 || t > e.length || t < e.length && /[\p{L}\p{N}\p{M}_#]/u.test(String.fromCodePoint(e.codePointAt(t)))) return null;
4
+ let r = e.lastIndexOf("@", t - 1);
5
+ if (r < 0 || t <= r || r > 0 && !/[\s(\[{]/u.test(e[r - 1])) return null;
6
+ let i = e.slice(r + 1, t);
7
+ return i.length > 261 || /[@\r\n]/u.test(i) ? null : {
8
+ start: r,
9
+ end: t,
10
+ prefix: i
11
+ };
12
+ }, t = (t, n, r, i) => {
13
+ if (!r || r.length > 256 || /[@\r\n]/u.test(r) || !/#\d{4}$/u.test(r) || e(t, n.end, n.end)?.start !== n.start || t.slice(n.start + 1, n.end) !== n.prefix) return null;
14
+ let a = "@" + r + " ", o = t.slice(0, n.start) + a + t.slice(n.end);
15
+ return [...o].length <= i ? {
16
+ body: o,
17
+ caret: n.start + a.length
18
+ } : null;
19
+ };
20
+ //#endregion
21
+ export { t as insertMentionDraft, e as mentionDraftToken };
@@ -0,0 +1,110 @@
1
+ import { chatError as e } from "./errors.js";
2
+ import { MESSAGES_TABLE as t } from "./contract.js";
3
+ import { chatEventTenant as n, committedChatMentions as r } from "./eventProducer.js";
4
+ import { ChatAdministration as i } from "./server.js";
5
+ import { Effect as a, Schema as o } from "effect";
6
+ import { createHash as s } from "node:crypto";
7
+ import { defineOutboxHandler as c, defineSubscriber as l } from "@voltro/runtime";
8
+ import { defineNotification as u, notificationOutboxHandler as d } from "@voltro/plugin-notifications";
9
+ //#region src/mentionNotifications.ts
10
+ var f = "voltro.chat.mention.notify", p = "chat.mention", m = o.NonEmptyString.pipe(o.check(o.isMaxLength(256)), o.check(o.makeFilter((e) => e.trim().length > 0 && !e.includes("\0") && e !== "~"))), h = o.Struct({
11
+ tenantId: m,
12
+ channelId: m,
13
+ messageId: m,
14
+ recipientId: m
15
+ }), g = o.Struct({
16
+ tenantId: m,
17
+ channelId: m,
18
+ messageId: m,
19
+ recipientId: m,
20
+ locale: o.NonEmptyString.pipe(o.check(o.isMaxLength(80)))
21
+ }), _ = u({
22
+ name: "chat.mentioned",
23
+ audience: o.Struct({ userId: m }),
24
+ payload: o.Struct({
25
+ channelId: m,
26
+ messageId: m
27
+ }),
28
+ render: (e, t) => ({
29
+ title: t.locale.startsWith("de") ? "Du wurdest erwähnt" : "You were mentioned",
30
+ body: t.locale.startsWith("de") ? "Öffne den Chat, um die Nachricht zu lesen." : "Open the chat to read the message.",
31
+ data: {
32
+ channelId: e.channelId,
33
+ messageId: e.messageId
34
+ }
35
+ })
36
+ }), v = (u) => {
37
+ let m = structuredClone(u.subject), v = u.run, y = u.service, b = u.outboxForTenant, x = u.localeFor, S = (e) => v(a.flatMap(i, (t) => t.canNotifyMention(m, e))), C = async (e) => {
38
+ let t = o.decodeUnknownSync(h)(e.payload);
39
+ return e.tenantId !== t.tenantId || e.recipientId !== t.recipientId ? !1 : S(t);
40
+ }, w = async (e) => {
41
+ let t = o.decodeUnknownSync(h)(structuredClone(e));
42
+ if (!await S(t)) return null;
43
+ let n = await x?.(t.recipientId, t.tenantId) ?? "en", r = o.decodeUnknownSync(g)({
44
+ ...t,
45
+ locale: n
46
+ }), i = s("sha256").update(JSON.stringify([
47
+ t.tenantId,
48
+ t.messageId,
49
+ t.recipientId
50
+ ])).digest("hex");
51
+ return b(t.tenantId).enqueue(f, { ...r }, {
52
+ idempotencyKey: "chat.mention:" + i,
53
+ maxAttempts: 5
54
+ });
55
+ };
56
+ return {
57
+ deliveryGuard: C,
58
+ enqueue: w,
59
+ outboxHandler: c({
60
+ effect: f,
61
+ maxAttempts: 5,
62
+ handler: async (t) => {
63
+ let n = o.decodeUnknownSync(g)(t.payload);
64
+ if (t.tenantId !== n.tenantId) throw e("identity_required");
65
+ if (!await S(n)) return { skipped: !0 };
66
+ let r = y();
67
+ if (!r) throw e("unavailable");
68
+ return d({
69
+ notifications: [_],
70
+ service: () => ({ send: async (t) => {
71
+ let i = await r.send({
72
+ ...t,
73
+ deliveryGuard: {
74
+ id: p,
75
+ payload: {
76
+ tenantId: n.tenantId,
77
+ channelId: n.channelId,
78
+ messageId: n.messageId,
79
+ recipientId: n.recipientId
80
+ }
81
+ }
82
+ });
83
+ if (i.failed.length > 0) throw e("unavailable");
84
+ return i;
85
+ } })
86
+ }).handler({ payload: {
87
+ notification: _.name,
88
+ recipientId: n.recipientId,
89
+ locale: n.locale,
90
+ tenantId: n.tenantId,
91
+ payload: {
92
+ channelId: n.channelId,
93
+ messageId: n.messageId
94
+ }
95
+ } });
96
+ }
97
+ }),
98
+ subscriber: l({
99
+ table: t,
100
+ on: ["insert"],
101
+ once: !0,
102
+ eventTenant: n,
103
+ handler: async (e) => {
104
+ for (let t of r(e)) await w(t);
105
+ }
106
+ })
107
+ };
108
+ };
109
+ //#endregion
110
+ export { f as CHAT_MENTION_NOTIFICATION_EFFECT, p as CHAT_MENTION_NOTIFICATION_GUARD, v as createChatMentionNotifications };
@@ -0,0 +1,28 @@
1
+ import { MESSAGES_TABLE as e } from "./contract.js";
2
+ import { boolean as t, id as n, integer as r, json as i, table as a, text as o, timestamp as s } from "@voltro/database";
3
+ //#region src/messages.entity.ts
4
+ var c = a(e, {
5
+ id: n({ prefix: "cmsg" }),
6
+ tenantId: o().maxLength(256).externalId().sensitive("pii"),
7
+ channelId: o().maxLength(64).safe(),
8
+ authorId: o().maxLength(256).nullable().externalId().sensitive("pii"),
9
+ requestKey: o().maxLength(64).serverOnly(),
10
+ kind: o().maxLength(16).oneOf([
11
+ "text",
12
+ "emote",
13
+ "system",
14
+ "media"
15
+ ]).safe(),
16
+ body: o().sensitive("pii"),
17
+ originalBody: o().sensitive("pii").serverOnly(),
18
+ payload: i().sensitive("pii"),
19
+ replyToId: o().maxLength(64).nullable().safe(),
20
+ editedAt: s().nullable().safe(),
21
+ deletedAt: s().nullable().safe(),
22
+ flagged: t().safe(),
23
+ createdAt: s().safe(),
24
+ version: r().safe(),
25
+ metadata: i().sensitive("pii")
26
+ }).index(["channelId", "createdAt"]).index(["tenantId", "authorId"]);
27
+ //#endregion
28
+ export { c as chatMessagesTable };
@@ -0,0 +1,16 @@
1
+ import { ChatAdministration as e } from "./server.js";
2
+ import { Effect as t } from "effect";
3
+ import { sanctionsError as n } from "@voltro/plugin-sanctions/errors";
4
+ //#region src/reportEvidence.ts
5
+ var r = (r) => t.gen(function* () {
6
+ if (r.context.channelId === void 0) return [];
7
+ if (!Array.isArray(r.context.messageIds) || r.context.messageIds.length !== 1) return yield* t.fail(n("invalid_input"));
8
+ let i = yield* t.serviceOption(e);
9
+ return i._tag === "None" ? yield* t.fail(n("unavailable")) : [{ ...yield* i.value.collectReportContext(r.subject, {
10
+ channelId: r.context.channelId,
11
+ messageId: r.context.messageIds[0],
12
+ targetId: r.targetId
13
+ }).pipe(t.mapError((e) => n(e.code === "unavailable" ? "unavailable" : "forbidden")), t.catchDefect(() => t.fail(n("unavailable")))) }];
14
+ });
15
+ //#endregion
16
+ export { r as chatSanctionEvidenceCollector };
@@ -0,0 +1,11 @@
1
+ import { id as e, integer as t, table as n, text as r, timestamp as i } from "@voltro/database";
2
+ //#region src/retention.entity.ts
3
+ var a = n("_voltro_chat_retention", {
4
+ id: e({ prefix: "cret" }),
5
+ tenantId: r().maxLength(256).nullable().serverOnly(),
6
+ afterChannelId: r().maxLength(64).nullable().serverOnly(),
7
+ admission: t().serverOnly(),
8
+ updatedAt: i().serverOnly()
9
+ });
10
+ //#endregion
11
+ export { a as chatRetentionTable };