@voltro/plugin-comments 0.85.0 → 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/dist/index.js CHANGED
@@ -1,123 +1,124 @@
1
1
  import { CommentAccessRefused as e, CommentNotFound as t, CommentNotYours as n, CommentStatusRefused as r } from "./errors.js";
2
- import { a as i, c as a, d as o, f as s, h as c, i as l, l as u, m as d, n as f, o as p, p as m, r as h, s as g, t as _, u as v } from "./rpc-BTQBcdhT.js";
3
- import { Effect as y, Option as b } from "effect";
4
- import { and as x, contains as S, eq as C, generateId as w, id as T, inSet as E, json as D, neq as O, or as k, table as A, text as j, timestamp as M } from "@voltro/database";
5
- import { definePlugin as N, pluginInstanceName as P, publishReactivity as F } from "@voltro/protocol";
2
+ import { QUOTE_MAX_LENGTH as i, findQuote as a, textQuote as o } from "./quote.js";
3
+ import { BASE_NAME as s, COMMENT_THREAD_KINDS as c, commentsFeed as l, commentsRpcClientImports as u, createDescriptor as d, deleteDescriptor as f, editDescriptor as p, listDescriptor as m, markReadDescriptor as h, mentionSearchDescriptor as g, reactDescriptor as _, resolveDescriptor as ee } from "./rpc.js";
4
+ import { Effect as v, Option as y } from "effect";
5
+ import { and as b, contains as x, eq as S, generateId as C, id as w, inSet as T, json as E, neq as D, or as O, table as k, text as A, timestamp as j } from "@voltro/database";
6
+ import { definePlugin as M, effectiveScopes as N, pluginInstanceName as P, publishReactivity as F } from "@voltro/protocol";
6
7
  import { NotificationService as I } from "@voltro/plugin-notifications";
7
8
  //#region src/index.ts
8
- var L = A("_voltro_comment_threads", {
9
- id: T({ prefix: "cmtthr" }),
10
- anchor: j(),
11
- quote: D().nullable(),
12
- kind: j().default("discussion"),
13
- status: j().default("open"),
14
- createdBy: j(),
15
- createdAt: M().default("now"),
16
- tenantId: j().nullable()
17
- }).index("byThreadAnchor", ["anchor", "tenantId"]), R = A("_voltro_comments", {
18
- id: T({ prefix: "cmt" }),
19
- threadId: j(),
20
- body: j(),
21
- authorSubjectId: j(),
22
- mentions: D(),
23
- editedAt: M().nullable(),
24
- createdAt: M().default("now"),
25
- tenantId: j().nullable()
26
- }).index("byCommentThread", ["threadId"]), z = A("_voltro_comment_thread_events", {
27
- id: T({ prefix: "cmtevt" }),
28
- threadId: j(),
29
- fromStatus: j().nullable(),
30
- toStatus: j(),
31
- actor: j(),
32
- reason: j().nullable(),
33
- at: M().default("now"),
34
- tenantId: j().nullable()
35
- }).index("byThreadEvents", ["threadId"]), B = A("_voltro_comment_reactions", {
36
- id: T({ prefix: "cmtrx" }),
37
- commentId: j(),
38
- subjectId: j(),
39
- emoji: j()
9
+ var L = k("_voltro_comment_threads", {
10
+ id: w({ prefix: "cmtthr" }),
11
+ anchor: A(),
12
+ quote: E().nullable(),
13
+ kind: A().default("discussion"),
14
+ status: A().default("open"),
15
+ createdBy: A(),
16
+ createdAt: j().default("now"),
17
+ tenantId: A().nullable()
18
+ }).index("byThreadAnchor", ["anchor", "tenantId"]), R = k("_voltro_comments", {
19
+ id: w({ prefix: "cmt" }),
20
+ threadId: A(),
21
+ body: A(),
22
+ authorSubjectId: A(),
23
+ mentions: E(),
24
+ editedAt: j().nullable(),
25
+ createdAt: j().default("now"),
26
+ tenantId: A().nullable()
27
+ }).index("byCommentThread", ["threadId"]), z = k("_voltro_comment_thread_events", {
28
+ id: w({ prefix: "cmtevt" }),
29
+ threadId: A(),
30
+ fromStatus: A().nullable(),
31
+ toStatus: A(),
32
+ actor: A(),
33
+ reason: A().nullable(),
34
+ at: j().default("now"),
35
+ tenantId: A().nullable()
36
+ }).index("byThreadEvents", ["threadId"]), B = k("_voltro_comment_reactions", {
37
+ id: w({ prefix: "cmtrx" }),
38
+ commentId: A(),
39
+ subjectId: A(),
40
+ emoji: A()
40
41
  }).unique("byReactionIdentity", [
41
42
  "commentId",
42
43
  "subjectId",
43
44
  "emoji"
44
- ]).index("byReactionComment", ["commentId"]), V = A("_voltro_comment_reads", {
45
- id: T({ prefix: "cmtread" }),
46
- threadId: j(),
47
- subjectId: j(),
48
- lastReadAt: M()
49
- }).unique("byReadThreadSubject", ["threadId", "subjectId"]), H = _, U = (e) => {
45
+ ]).index("byReactionComment", ["commentId"]), V = k("_voltro_comment_reads", {
46
+ id: w({ prefix: "cmtread" }),
47
+ threadId: A(),
48
+ subjectId: A(),
49
+ lastReadAt: j()
50
+ }).unique("byReadThreadSubject", ["threadId", "subjectId"]), H = s, U = (e) => {
50
51
  let t = e.request.subject ?? {};
51
52
  return {
52
53
  id: t.id ?? null,
53
54
  tenantId: t.tenantId ?? null,
54
- scopes: t.scopes ?? []
55
+ scopes: N(t)
55
56
  };
56
- }, W = (c = {}) => {
57
- let d = P({
57
+ }, W = (i = {}) => {
58
+ let a = P({
58
59
  base: H,
59
- alias: c.alias,
60
- instance: c.name
61
- }), m, _, T = async (e, t, n) => m === void 0 ? [] : m.query({
60
+ alias: i.alias,
61
+ instance: i.name
62
+ }), o, s, w = async (e, t, n) => o === void 0 ? [] : o.query({
62
63
  table: e,
63
64
  predicate: t,
64
65
  order: [],
65
66
  take: n,
66
67
  skip: void 0,
67
68
  projection: void 0
68
- }), D = async (e, t, n, r) => {
69
+ }), E = async (e, t, n, r) => {
69
70
  let i = [], a = [...new Set(n)];
70
71
  for (let n = 0; n < a.length; n += 500) {
71
- let o = E(t, a.slice(n, n + 500));
72
- i.push(...await T(e, r === void 0 ? o : x(o, r)));
72
+ let o = T(t, a.slice(n, n + 500));
73
+ i.push(...await w(e, r === void 0 ? o : b(o, r)));
73
74
  }
74
75
  return i;
75
- }, A = (e, t) => {
76
+ }, k = (e, t) => {
76
77
  let n = /* @__PURE__ */ new Map();
77
78
  for (let r of e) {
78
79
  let e = String(r[t]), i = n.get(e);
79
80
  i === void 0 ? n.set(e, [r]) : i.push(r);
80
81
  }
81
82
  return n;
82
- }, j = () => {
83
- F(_, h);
84
- }, M = (t, n) => y.gen(function* () {
83
+ }, A = () => {
84
+ F(s, l);
85
+ }, j = (t, n) => v.gen(function* () {
85
86
  let r = U(n);
86
- return c.access?.viaEntity === void 0 ? c.access?.scope === void 0 ? yield* y.fail(new e({
87
+ return i.access?.viaEntity === void 0 ? i.access?.scope === void 0 ? yield* v.fail(new e({
87
88
  anchor: t,
88
89
  reason: "no access rule declared — set commentsPlugin({ access: { viaEntity } }) or { access: { scope } }"
89
- })) : r.scopes.includes(c.access.scope) ? void 0 : yield* y.fail(new e({
90
+ })) : r.scopes.includes(i.access.scope) ? void 0 : yield* v.fail(new e({
90
91
  anchor: t,
91
- reason: `missing scope '${c.access.scope}'`
92
- })) : (yield* y.promise(async () => {
92
+ reason: `missing scope '${i.access.scope}'`
93
+ })) : (yield* v.promise(async () => {
93
94
  try {
94
- return await c.access.viaEntity({
95
+ return await i.access.viaEntity({
95
96
  anchor: t,
96
97
  subject: r,
97
- store: m
98
+ store: o
98
99
  });
99
100
  } catch {
100
101
  return !1;
101
102
  }
102
- })) ? void 0 : yield* y.fail(new e({
103
+ })) ? void 0 : yield* v.fail(new e({
103
104
  anchor: t,
104
105
  reason: "the anchored entity is not readable by this caller (or no longer available)"
105
106
  }));
106
- }), W = async (e) => (await T("_voltro_comment_threads", C("id", e), 1))[0], G = (e) => ({
107
+ }), N = async (e) => (await w("_voltro_comment_threads", S("id", e), 1))[0], W = (e) => ({
107
108
  id: String(e.id),
108
109
  anchor: String(e.anchor),
109
- kind: f.includes(String(e.kind)) ? e.kind : "discussion",
110
+ kind: c.includes(String(e.kind)) ? e.kind : "discussion",
110
111
  status: e.status === "resolved" ? "resolved" : "open",
111
112
  createdBy: String(e.createdBy)
112
- }), K = (e, t) => c.visibleTo === void 0 || c.visibleTo({
113
- thread: G(e),
113
+ }), G = (e, t) => i.visibleTo === void 0 || i.visibleTo({
114
+ thread: W(e),
114
115
  subject: U(t)
115
- }), q = async (e, t) => {
116
- let n = await W(e);
117
- return n !== void 0 && K(n, t) ? n : void 0;
118
- }, J = async (e, t) => {
116
+ }), K = async (e, t) => {
117
+ let n = await N(e);
118
+ return n !== void 0 && G(n, t) ? n : void 0;
119
+ }, q = async (e, t) => {
119
120
  await e.insert("_voltro_comment_thread_events", {
120
- id: w({
121
+ id: C({
121
122
  kind: "typeid",
122
123
  prefix: "cmtevt"
123
124
  }, "_voltro_comment_thread_events"),
@@ -129,16 +130,13 @@ var L = A("_voltro_comment_threads", {
129
130
  at: (/* @__PURE__ */ new Date()).toISOString(),
130
131
  tenantId: t.tenantId
131
132
  });
132
- }, Y = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : "", X = (e) => y.gen(function* () {
133
+ }, J = (e) => e instanceof Date ? e.toISOString() : typeof e == "string" ? e : "", Y = (e) => v.gen(function* () {
133
134
  if (e.mentions.length === 0) return;
134
- let t = yield* y.serviceOption(I);
135
- if (b.isNone(t)) {
136
- yield* y.logInfo("comments: mention recorded without notification — @voltro/plugin-notifications is not configured");
137
- return;
138
- }
139
- for (let n of e.mentions) n !== e.author && (yield* y.promise(() => t.value.send({
135
+ let t = yield* v.serviceOption(I);
136
+ if (y.isNone(t)) yield* v.logInfo("comments: mention recorded without notification — @voltro/plugin-notifications is not configured");
137
+ else for (let n of e.mentions) n !== e.author && (yield* v.promise(() => t.value.send({
140
138
  to: n,
141
- category: c.mentionCategory ?? "mention",
139
+ category: i.mentionCategory ?? "mention",
142
140
  title: "You were mentioned",
143
141
  body: e.body.length > 200 ? `${e.body.slice(0, 200)}…` : e.body,
144
142
  data: {
@@ -147,29 +145,29 @@ var L = A("_voltro_comment_threads", {
147
145
  },
148
146
  tenantId: e.tenantId
149
147
  }).then(() => void 0).catch(() => void 0)));
150
- }), Z = async (e, t) => {
151
- if (e.length === 0 || c.resolveMentions === void 0) return [];
148
+ }), X = async (e, t) => {
149
+ if (e.length === 0 || i.resolveMentions === void 0) return [];
152
150
  let n = [];
153
151
  for (let r of [...new Set(e)].slice(0, 20)) {
154
- let e = (await c.resolveMentions({
152
+ let e = (await i.resolveMentions({
155
153
  query: r,
156
154
  subject: t
157
155
  }).catch(() => [])).find((e) => e.subjectId === r);
158
- e !== void 0 && (c.crossTenant === !0 || e.tenantId === void 0 || e.tenantId === null || e.tenantId === t.tenantId) && n.push(r);
156
+ e !== void 0 && (i.crossTenant === !0 || e.tenantId === void 0 || e.tenantId === null || e.tenantId === t.tenantId) && n.push(r);
159
157
  }
160
158
  return n;
161
- }, Q = async (e, t) => {
162
- let { tenantId: n, id: r } = U(t), i = (await T("_voltro_comment_threads", x(C("anchor", e), C("tenantId", n)))).filter((e) => K(e, t));
159
+ }, Z = async (e, t) => {
160
+ let { tenantId: n, id: r } = U(t), i = (await w("_voltro_comment_threads", b(S("anchor", e), S("tenantId", n)))).filter((e) => G(e, t));
163
161
  if (i.length === 0) return [];
164
162
  let a = i.map((e) => String(e.id)), [o, s, c] = await Promise.all([
165
- D("_voltro_comments", "threadId", a),
166
- r === null ? Promise.resolve([]) : D("_voltro_comment_reads", "threadId", a, C("subjectId", r)),
167
- D("_voltro_comment_thread_events", "threadId", a)
168
- ]), l = A(o, "threadId"), u = A(s, "threadId"), d = A(c, "threadId"), f = A(await D("_voltro_comment_reactions", "commentId", o.map((e) => String(e.id))), "commentId"), p = [];
163
+ E("_voltro_comments", "threadId", a),
164
+ r === null ? Promise.resolve([]) : E("_voltro_comment_reads", "threadId", a, S("subjectId", r)),
165
+ E("_voltro_comment_thread_events", "threadId", a)
166
+ ]), l = k(o, "threadId"), u = k(s, "threadId"), d = k(c, "threadId"), f = k(await E("_voltro_comment_reactions", "commentId", o.map((e) => String(e.id))), "commentId"), p = [];
169
167
  for (let e of i) {
170
168
  let t = l.get(String(e.id)) ?? [];
171
- t.sort((e, t) => Y(e.createdAt) < Y(t.createdAt) ? -1 : 1);
172
- let n = u.get(String(e.id)) ?? [], i = n[0] ? Y(n[0].lastReadAt) : "", a = [];
169
+ t.sort((e, t) => J(e.createdAt) < J(t.createdAt) ? -1 : 1);
170
+ let n = u.get(String(e.id)) ?? [], i = n[0] ? J(n[0].lastReadAt) : "", a = [];
173
171
  for (let e of t) {
174
172
  let t = f.get(String(e.id)) ?? [], n = /* @__PURE__ */ new Map();
175
173
  for (let e of t) {
@@ -185,8 +183,8 @@ var L = A("_voltro_comment_threads", {
185
183
  body: String(e.body),
186
184
  authorSubjectId: String(e.authorSubjectId),
187
185
  mentions: e.mentions ?? [],
188
- editedAt: e.editedAt == null ? null : Y(e.editedAt),
189
- createdAt: Y(e.createdAt),
186
+ editedAt: e.editedAt == null ? null : J(e.editedAt),
187
+ createdAt: J(e.createdAt),
190
188
  reactions: [...n.entries()].map(([e, t]) => ({
191
189
  emoji: e,
192
190
  count: t.count,
@@ -195,8 +193,8 @@ var L = A("_voltro_comment_threads", {
195
193
  });
196
194
  }
197
195
  let o = d.get(String(e.id)) ?? [];
198
- o.sort((e, t) => Y(e.at) < Y(t.at) ? -1 : Y(e.at) > Y(t.at) ? 1 : String(e.id) < String(t.id) ? -1 : 1);
199
- let s = G(e);
196
+ o.sort((e, t) => J(e.at) < J(t.at) ? -1 : J(e.at) > J(t.at) ? 1 : String(e.id) < String(t.id) ? -1 : 1);
197
+ let s = W(e);
200
198
  p.push({
201
199
  id: s.id,
202
200
  anchor: s.anchor,
@@ -204,204 +202,204 @@ var L = A("_voltro_comment_threads", {
204
202
  quote: e.quote ?? null,
205
203
  status: s.status,
206
204
  createdBy: String(e.createdBy),
207
- createdAt: Y(e.createdAt),
205
+ createdAt: J(e.createdAt),
208
206
  comments: a,
209
207
  unreadCount: a.filter((e) => String(e.authorSubjectId) !== r && String(e.createdAt) > i).length,
210
208
  history: o.map((e) => ({
211
209
  from: e.fromStatus === "open" || e.fromStatus === "resolved" ? e.fromStatus : null,
212
210
  to: e.toStatus === "resolved" ? "resolved" : "open",
213
211
  by: String(e.actor),
214
- at: Y(e.at),
212
+ at: J(e.at),
215
213
  reason: e.reason == null ? null : String(e.reason)
216
214
  }))
217
215
  });
218
216
  }
219
217
  return p.sort((e, t) => String(e.createdAt) < String(t.createdAt) ? -1 : 1), p;
220
- }, ee = [
218
+ }, Q = [
221
219
  {
222
- ...a,
220
+ ...m,
223
221
  description: "Threads + comments + reactions + unread for one anchor, live.",
224
- execute: (e, t) => y.gen(function* () {
222
+ execute: (e, t) => v.gen(function* () {
225
223
  let { anchor: n } = e;
226
- return yield* M(n, t), yield* y.promise(() => Q(n, t));
224
+ return yield* j(n, t), yield* v.promise(() => Z(n, t));
227
225
  })
228
226
  },
229
227
  {
230
- ...i,
228
+ ...d,
231
229
  description: "Comment on an anchor — a reply into a thread, or a new thread.",
232
- execute: (n, r) => y.gen(function* () {
230
+ execute: (n, r) => v.gen(function* () {
233
231
  let i = n;
234
- yield* M(i.anchor, r);
235
- let a = U(r), o = a.id ?? "anonymous", s = m;
236
- if (s === void 0) return yield* y.fail(new t({ id: i.anchor }));
237
- let c = i.threadId;
238
- if (c !== void 0) {
239
- let e = yield* y.promise(() => q(c, r));
240
- if (e === void 0 || String(e.anchor) !== i.anchor) return yield* y.fail(new t({ id: c }));
232
+ yield* j(i.anchor, r);
233
+ let a = U(r), s = a.id ?? "anonymous", c = o;
234
+ if (c === void 0) return yield* v.fail(new t({ id: i.anchor }));
235
+ let l = i.threadId;
236
+ if (l !== void 0) {
237
+ let e = yield* v.promise(() => K(l, r));
238
+ if (e === void 0 || String(e.anchor) !== i.anchor) return yield* v.fail(new t({ id: l }));
241
239
  } else {
242
- let t = w({
240
+ let t = C({
243
241
  kind: "typeid",
244
242
  prefix: "cmtthr"
245
243
  }, "_voltro_comment_threads");
246
- c = t;
244
+ l = t;
247
245
  let n = i.kind ?? "discussion";
248
- if (!K({
246
+ if (!G({
249
247
  id: t,
250
248
  anchor: i.anchor,
251
249
  kind: n,
252
250
  status: "open",
253
- createdBy: o
254
- }, r)) return yield* y.fail(new e({
251
+ createdBy: s
252
+ }, r)) return yield* v.fail(new e({
255
253
  anchor: i.anchor,
256
254
  reason: `a ${n} thread here would not be visible to its author`
257
255
  }));
258
- yield* y.promise(async () => {
259
- await s.insert("_voltro_comment_threads", {
256
+ yield* v.promise(async () => {
257
+ await c.insert("_voltro_comment_threads", {
260
258
  id: t,
261
259
  anchor: i.anchor,
262
260
  quote: i.quote ?? null,
263
261
  kind: n,
264
262
  status: "open",
265
- createdBy: o,
263
+ createdBy: s,
266
264
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
267
265
  tenantId: a.tenantId
268
- }), await J(s, {
266
+ }), await q(c, {
269
267
  threadId: t,
270
268
  from: null,
271
269
  to: "open",
272
- actor: o,
270
+ actor: s,
273
271
  reason: null,
274
272
  tenantId: a.tenantId
275
273
  });
276
274
  });
277
275
  }
278
- let l = yield* y.promise(() => Z(i.mentions ?? [], a)), u = w({
276
+ let u = yield* v.promise(() => X(i.mentions ?? [], a)), d = C({
279
277
  kind: "typeid",
280
278
  prefix: "cmt"
281
279
  }, "_voltro_comments");
282
- return yield* y.promise(() => s.insert("_voltro_comments", {
283
- id: u,
284
- threadId: c,
280
+ return yield* v.promise(() => c.insert("_voltro_comments", {
281
+ id: d,
282
+ threadId: l,
285
283
  body: i.body,
286
- authorSubjectId: o,
287
- mentions: l,
284
+ authorSubjectId: s,
285
+ mentions: u,
288
286
  editedAt: null,
289
287
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
290
288
  tenantId: a.tenantId
291
- })), j(), yield* X({
292
- mentions: l,
293
- author: o,
289
+ })), A(), yield* Y({
290
+ mentions: u,
291
+ author: s,
294
292
  anchor: i.anchor,
295
- threadId: c,
293
+ threadId: l,
296
294
  body: i.body,
297
295
  tenantId: a.tenantId
298
296
  }), {
299
- threadId: c,
300
- commentId: u
297
+ threadId: l,
298
+ commentId: d
301
299
  };
302
300
  })
303
301
  },
304
302
  {
305
- ...g,
303
+ ...p,
306
304
  description: "Edit your own comment.",
307
- execute: (e, r) => y.gen(function* () {
308
- let i = e, a = (yield* y.promise(() => T("_voltro_comments", C("id", i.commentId), 1)))[0];
309
- if (a === void 0) return yield* y.fail(new t({ id: i.commentId }));
310
- let o = yield* y.promise(() => q(String(a.threadId), r));
311
- return o === void 0 ? yield* y.fail(new t({ id: i.commentId })) : (yield* M(String(o.anchor), r), String(a.authorSubjectId) === (U(r).id ?? "anonymous") ? (yield* y.promise(() => m.update("_voltro_comments", i.commentId, {
305
+ execute: (e, r) => v.gen(function* () {
306
+ let i = e, a = (yield* v.promise(() => w("_voltro_comments", S("id", i.commentId), 1)))[0];
307
+ if (a === void 0) return yield* v.fail(new t({ id: i.commentId }));
308
+ let s = yield* v.promise(() => K(String(a.threadId), r));
309
+ return s === void 0 ? yield* v.fail(new t({ id: i.commentId })) : (yield* j(String(s.anchor), r), String(a.authorSubjectId) === (U(r).id ?? "anonymous") ? (yield* v.promise(() => o.update("_voltro_comments", i.commentId, {
312
310
  body: i.body,
313
311
  editedAt: (/* @__PURE__ */ new Date()).toISOString()
314
- })), j(), { ok: !0 }) : yield* y.fail(new n({ id: i.commentId })));
312
+ })), A(), { ok: !0 }) : yield* v.fail(new n({ id: i.commentId })));
315
313
  })
316
314
  },
317
315
  {
318
- ...s,
316
+ ...ee,
319
317
  description: "Resolve or reopen a thread.",
320
- execute: (e, n) => y.gen(function* () {
321
- let i = e, a = yield* y.promise(() => q(i.threadId, n));
322
- if (a === void 0) return yield* y.fail(new t({ id: i.threadId }));
323
- yield* M(String(a.anchor), n);
324
- let o = G(a), s = i.resolved ? "resolved" : "open";
325
- if (o.status === s) return { ok: !0 };
326
- let l = U(n);
327
- if (c.statusPolicy !== void 0 && !(yield* y.promise(async () => {
318
+ execute: (e, n) => v.gen(function* () {
319
+ let a = e, s = yield* v.promise(() => K(a.threadId, n));
320
+ if (s === void 0) return yield* v.fail(new t({ id: a.threadId }));
321
+ yield* j(String(s.anchor), n);
322
+ let c = W(s), l = a.resolved ? "resolved" : "open";
323
+ if (c.status === l) return { ok: !0 };
324
+ let u = U(n);
325
+ if (i.statusPolicy !== void 0 && !(yield* v.promise(async () => {
328
326
  try {
329
- return await c.statusPolicy({
330
- thread: o,
331
- to: s,
332
- subject: l,
333
- store: m
327
+ return await i.statusPolicy({
328
+ thread: c,
329
+ to: l,
330
+ subject: u,
331
+ store: o
334
332
  });
335
333
  } catch {
336
334
  return !1;
337
335
  }
338
- }))) return yield* y.fail(new r({
339
- threadId: i.threadId,
340
- reason: `the status policy does not let this caller ${i.resolved ? "resolve" : "reopen"} this ${o.kind} thread`
336
+ }))) return yield* v.fail(new r({
337
+ threadId: a.threadId,
338
+ reason: `the status policy does not let this caller ${a.resolved ? "resolve" : "reopen"} this ${c.kind} thread`
341
339
  }));
342
- let u = i.reason?.trim() ? i.reason.trim() : null;
343
- return yield* y.promise(async () => {
344
- await m.update("_voltro_comment_threads", i.threadId, { status: s }), await J(m, {
345
- threadId: i.threadId,
346
- from: o.status,
347
- to: s,
348
- actor: l.id ?? "anonymous",
349
- reason: u,
350
- tenantId: l.tenantId
340
+ let d = a.reason?.trim() ? a.reason.trim() : null;
341
+ return yield* v.promise(async () => {
342
+ await o.update("_voltro_comment_threads", a.threadId, { status: l }), await q(o, {
343
+ threadId: a.threadId,
344
+ from: c.status,
345
+ to: l,
346
+ actor: u.id ?? "anonymous",
347
+ reason: d,
348
+ tenantId: u.tenantId
351
349
  });
352
- }), j(), { ok: !0 };
350
+ }), A(), { ok: !0 };
353
351
  })
354
352
  },
355
353
  {
356
- ...p,
354
+ ...f,
357
355
  description: "Delete your own comment (comments:moderate deletes any).",
358
- execute: (e, r) => y.gen(function* () {
359
- let i = e, a = (yield* y.promise(() => T("_voltro_comments", C("id", i.commentId), 1)))[0];
360
- if (a === void 0) return yield* y.fail(new t({ id: i.commentId }));
361
- let o = yield* y.promise(() => q(String(a.threadId), r));
362
- if (o === void 0) return yield* y.fail(new t({ id: i.commentId }));
363
- yield* M(String(o.anchor), r);
364
- let s = U(r);
365
- return String(a.authorSubjectId) !== (s.id ?? "anonymous") && !s.scopes.includes("comments:moderate") ? yield* y.fail(new n({ id: i.commentId })) : (yield* y.promise(async () => {
366
- for (let e of await T("_voltro_comment_reactions", C("commentId", i.commentId))) await m.delete("_voltro_comment_reactions", String(e.id));
367
- await m.delete("_voltro_comments", i.commentId);
368
- }), j(), { ok: !0 });
356
+ execute: (e, r) => v.gen(function* () {
357
+ let i = e, a = (yield* v.promise(() => w("_voltro_comments", S("id", i.commentId), 1)))[0];
358
+ if (a === void 0) return yield* v.fail(new t({ id: i.commentId }));
359
+ let s = yield* v.promise(() => K(String(a.threadId), r));
360
+ if (s === void 0) return yield* v.fail(new t({ id: i.commentId }));
361
+ yield* j(String(s.anchor), r);
362
+ let c = U(r);
363
+ return String(a.authorSubjectId) !== (c.id ?? "anonymous") && !c.scopes.includes("comments:moderate") ? yield* v.fail(new n({ id: i.commentId })) : (yield* v.promise(async () => {
364
+ for (let e of await w("_voltro_comment_reactions", S("commentId", i.commentId))) await o.delete("_voltro_comment_reactions", String(e.id));
365
+ await o.delete("_voltro_comments", i.commentId);
366
+ }), A(), { ok: !0 });
369
367
  })
370
368
  },
371
369
  {
372
- ...o,
370
+ ..._,
373
371
  description: "Toggle an emoji reaction on a comment.",
374
- execute: (e, n) => y.gen(function* () {
375
- let r = e, i = (yield* y.promise(() => T("_voltro_comments", C("id", r.commentId), 1)))[0];
376
- if (i === void 0) return yield* y.fail(new t({ id: r.commentId }));
377
- let a = yield* y.promise(() => q(String(i.threadId), n));
378
- if (a === void 0) return yield* y.fail(new t({ id: r.commentId }));
379
- yield* M(String(a.anchor), n);
380
- let o = U(n).id ?? "anonymous", s = (yield* y.promise(() => T("_voltro_comment_reactions", x(C("commentId", r.commentId), x(C("subjectId", o), C("emoji", r.emoji))), 1)))[0];
381
- if (s !== void 0) return yield* y.promise(() => m.delete("_voltro_comment_reactions", String(s.id))), j(), { reacted: !1 };
382
- let c = w({
372
+ execute: (e, n) => v.gen(function* () {
373
+ let r = e, i = (yield* v.promise(() => w("_voltro_comments", S("id", r.commentId), 1)))[0];
374
+ if (i === void 0) return yield* v.fail(new t({ id: r.commentId }));
375
+ let a = yield* v.promise(() => K(String(i.threadId), n));
376
+ if (a === void 0) return yield* v.fail(new t({ id: r.commentId }));
377
+ yield* j(String(a.anchor), n);
378
+ let s = U(n).id ?? "anonymous", c = (yield* v.promise(() => w("_voltro_comment_reactions", b(S("commentId", r.commentId), b(S("subjectId", s), S("emoji", r.emoji))), 1)))[0];
379
+ if (c !== void 0) return yield* v.promise(() => o.delete("_voltro_comment_reactions", String(c.id))), A(), { reacted: !1 };
380
+ let l = C({
383
381
  kind: "typeid",
384
382
  prefix: "cmtrx"
385
383
  }, "_voltro_comment_reactions");
386
- return yield* y.promise(() => m.insert("_voltro_comment_reactions", {
387
- id: c,
384
+ return yield* v.promise(() => o.insert("_voltro_comment_reactions", {
385
+ id: l,
388
386
  commentId: r.commentId,
389
- subjectId: o,
387
+ subjectId: s,
390
388
  emoji: r.emoji
391
- })), j(), { reacted: !0 };
389
+ })), A(), { reacted: !0 };
392
390
  })
393
391
  },
394
392
  {
395
- ...u,
393
+ ...h,
396
394
  description: "Stamp the caller's read marker for a thread.",
397
- execute: (e, n) => y.gen(function* () {
395
+ execute: (e, n) => v.gen(function* () {
398
396
  let r = e;
399
- if ((yield* y.promise(() => W(r.threadId))) === void 0) return yield* y.fail(new t({ id: r.threadId }));
400
- let i = U(n).id ?? "anonymous", a = w({
397
+ if ((yield* v.promise(() => N(r.threadId))) === void 0) return yield* v.fail(new t({ id: r.threadId }));
398
+ let i = U(n).id ?? "anonymous", a = C({
401
399
  kind: "typeid",
402
400
  prefix: "cmtread"
403
401
  }, "_voltro_comment_reads");
404
- return yield* y.promise(() => m.upsert("_voltro_comment_reads", {
402
+ return yield* v.promise(() => o.upsert("_voltro_comment_reads", {
405
403
  id: a,
406
404
  threadId: r.threadId,
407
405
  subjectId: i,
@@ -413,19 +411,19 @@ var L = A("_voltro_comment_threads", {
413
411
  })
414
412
  },
415
413
  {
416
- ...v,
414
+ ...g,
417
415
  description: "@-mention autocomplete over the app-declared directory, tenant-filtered.",
418
- execute: (e, t) => y.promise(async () => {
416
+ execute: (e, t) => v.promise(async () => {
419
417
  let { query: n } = e;
420
- if (c.resolveMentions === void 0) return [];
418
+ if (i.resolveMentions === void 0) return [];
421
419
  let r = U(t);
422
- return (await c.resolveMentions({
420
+ return (await i.resolveMentions({
423
421
  query: n,
424
422
  subject: {
425
423
  id: r.id,
426
424
  tenantId: r.tenantId
427
425
  }
428
- }).catch(() => [])).filter((e) => c.crossTenant === !0 || e.tenantId === void 0 || e.tenantId === null || e.tenantId === r.tenantId).map((e) => ({
426
+ }).catch(() => [])).filter((e) => i.crossTenant === !0 || e.tenantId === void 0 || e.tenantId === null || e.tenantId === r.tenantId).map((e) => ({
429
427
  subjectId: e.subjectId,
430
428
  label: e.label
431
429
  }));
@@ -435,8 +433,8 @@ var L = A("_voltro_comment_threads", {
435
433
  kind: "json",
436
434
  data: e
437
435
  });
438
- return N({
439
- name: d,
436
+ return M({
437
+ name: a,
440
438
  baseName: H,
441
439
  description: "Comment threads on any app entity — replies, resolve/reopen, @-mentions with notifications, reactions, unread — live over the reactive engine.",
442
440
  permissions: ["inspect:read", "store:write"],
@@ -447,17 +445,17 @@ var L = A("_voltro_comment_threads", {
447
445
  B,
448
446
  V
449
447
  ] },
450
- routes: ee,
451
- rpcClientDescriptors: l,
448
+ routes: Q,
449
+ rpcClientDescriptors: u,
452
450
  inspectEndpoints: [{
453
451
  method: "GET",
454
452
  path: "/threads",
455
453
  scope: "process",
456
454
  description: "Thread volume and searchable, paginated threads (operator surface).",
457
- handler: (e) => y.promise(async () => {
455
+ handler: (e) => v.promise(async () => {
458
456
  let t = new URL(e.url, "http://inspect.local").searchParams, n = t.get("threadId"), r = Number(t.get("offset") ?? 0), i = Number.isSafeInteger(r) && r >= 0 ? r : 0, a = (t.get("search") ?? "").trim().slice(0, 200);
459
457
  if (n) {
460
- let e = (await T("_voltro_comment_threads", C("id", n), 1))[0], t = C("threadId", n), [r, a] = e && m ? await Promise.all([m.query({
458
+ let e = (await w("_voltro_comment_threads", S("id", n), 1))[0], t = S("threadId", n), [r, a] = e && o ? await Promise.all([o.query({
461
459
  table: "_voltro_comments",
462
460
  predicate: t,
463
461
  order: [{
@@ -470,7 +468,7 @@ var L = A("_voltro_comment_threads", {
470
468
  take: 50,
471
469
  skip: i,
472
470
  projection: void 0
473
- }), m.query({
471
+ }), o.query({
474
472
  table: "_voltro_comments",
475
473
  predicate: t,
476
474
  order: [],
@@ -481,32 +479,32 @@ var L = A("_voltro_comment_threads", {
481
479
  op: "count",
482
480
  alias: "count"
483
481
  }]
484
- })]) : [[], []], o = Number(a[0]?.count ?? 0);
482
+ })]) : [[], []], s = Number(a[0]?.count ?? 0);
485
483
  return $({
486
484
  stats: {
487
485
  threads: +!!e,
488
486
  open: e && e.status !== "resolved" ? 1 : 0,
489
- comments: o
487
+ comments: s
490
488
  },
491
489
  recent: [],
492
490
  detail: {
493
491
  threadId: n,
494
492
  found: !!e,
495
493
  offset: i,
496
- total: o,
494
+ total: s,
497
495
  messages: r.map((e) => ({
498
496
  id: String(e.id),
499
497
  body: String(e.body),
500
498
  author: String(e.authorSubjectId),
501
- createdAt: Y(e.createdAt),
502
- editedAt: e.editedAt == null ? null : Y(e.editedAt)
499
+ createdAt: J(e.createdAt),
500
+ editedAt: e.editedAt == null ? null : J(e.editedAt)
503
501
  }))
504
502
  }
505
503
  });
506
504
  }
507
- if (!m) throw Error("Comments store is not available");
508
- let o = async (e, t) => {
509
- let n = await m.query({
505
+ if (!o) throw Error("Comments store is not available");
506
+ let s = async (e, t) => {
507
+ let n = await o.query({
510
508
  table: e,
511
509
  predicate: t,
512
510
  order: [],
@@ -519,10 +517,10 @@ var L = A("_voltro_comment_threads", {
519
517
  }]
520
518
  });
521
519
  return Number(n[0]?.count ?? 0);
522
- }, s = a ? k(S("anchor", a), S("id", a), S("createdBy", a)) : void 0, [c, l, u, d, f] = await Promise.all([
523
- m.query({
520
+ }, c = a ? O(x("anchor", a), x("id", a), x("createdBy", a)) : void 0, [l, u, d, f, p] = await Promise.all([
521
+ o.query({
524
522
  table: "_voltro_comment_threads",
525
- predicate: s,
523
+ predicate: c,
526
524
  order: [{
527
525
  column: "createdAt",
528
526
  direction: "desc"
@@ -534,13 +532,13 @@ var L = A("_voltro_comment_threads", {
534
532
  skip: i,
535
533
  projection: void 0
536
534
  }),
537
- o("_voltro_comment_threads"),
538
- o("_voltro_comment_threads", O("status", "resolved")),
539
- o("_voltro_comments"),
540
- o("_voltro_comment_threads", s)
541
- ]), p = c.length === 0 ? [] : await m.query({
535
+ s("_voltro_comment_threads"),
536
+ s("_voltro_comment_threads", D("status", "resolved")),
537
+ s("_voltro_comments"),
538
+ s("_voltro_comment_threads", c)
539
+ ]), m = l.length === 0 ? [] : await o.query({
542
540
  table: "_voltro_comments",
543
- predicate: E("threadId", c.map((e) => String(e.id))),
541
+ predicate: T("threadId", l.map((e) => String(e.id))),
544
542
  order: [],
545
543
  take: void 0,
546
544
  skip: void 0,
@@ -554,38 +552,38 @@ var L = A("_voltro_comment_threads", {
554
552
  alias: "count"
555
553
  }],
556
554
  groupBy: ["threadId"]
557
- }), h = new Map(p.map((e) => [String(e.threadId), Number(e.count)]));
555
+ }), h = new Map(m.map((e) => [String(e.threadId), Number(e.count)]));
558
556
  return $({
559
557
  stats: {
560
- threads: l,
561
- open: u,
562
- comments: d
558
+ threads: u,
559
+ open: d,
560
+ comments: f
563
561
  },
564
562
  page: {
565
563
  offset: i,
566
564
  search: a,
567
- total: f,
565
+ total: p,
568
566
  pageSize: 50
569
567
  },
570
- recent: c.map((e) => ({
568
+ recent: l.map((e) => ({
571
569
  id: String(e.id),
572
570
  anchor: String(e.anchor),
573
571
  status: String(e.status),
574
572
  createdBy: String(e.createdBy),
575
- createdAt: Y(e.createdAt),
573
+ createdAt: J(e.createdAt),
576
574
  comments: h.get(String(e.id)) ?? 0
577
575
  }))
578
576
  });
579
577
  })
580
578
  }],
581
579
  bindDataStore: (e) => {
582
- m = e, _ = e;
580
+ o = e, s = e;
583
581
  },
584
- onActivate: (e) => y.sync(() => {
585
- c.access?.viaEntity === void 0 && c.access?.scope === void 0 && e.logger.warn("comments: no access rule declared — EVERY read and write will be refused (fail-closed). Set commentsPlugin({ access: { viaEntity } }) or { access: { scope } }."), e.logger.info("comments active", { mentions: c.resolveMentions !== void 0 });
582
+ onActivate: (e) => v.sync(() => {
583
+ i.access?.viaEntity === void 0 && i.access?.scope === void 0 && e.logger.warn("comments: no access rule declared — EVERY read and write will be refused (fail-closed). Set commentsPlugin({ access: { viaEntity } }) or { access: { scope } }."), e.logger.info("comments active", { mentions: i.resolveMentions !== void 0 });
586
584
  }),
587
- onDeactivate: () => y.sync(() => {
588
- m = void 0, _ = void 0;
585
+ onDeactivate: () => v.sync(() => {
586
+ o = void 0, s = void 0;
589
587
  })
590
588
  });
591
589
  }, G = async (e, t, n = /* @__PURE__ */ new Date()) => {
@@ -600,20 +598,20 @@ var L = A("_voltro_comment_threads", {
600
598
  for (let [o, s] of Object.entries(t)) {
601
599
  if (s === void 0 || !(s >= 0)) continue;
602
600
  let t = n.getTime() - s * 864e5;
603
- for (let c of await r("_voltro_comment_threads", x(C("status", "resolved"), C("kind", o)))) {
604
- let o = [...await r("_voltro_comment_thread_events", C("threadId", String(c.id)))], l = (e) => new Date(e.at instanceof Date ? e.at : String(e.at)).getTime();
601
+ for (let c of await r("_voltro_comment_threads", b(S("status", "resolved"), S("kind", o)))) {
602
+ let o = [...await r("_voltro_comment_thread_events", S("threadId", String(c.id)))], l = (e) => new Date(e.at instanceof Date ? e.at : String(e.at)).getTime();
605
603
  o.sort((e, t) => l(e) - l(t));
606
604
  let u = [...o].reverse().find((e) => e.toStatus === "resolved" && e.fromStatus === "open");
607
605
  if (u === void 0 || l(u) > t) continue;
608
- let d = await r("_voltro_comments", C("threadId", String(c.id)));
606
+ let d = await r("_voltro_comments", S("threadId", String(c.id)));
609
607
  if (d.length !== 0) {
610
608
  for (let t of d) {
611
- for (let n of await r("_voltro_comment_reactions", C("commentId", String(t.id)))) await e.delete("_voltro_comment_reactions", String(n.id));
609
+ for (let n of await r("_voltro_comment_reactions", S("commentId", String(t.id)))) await e.delete("_voltro_comment_reactions", String(n.id));
612
610
  await e.delete("_voltro_comments", String(t.id));
613
611
  }
614
- for (let t of await r("_voltro_comment_reads", C("threadId", String(c.id)))) await e.delete("_voltro_comment_reads", String(t.id));
612
+ for (let t of await r("_voltro_comment_reads", S("threadId", String(c.id)))) await e.delete("_voltro_comment_reads", String(t.id));
615
613
  await e.insert("_voltro_comment_thread_events", {
616
- id: w({
614
+ id: C({
617
615
  kind: "typeid",
618
616
  prefix: "cmtevt"
619
617
  }, "_voltro_comment_thread_events"),
@@ -634,4 +632,4 @@ var L = A("_voltro_comment_threads", {
634
632
  };
635
633
  }, K = () => "plugin-comments";
636
634
  //#endregion
637
- export { f as COMMENT_THREAD_KINDS, e as CommentAccessRefused, t as CommentNotFound, n as CommentNotYours, r as CommentStatusRefused, m as QUOTE_MAX_LENGTH, G as applyCommentRetention, B as commentReactionsTable, V as commentReadsTable, z as commentThreadEventsTable, L as commentThreadsTable, h as commentsFeed, W as commentsPlugin, R as commentsTable, d as findQuote, K as pluginComments, c as textQuote };
635
+ export { c as COMMENT_THREAD_KINDS, e as CommentAccessRefused, t as CommentNotFound, n as CommentNotYours, r as CommentStatusRefused, i as QUOTE_MAX_LENGTH, G as applyCommentRetention, B as commentReactionsTable, V as commentReadsTable, z as commentThreadEventsTable, L as commentThreadsTable, l as commentsFeed, W as commentsPlugin, R as commentsTable, a as findQuote, K as pluginComments, o as textQuote };