@leemour/cli-messaging 0.146.0 → 0.147.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/background/units.d.ts +1 -0
- package/dist/background/units.d.ts.map +1 -1
- package/dist/background/units.js +9 -0
- package/dist/background/units.js.map +1 -1
- package/dist/cli/bot/people.js +1 -1
- package/dist/cli/bot/people.js.map +1 -1
- package/dist/cli/messenger/backfill-command.d.ts.map +1 -1
- package/dist/cli/messenger/backfill-command.js +4 -0
- package/dist/cli/messenger/backfill-command.js.map +1 -1
- package/dist/cli/messenger/chats-members-command.d.ts.map +1 -1
- package/dist/cli/messenger/chats-members-command.js +35 -1
- package/dist/cli/messenger/chats-members-command.js.map +1 -1
- package/dist/cli/messenger/chats-stats-command.js +1 -1
- package/dist/cli/messenger/chats-stats-command.js.map +1 -1
- package/dist/cli/messenger/context.d.ts +2 -0
- package/dist/cli/messenger/context.d.ts.map +1 -1
- package/dist/cli/messenger/context.js.map +1 -1
- package/dist/cli/messenger/messages-search-command.d.ts.map +1 -1
- package/dist/cli/messenger/messages-search-command.js +3 -1
- package/dist/cli/messenger/messages-search-command.js.map +1 -1
- package/dist/cli/messenger/points.d.ts +2 -1
- package/dist/cli/messenger/points.d.ts.map +1 -1
- package/dist/cli/messenger/points.js +1 -0
- package/dist/cli/messenger/points.js.map +1 -1
- package/dist/cli/messenger/server-command.d.ts.map +1 -1
- package/dist/cli/messenger/server-command.js +18 -2
- package/dist/cli/messenger/server-command.js.map +1 -1
- package/dist/domain/models.d.ts +10 -0
- package/dist/domain/models.d.ts.map +1 -1
- package/dist/mcp/prompts.d.ts.map +1 -1
- package/dist/mcp/prompts.js +27 -8
- package/dist/mcp/prompts.js.map +1 -1
- package/dist/mcp/tools/chats.d.ts.map +1 -1
- package/dist/mcp/tools/chats.js +19 -1
- package/dist/mcp/tools/chats.js.map +1 -1
- package/dist/mcp/tools/inbox.d.ts +2 -0
- package/dist/mcp/tools/inbox.d.ts.map +1 -1
- package/dist/mcp/tools/inbox.js +27 -4
- package/dist/mcp/tools/inbox.js.map +1 -1
- package/dist/mcp/tools/review.d.ts.map +1 -1
- package/dist/mcp/tools/review.js +23 -2
- package/dist/mcp/tools/review.js.map +1 -1
- package/dist/replies/decide.d.ts +34 -0
- package/dist/replies/decide.d.ts.map +1 -0
- package/dist/replies/decide.js +109 -0
- package/dist/replies/decide.js.map +1 -0
- package/dist/replies/rules.d.ts +127 -0
- package/dist/replies/rules.d.ts.map +1 -0
- package/dist/replies/rules.js +119 -0
- package/dist/replies/rules.js.map +1 -0
- package/dist/replies/state.d.ts +36 -0
- package/dist/replies/state.d.ts.map +1 -0
- package/dist/replies/state.js +67 -0
- package/dist/replies/state.js.map +1 -0
- package/dist/search/search.d.ts.map +1 -1
- package/dist/search/search.js +4 -3
- package/dist/search/search.js.map +1 -1
- package/dist/services/archive.d.ts.map +1 -1
- package/dist/services/archive.js +4 -2
- package/dist/services/archive.js.map +1 -1
- package/dist/services/chat-stats.d.ts +3 -0
- package/dist/services/chat-stats.d.ts.map +1 -1
- package/dist/services/chat-stats.js +3 -0
- package/dist/services/chat-stats.js.map +1 -1
- package/dist/services/chats.d.ts +10 -0
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.js +61 -0
- package/dist/services/chats.js.map +1 -1
- package/dist/services/members-audit.d.ts +44 -0
- package/dist/services/members-audit.d.ts.map +1 -0
- package/dist/services/members-audit.js +111 -0
- package/dist/services/members-audit.js.map +1 -0
- package/dist/services/messages-search.d.ts +4 -2
- package/dist/services/messages-search.d.ts.map +1 -1
- package/dist/services/messages-search.js +13 -5
- package/dist/services/messages-search.js.map +1 -1
- package/dist/services/messages.js +1 -1
- package/dist/services/messages.js.map +1 -1
- package/dist/store/sqlite/completeness.d.ts +10 -1
- package/dist/store/sqlite/completeness.d.ts.map +1 -1
- package/dist/store/sqlite/completeness.js +15 -3
- package/dist/store/sqlite/completeness.js.map +1 -1
- package/dist/store/store.d.ts +2 -1
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +9 -2
- package/dist/store/store.js.map +1 -1
- package/package.json +1 -1
- package/parity.json +16 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { DAYS } from "./rules.js";
|
|
2
|
+
import { answeredKey } from "./state.js";
|
|
3
|
+
const skip = (why) => ({ skip: why });
|
|
4
|
+
/**
|
|
5
|
+
* Whether `rule` answers this message at `now`, and with what — or why not, in words `replies test`
|
|
6
|
+
* can print. Pure: it reads `state` and changes nothing; the caller records a reply it sent.
|
|
7
|
+
*/
|
|
8
|
+
export const decide = (rule, incoming, state, now) => {
|
|
9
|
+
const { message, chat, owner, sender } = incoming;
|
|
10
|
+
if (state.paused)
|
|
11
|
+
return skip("replies are paused");
|
|
12
|
+
if (!rule.on)
|
|
13
|
+
return skip("the rule is off");
|
|
14
|
+
if (message.outgoing !== false)
|
|
15
|
+
return skip(message.outgoing ? "your own message" : "the account is not known");
|
|
16
|
+
if (message.senderIsChat || message.senderId === null)
|
|
17
|
+
return skip("sent as a chat, not by a person");
|
|
18
|
+
if (sender.isBot)
|
|
19
|
+
return skip("sent by a bot");
|
|
20
|
+
if (chat.kind !== "dialog" && chat.kind !== "group")
|
|
21
|
+
return skip(`a ${chat.kind} is never answered`);
|
|
22
|
+
if (message.editedAt !== null)
|
|
23
|
+
return skip("an edited message");
|
|
24
|
+
if (message.scheduledFor !== undefined)
|
|
25
|
+
return skip("a scheduled message");
|
|
26
|
+
if (Date.parse(message.timestamp) < incoming.since)
|
|
27
|
+
return skip("older than the catch-up start");
|
|
28
|
+
if (state.answered.includes(answeredKey(message)))
|
|
29
|
+
return skip("already answered");
|
|
30
|
+
const { where, when } = rule;
|
|
31
|
+
if (where.kinds.length > 0 && !where.kinds.includes(chat.kind))
|
|
32
|
+
return skip(`the rule does not answer a ${chat.kind}`);
|
|
33
|
+
if (where.chats.length > 0 && !where.chats.includes(chat.id))
|
|
34
|
+
return skip("not one of the rule's chats");
|
|
35
|
+
if (where.notChats.includes(chat.id))
|
|
36
|
+
return skip("one of the chats the rule leaves out");
|
|
37
|
+
const toMe = mentionsOwner(message, owner);
|
|
38
|
+
if (chat.kind === "group" && !where.chats.includes(chat.id) && !toMe) {
|
|
39
|
+
return skip("a group message that neither mentions you nor replies to you");
|
|
40
|
+
}
|
|
41
|
+
if (when.hours && !outside(when.hours, now))
|
|
42
|
+
return skip("inside the hours the rule leaves alone");
|
|
43
|
+
if (when.words.length > 0 && !when.words.some((word) => hasWord(message.text, word))) {
|
|
44
|
+
return skip("none of the rule's words");
|
|
45
|
+
}
|
|
46
|
+
if (when.question && !isQuestion(message.text))
|
|
47
|
+
return skip("not a question");
|
|
48
|
+
if (when.mentionsMe && !toMe)
|
|
49
|
+
return skip("does not mention you or reply to you");
|
|
50
|
+
const { from } = when;
|
|
51
|
+
if (from.people.length > 0 && !from.people.includes(message.senderId))
|
|
52
|
+
return skip("not from the rule's people");
|
|
53
|
+
if (from.notPeople.includes(message.senderId))
|
|
54
|
+
return skip("from a person the rule leaves out");
|
|
55
|
+
if (from.contactsOnly && !sender.isContact)
|
|
56
|
+
return skip("not from a contact");
|
|
57
|
+
const sent = state.sent[rule.id];
|
|
58
|
+
if (over(sent?.chats[chat.id], rule.limits.perChat, now))
|
|
59
|
+
return skip("the chat's limit is reached");
|
|
60
|
+
if (over(sent?.people[message.senderId], rule.limits.perPerson, now))
|
|
61
|
+
return skip("the person's limit is reached");
|
|
62
|
+
const text = filled(rule.reply.template, message.senderName);
|
|
63
|
+
if (text === undefined)
|
|
64
|
+
return skip("the template needs a name the sender has not given");
|
|
65
|
+
return { reply: { text, asReply: rule.reply.asReply, model: rule.reply.model } };
|
|
66
|
+
};
|
|
67
|
+
const mentionsOwner = (message, owner) => message.replyTo?.outgoing === true ||
|
|
68
|
+
(owner.id !== null && (message.mentions ?? []).includes(owner.id)) ||
|
|
69
|
+
(owner.username !== undefined && hasWord(message.text, `@${owner.username}`));
|
|
70
|
+
const local = (zone, now) => {
|
|
71
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
72
|
+
timeZone: zone,
|
|
73
|
+
weekday: "short",
|
|
74
|
+
hour: "2-digit",
|
|
75
|
+
minute: "2-digit",
|
|
76
|
+
hourCycle: "h23",
|
|
77
|
+
}).formatToParts(now);
|
|
78
|
+
const part = (type) => parts.find((one) => one.type === type)?.value ?? "";
|
|
79
|
+
return {
|
|
80
|
+
day: part("weekday").toLowerCase(),
|
|
81
|
+
minute: Number(part("hour")) * 60 + Number(part("minute")),
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Outside the working time: not on one of `days`, or on one but not inside the window. A window that
|
|
86
|
+
* crosses midnight belongs to the day it starts on, so Friday 22:00–02:00 covers Saturday 01:00.
|
|
87
|
+
*/
|
|
88
|
+
const outside = ({ outside: window, days, timezone }, now) => {
|
|
89
|
+
const { day, minute } = local(timezone, now);
|
|
90
|
+
const crosses = window.to < window.from;
|
|
91
|
+
const working = crosses
|
|
92
|
+
? (days.includes(day) && minute >= window.from) || (days.includes(dayBefore(day)) && minute < window.to)
|
|
93
|
+
: days.includes(day) && minute >= window.from && minute < window.to;
|
|
94
|
+
return !working;
|
|
95
|
+
};
|
|
96
|
+
const dayBefore = (day) => DAYS[(DAYS.indexOf(day) + 6) % 7];
|
|
97
|
+
const escaped = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
98
|
+
/** Whole words, any case, any script: `price` is not found in `prices`, `цена` is found in `Цена?`. */
|
|
99
|
+
const hasWord = (text, word) => new RegExp(`(?<![\\p{L}\\p{N}_])${escaped(word.trim())}(?![\\p{L}\\p{N}_])`, "iu").test(text);
|
|
100
|
+
/** A shared link's query string is not a question. */
|
|
101
|
+
const isQuestion = (text) => text.replace(/https?:\/\/\S+/g, "").includes("?");
|
|
102
|
+
const over = (sent, { count, ms }, now) => (sent ?? []).filter((at) => now - Date.parse(at) < ms).length >= count;
|
|
103
|
+
const filled = (template, senderName) => {
|
|
104
|
+
const name = senderName?.trim() ?? "";
|
|
105
|
+
if (/\{(firstName|name)\}/.test(template) && name === "")
|
|
106
|
+
return undefined;
|
|
107
|
+
return template.replaceAll("{firstName}", name.split(/\s+/)[0] ?? name).replaceAll("{name}", name);
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=decide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decide.js","sourceRoot":"","sources":["../../src/replies/decide.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAqD,MAAM,YAAY,CAAA;AACpF,OAAO,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAA;AAiB3D,MAAM,IAAI,GAAG,CAAC,GAAW,EAAY,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;AAEvD;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAe,EAAE,QAAkB,EAAE,KAAmB,EAAE,GAAW,EAAY,EAAE;IACxG,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IACjD,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC,oBAAoB,CAAC,CAAA;IACnD,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAA;IAC/G,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,iCAAiC,CAAC,CAAA;IACrG,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,eAAe,CAAC,CAAA;IAC9C,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,oBAAoB,CAAC,CAAA;IACpG,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,mBAAmB,CAAC,CAAA;IAC/D,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,qBAAqB,CAAC,CAAA;IAC1E,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,+BAA+B,CAAC,CAAA;IAChG,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAElF,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;IAC5B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,8BAA8B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACtH,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC,6BAA6B,CAAC,CAAA;IACxG,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC,sCAAsC,CAAC,CAAA;IACzF,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACrE,OAAO,IAAI,CAAC,8DAA8D,CAAC,CAAA;IAC7E,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,wCAAwC,CAAC,CAAA;IAClG,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;QACrF,OAAO,IAAI,CAAC,0BAA0B,CAAC,CAAA;IACzC,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,gBAAgB,CAAC,CAAA;IAC7E,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,sCAAsC,CAAC,CAAA;IACjF,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;IACrB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC,4BAA4B,CAAC,CAAA;IAChH,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC,mCAAmC,CAAC,CAAA;IAC/F,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC,oBAAoB,CAAC,CAAA;IAE7E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,6BAA6B,CAAC,CAAA;IACpG,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,+BAA+B,CAAC,CAAA;IAElH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;IAC5D,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,oDAAoD,CAAC,CAAA;IACzF,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAA;AAClF,CAAC,CAAA;AAED,MAAM,aAAa,GAAG,CAAC,OAAgB,EAAE,KAAwB,EAAW,EAAE,CAC5E,OAAO,CAAC,OAAO,EAAE,QAAQ,KAAK,IAAI;IAClC,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClE,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;AAE/E,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,GAAW,EAAgC,EAAE;IACxE,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC7C,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IACrB,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAA;IAClF,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAS;QACzC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;KAC3D,CAAA;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,OAAO,GAAG,CACd,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAsD,EACvF,GAAW,EACX,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAA;IACvC,MAAM,OAAO,GAAG,OAAO;QACrB,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;QACxG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;IACrE,OAAO,CAAC,OAAO,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,GAAQ,EAAO,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAQ,CAAA;AAE7E,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AAE7E,uGAAuG;AACvG,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,IAAY,EAAW,EAAE,CACtD,IAAI,MAAM,CAAC,uBAAuB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAE/F,sDAAsD;AACtD,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;AAE/F,MAAM,IAAI,GAAG,CAAC,IAA0B,EAAE,EAAE,KAAK,EAAE,EAAE,EAAS,EAAE,GAAW,EAAW,EAAE,CACtF,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,IAAI,KAAK,CAAA;AAExE,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,UAAyB,EAAsB,EAAE;IACjF,MAAM,IAAI,GAAG,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACrC,IAAI,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAA;IAC1E,OAAO,QAAQ,CAAC,UAAU,CAAC,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;AACpG,CAAC,CAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import type { AppIdentity } from "../cli/app.js";
|
|
3
|
+
export declare const REPLY_ACTIONS: readonly ["reply", "task"];
|
|
4
|
+
export declare const REPLY_MODELS: readonly ["fill-only", "may-reword"];
|
|
5
|
+
/** Channels, saved messages and chats of unknown kind are never answered, so a rule cannot name them. */
|
|
6
|
+
export declare const REPLY_KINDS: readonly ["dialog", "group"];
|
|
7
|
+
export declare const PLACEHOLDERS: readonly ["firstName", "name"];
|
|
8
|
+
export declare const DAYS: readonly ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
|
|
9
|
+
export type Day = (typeof DAYS)[number];
|
|
10
|
+
/** Minutes after midnight, `[from, to)`; `to` below `from` crosses midnight. */
|
|
11
|
+
export interface Window {
|
|
12
|
+
from: number;
|
|
13
|
+
to: number;
|
|
14
|
+
}
|
|
15
|
+
/** At most `count` sends inside any `ms`. */
|
|
16
|
+
export interface Limit {
|
|
17
|
+
count: number;
|
|
18
|
+
ms: number;
|
|
19
|
+
}
|
|
20
|
+
declare const rule: v.SchemaWithPipe<readonly [v.StrictObjectSchema<{
|
|
21
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a rule id is lower-case letters, digits and -">]>;
|
|
22
|
+
readonly on: v.BooleanSchema<undefined>;
|
|
23
|
+
readonly do: v.SchemaWithPipe<readonly [v.ArraySchema<v.PicklistSchema<readonly ["reply", "task"], undefined>, undefined>, v.MinLengthAction<("reply" | "task")[], 1, "a rule has to do something: reply">]>;
|
|
24
|
+
readonly where: v.StrictObjectSchema<{
|
|
25
|
+
readonly kinds: v.ArraySchema<v.PicklistSchema<readonly ["dialog", "group"], undefined>, undefined>;
|
|
26
|
+
readonly chats: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
27
|
+
readonly notChats: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
28
|
+
}, undefined>;
|
|
29
|
+
readonly when: v.StrictObjectSchema<{
|
|
30
|
+
readonly hours: v.NullableSchema<v.StrictObjectSchema<{
|
|
31
|
+
readonly outside: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a window is written \"09:00-19:00\", 24-hour">, v.TransformAction<string, Window>, v.CheckAction<Window, "a window has to start and end at different times">]>;
|
|
32
|
+
readonly days: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<string, ("fri" | "mon" | "sat" | "sun" | "thu" | "tue" | "wed")[] | undefined>, v.CheckAction<("fri" | "mon" | "sat" | "sun" | "thu" | "tue" | "wed")[] | undefined, `days are written "mon-fri" or "sat,sun", from ${string}`>, v.TransformAction<("fri" | "mon" | "sat" | "sun" | "thu" | "tue" | "wed")[] | undefined, ("fri" | "mon" | "sat" | "sun" | "thu" | "tue" | "wed")[]>]>;
|
|
33
|
+
readonly timezone: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "a time zone is written as \"Europe/Madrid\"">]>;
|
|
34
|
+
}, undefined>, undefined>;
|
|
35
|
+
readonly words: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
36
|
+
readonly question: v.BooleanSchema<undefined>;
|
|
37
|
+
readonly mentionsMe: v.BooleanSchema<undefined>;
|
|
38
|
+
readonly from: v.StrictObjectSchema<{
|
|
39
|
+
readonly people: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
40
|
+
readonly notPeople: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
41
|
+
readonly contactsOnly: v.BooleanSchema<undefined>;
|
|
42
|
+
}, undefined>;
|
|
43
|
+
}, undefined>;
|
|
44
|
+
readonly reply: v.StrictObjectSchema<{
|
|
45
|
+
readonly template: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "a reply template cannot be empty">, v.CheckAction<string, `a template fills only ${string}`>]>;
|
|
46
|
+
readonly model: v.PicklistSchema<readonly ["fill-only", "may-reword"], undefined>;
|
|
47
|
+
readonly asReply: v.BooleanSchema<undefined>;
|
|
48
|
+
}, undefined>;
|
|
49
|
+
readonly limits: v.StrictObjectSchema<{
|
|
50
|
+
readonly perChat: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a limit is written \"1/12h\": this many replies in this long — m, h or d">, v.TransformAction<string, Limit>]>;
|
|
51
|
+
readonly perPerson: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a limit is written \"1/12h\": this many replies in this long — m, h or d">, v.TransformAction<string, Limit>]>;
|
|
52
|
+
}, undefined>;
|
|
53
|
+
}, undefined>, v.CheckAction<{
|
|
54
|
+
id: string;
|
|
55
|
+
on: boolean;
|
|
56
|
+
do: ("reply" | "task")[];
|
|
57
|
+
where: {
|
|
58
|
+
kinds: ("dialog" | "group")[];
|
|
59
|
+
chats: string[];
|
|
60
|
+
notChats: string[];
|
|
61
|
+
};
|
|
62
|
+
when: {
|
|
63
|
+
hours: {
|
|
64
|
+
outside: Window;
|
|
65
|
+
days: ("fri" | "mon" | "sat" | "sun" | "thu" | "tue" | "wed")[];
|
|
66
|
+
timezone: string;
|
|
67
|
+
} | null;
|
|
68
|
+
words: string[];
|
|
69
|
+
question: boolean;
|
|
70
|
+
mentionsMe: boolean;
|
|
71
|
+
from: {
|
|
72
|
+
people: string[];
|
|
73
|
+
notPeople: string[];
|
|
74
|
+
contactsOnly: boolean;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
reply: {
|
|
78
|
+
template: string;
|
|
79
|
+
model: "fill-only" | "may-reword";
|
|
80
|
+
asReply: boolean;
|
|
81
|
+
};
|
|
82
|
+
limits: {
|
|
83
|
+
perChat: Limit;
|
|
84
|
+
perPerson: Limit;
|
|
85
|
+
};
|
|
86
|
+
}, "\"task\" waits for the tasks package; only \"reply\" works now">]>;
|
|
87
|
+
export type ReplyRule = v.InferOutput<typeof rule>;
|
|
88
|
+
/**
|
|
89
|
+
* Every key written out, so the file shows all there is to set, as moderation's does (max-cli
|
|
90
|
+
* `NEED-314`). Off until the owner turns it on, and the limits are the tightest worth having.
|
|
91
|
+
*/
|
|
92
|
+
export declare const defaultRule: (id: string) => {
|
|
93
|
+
id: string;
|
|
94
|
+
on: boolean;
|
|
95
|
+
do: string[];
|
|
96
|
+
where: {
|
|
97
|
+
kinds: string[];
|
|
98
|
+
chats: never[];
|
|
99
|
+
notChats: never[];
|
|
100
|
+
};
|
|
101
|
+
when: {
|
|
102
|
+
hours: null;
|
|
103
|
+
words: never[];
|
|
104
|
+
question: boolean;
|
|
105
|
+
mentionsMe: boolean;
|
|
106
|
+
from: {
|
|
107
|
+
people: never[];
|
|
108
|
+
notPeople: never[];
|
|
109
|
+
contactsOnly: boolean;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
reply: {
|
|
113
|
+
template: string;
|
|
114
|
+
model: string;
|
|
115
|
+
asReply: boolean;
|
|
116
|
+
};
|
|
117
|
+
limits: {
|
|
118
|
+
perChat: string;
|
|
119
|
+
perPerson: string;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
export declare const repliesPathFor: (app: AppIdentity, profile: string, env?: NodeJS.ProcessEnv) => string;
|
|
123
|
+
/** The owner's rules, in file order. No file is no rules; a file that does not check out refuses, naming the field. */
|
|
124
|
+
export declare const readReplyRules: (path: string) => ReplyRule[];
|
|
125
|
+
export declare const parseReplyRules: (parsed: unknown, path: string) => ReplyRule[];
|
|
126
|
+
export {};
|
|
127
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/replies/rules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD,eAAO,MAAM,aAAa,YAAI,OAAO,EAAE,MAAM,CAAU,CAAA;AACvD,eAAO,MAAM,YAAY,YAAI,WAAW,EAAE,YAAY,CAAU,CAAA;AAChE,yGAAyG;AACzG,eAAO,MAAM,WAAW,YAAI,QAAQ,EAAE,OAAO,CAAU,CAAA;AACvD,eAAO,MAAM,YAAY,YAAI,WAAW,EAAE,MAAM,CAAU,CAAA;AAC1D,eAAO,MAAM,IAAI,YAAI,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAA;AAE9E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAA;AAMvC,gFAAgF;AAChF,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;CACX;AAED,6CAA6C;AAC7C,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,EAAE,EAAE,MAAM,CAAA;CACX;AAoED,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sEAkBT,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,IAAI,CAAC,CAAA;AAUlD;;;GAGG;AACH,eAAO,MAAM,WAAW,OAAQ,MAAM;;;;;QAI3B,KAAK;QAAc,KAAK;QAAM,QAAQ;;;QAE7C,KAAK;QACL,KAAK;QACL,QAAQ;QACR,UAAU;QACV,IAAI;YAAI,MAAM;YAAM,SAAS;YAAM,YAAY;;;;QAExC,QAAQ;QAAM,KAAK;QAAe,OAAO;;;QACxC,OAAO;QAAU,SAAS;;CACpC,CAAA;AAEF,eAAO,MAAM,cAAc,QAAS,WAAW,WAAW,MAAM,QAAO,MAAM,CAAC,UAAU,KAAiB,MACG,CAAA;AAE5G,uHAAuH;AACvH,eAAO,MAAM,cAAc,SAAU,MAAM,KAAG,SAAS,EAStD,CAAA;AAED,eAAO,MAAM,eAAe,WAAY,OAAO,QAAQ,MAAM,KAAG,SAAS,EAIxE,CAAA"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CliError, resolvePaths } from "@leemour/cli-core";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
export const REPLY_ACTIONS = ["reply", "task"];
|
|
6
|
+
export const REPLY_MODELS = ["fill-only", "may-reword"];
|
|
7
|
+
/** Channels, saved messages and chats of unknown kind are never answered, so a rule cannot name them. */
|
|
8
|
+
export const REPLY_KINDS = ["dialog", "group"];
|
|
9
|
+
export const PLACEHOLDERS = ["firstName", "name"];
|
|
10
|
+
export const DAYS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
|
|
11
|
+
const WINDOW = /^([01]\d|2[0-3]):([0-5]\d)-([01]\d|2[0-3]):([0-5]\d)$/;
|
|
12
|
+
const LIMIT = /^([1-9]\d*)\/([1-9]\d*)(m|h|d)$/;
|
|
13
|
+
const UNIT_MS = { m: 60_000, h: 3_600_000, d: 86_400_000 };
|
|
14
|
+
const minutes = (hours, mins) => Number(hours) * 60 + Number(mins);
|
|
15
|
+
const window = v.pipe(v.string(), v.regex(WINDOW, 'a window is written "09:00-19:00", 24-hour'), v.transform((typed) => {
|
|
16
|
+
const [, h1, m1, h2, m2] = WINDOW.exec(typed);
|
|
17
|
+
return { from: minutes(h1, m1), to: minutes(h2, m2) };
|
|
18
|
+
}), v.check((one) => one.from !== one.to, "a window has to start and end at different times"));
|
|
19
|
+
const dayOf = (typed) => DAYS.indexOf(typed);
|
|
20
|
+
/** `mon-fri`, `sat,sun`, `fri-mon` across the week's end. */
|
|
21
|
+
const days = v.pipe(v.string(), v.transform((typed) => {
|
|
22
|
+
const found = new Set();
|
|
23
|
+
for (const part of typed.split(",").map((one) => one.trim().toLowerCase())) {
|
|
24
|
+
const [first = "", last = first] = part.split("-");
|
|
25
|
+
const from = dayOf(first);
|
|
26
|
+
const to = dayOf(last);
|
|
27
|
+
if (from < 0 || to < 0)
|
|
28
|
+
return undefined;
|
|
29
|
+
for (let at = from;; at = (at + 1) % 7) {
|
|
30
|
+
found.add(DAYS[at]);
|
|
31
|
+
if (at === to)
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return DAYS.filter((day) => found.has(day));
|
|
36
|
+
}), v.check((one) => one !== undefined, `days are written "mon-fri" or "sat,sun", from ${DAYS.join(", ")}`), v.transform((one) => one));
|
|
37
|
+
const knownZone = (zone) => {
|
|
38
|
+
try {
|
|
39
|
+
new Intl.DateTimeFormat("en-US", { timeZone: zone });
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const timezone = v.pipe(v.string(), v.check(knownZone, 'a time zone is written as "Europe/Madrid"'));
|
|
47
|
+
const limit = v.pipe(v.string(), v.regex(LIMIT, 'a limit is written "1/12h": this many replies in this long — m, h or d'), v.transform((typed) => {
|
|
48
|
+
const [, count, amount, unit] = LIMIT.exec(typed);
|
|
49
|
+
return { count: Number(count), ms: Number(amount) * (UNIT_MS[unit ?? ""] ?? 0) };
|
|
50
|
+
}));
|
|
51
|
+
const ids = v.array(v.pipe(v.string(), v.minLength(1)));
|
|
52
|
+
const template = v.pipe(v.string(), v.minLength(1, "a reply template cannot be empty"), v.check((text) => [...text.matchAll(/\{(\w*)\}/g)].every(([, name]) => PLACEHOLDERS.includes(name)), `a template fills only ${PLACEHOLDERS.map((name) => `{${name}}`).join(", ")}`));
|
|
53
|
+
const rule = v.pipe(v.strictObject({
|
|
54
|
+
id: v.pipe(v.string(), v.regex(/^[a-z0-9][a-z0-9-]*$/, "a rule id is lower-case letters, digits and -")),
|
|
55
|
+
on: v.boolean(),
|
|
56
|
+
do: v.pipe(v.array(v.picklist(REPLY_ACTIONS)), v.minLength(1, "a rule has to do something: reply")),
|
|
57
|
+
where: v.strictObject({ kinds: v.array(v.picklist(REPLY_KINDS)), chats: ids, notChats: ids }),
|
|
58
|
+
when: v.strictObject({
|
|
59
|
+
hours: v.nullable(v.strictObject({ outside: window, days, timezone })),
|
|
60
|
+
words: v.array(v.pipe(v.string(), v.trim(), v.minLength(1))),
|
|
61
|
+
question: v.boolean(),
|
|
62
|
+
mentionsMe: v.boolean(),
|
|
63
|
+
from: v.strictObject({ people: ids, notPeople: ids, contactsOnly: v.boolean() }),
|
|
64
|
+
}),
|
|
65
|
+
reply: v.strictObject({ template, model: v.picklist(REPLY_MODELS), asReply: v.boolean() }),
|
|
66
|
+
limits: v.strictObject({ perChat: limit, perPerson: limit }),
|
|
67
|
+
}),
|
|
68
|
+
// NEED-582: a rule may open a task, but there is no tasks package to open it in yet.
|
|
69
|
+
v.check((one) => !one.do.includes("task"), '"task" waits for the tasks package; only "reply" works now'));
|
|
70
|
+
const file = v.pipe(v.strictObject({ rules: v.array(rule) }), v.check(({ rules }) => new Set(rules.map((one) => one.id)).size === rules.length, "two rules share an id; each needs its own"));
|
|
71
|
+
/**
|
|
72
|
+
* Every key written out, so the file shows all there is to set, as moderation's does (max-cli
|
|
73
|
+
* `NEED-314`). Off until the owner turns it on, and the limits are the tightest worth having.
|
|
74
|
+
*/
|
|
75
|
+
export const defaultRule = (id) => ({
|
|
76
|
+
id,
|
|
77
|
+
on: false,
|
|
78
|
+
do: ["reply"],
|
|
79
|
+
where: { kinds: ["dialog"], chats: [], notChats: [] },
|
|
80
|
+
when: {
|
|
81
|
+
hours: null,
|
|
82
|
+
words: [],
|
|
83
|
+
question: false,
|
|
84
|
+
mentionsMe: false,
|
|
85
|
+
from: { people: [], notPeople: [], contactsOnly: false },
|
|
86
|
+
},
|
|
87
|
+
reply: { template: "", model: "fill-only", asReply: true },
|
|
88
|
+
limits: { perChat: "1/1d", perPerson: "1/1d" },
|
|
89
|
+
});
|
|
90
|
+
export const repliesPathFor = (app, profile, env = process.env) => join(resolvePaths({ appName: app.appName, prefix: app.envPrefix, env }).config, `${profile}.replies.json`);
|
|
91
|
+
/** The owner's rules, in file order. No file is no rules; a file that does not check out refuses, naming the field. */
|
|
92
|
+
export const readReplyRules = (path) => {
|
|
93
|
+
if (!existsSync(path))
|
|
94
|
+
return [];
|
|
95
|
+
let parsed;
|
|
96
|
+
try {
|
|
97
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw broken(path, error instanceof Error ? error.message : String(error));
|
|
101
|
+
}
|
|
102
|
+
return parseReplyRules(parsed, path);
|
|
103
|
+
};
|
|
104
|
+
export const parseReplyRules = (parsed, path) => {
|
|
105
|
+
const checked = v.safeParse(file, parsed);
|
|
106
|
+
if (!checked.success)
|
|
107
|
+
throw broken(path, checked.issues.map(problem).join("; "));
|
|
108
|
+
return checked.output.rules;
|
|
109
|
+
};
|
|
110
|
+
const problem = (issue) => {
|
|
111
|
+
const at = v.getDotPath(issue) ?? "the file";
|
|
112
|
+
if (issue.kind === "schema" && issue.expected === "never")
|
|
113
|
+
return `${at} is not a field a rule has`;
|
|
114
|
+
if (issue.expected === "Object" && issue.received === "undefined")
|
|
115
|
+
return `${at} is missing`;
|
|
116
|
+
return `${at}: ${issue.message}`;
|
|
117
|
+
};
|
|
118
|
+
const broken = (path, why) => new CliError("configuration_error", `the reply rules ${path} cannot be read (${why}) — fix the file`);
|
|
119
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/replies/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import type { AppIdentity } from "../cli/app.js";
|
|
3
|
+
import type { Message } from "../domain/models.js";
|
|
4
|
+
import type { ReplyRule } from "./rules.js";
|
|
5
|
+
/** Enough to cover any restart's catch-up; older ids are past the catch-up start and never answered anyway. */
|
|
6
|
+
export declare const ANSWERED_KEPT = 1000;
|
|
7
|
+
declare const stateFile: v.ObjectSchema<{
|
|
8
|
+
readonly paused: v.BooleanSchema<undefined>;
|
|
9
|
+
/** `<chat>:<message>`, oldest first. */
|
|
10
|
+
readonly answered: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
11
|
+
/** Per rule, when it replied, by chat and by person: what its limits count. */
|
|
12
|
+
readonly sent: v.RecordSchema<v.StringSchema<undefined>, v.ObjectSchema<{
|
|
13
|
+
readonly chats: v.RecordSchema<v.StringSchema<undefined>, v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
14
|
+
readonly people: v.RecordSchema<v.StringSchema<undefined>, v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
15
|
+
}, undefined>, undefined>;
|
|
16
|
+
}, undefined>;
|
|
17
|
+
export type RepliesState = v.InferOutput<typeof stateFile>;
|
|
18
|
+
export declare const emptyState: () => RepliesState;
|
|
19
|
+
export declare const answeredKey: (message: Pick<Message, "chatId" | "id">) => string;
|
|
20
|
+
/**
|
|
21
|
+
* What the rules did, apart from the rules: editing the rules file never forgets what was already
|
|
22
|
+
* answered. Read on every message, so `pause` stops a running `serve` without a restart.
|
|
23
|
+
*/
|
|
24
|
+
export declare const repliesStatePathFor: (app: AppIdentity, profile: string, env?: NodeJS.ProcessEnv) => string;
|
|
25
|
+
/** A file that does not check out refuses: guessing would forget what was answered, and answer it twice. */
|
|
26
|
+
export declare const readRepliesState: (path: string) => RepliesState;
|
|
27
|
+
export declare const writeRepliesState: (path: string, state: RepliesState) => void;
|
|
28
|
+
export declare const paused: (state: RepliesState, on: boolean) => RepliesState;
|
|
29
|
+
/**
|
|
30
|
+
* The state after `rule` replied to `message` at `now`: the message answered, the reply counted for
|
|
31
|
+
* its chat and its sender. Counts older than the rule's longest limit are dropped, since no limit
|
|
32
|
+
* reads them.
|
|
33
|
+
*/
|
|
34
|
+
export declare const recordReply: (state: RepliesState, rule: Pick<ReplyRule, "id" | "limits">, message: Pick<Message, "chatId" | "id" | "senderId">, now: number) => RepliesState;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/replies/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAM,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,+GAA+G;AAC/G,eAAO,MAAM,aAAa,OAAO,CAAA;AAIjC,QAAA,MAAM,SAAS;;IAEb,wCAAwC;;IAExC,+EAA+E;;;;;aAE/E,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,SAAS,CAAC,CAAA;AAE1D,eAAO,MAAM,UAAU,QAAO,YAA2D,CAAA;AAEzF,eAAO,MAAM,WAAW,YAAa,IAAI,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC,KAAG,MAA2C,CAAA;AAEjH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAAS,WAAW,WAAW,MAAM,QAAO,MAAM,CAAC,UAAU,KAAiB,MACG,CAAA;AAEjH,4GAA4G;AAC5G,eAAO,MAAM,gBAAgB,SAAU,MAAM,KAAG,YAa/C,CAAA;AAED,eAAO,MAAM,iBAAiB,SAAU,MAAM,SAAS,YAAY,KAAG,IACZ,CAAA;AAE1D,eAAO,MAAM,MAAM,UAAW,YAAY,MAAM,OAAO,KAAG,YAA0C,CAAA;AAEpG;;;;GAIG;AACH,eAAO,MAAM,WAAW,UACf,YAAY,QACb,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,QAAQ,CAAC,WAC7B,IAAI,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,CAAC,OAC/C,MAAM,KACV,YAsBF,CAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CliError, resolvePaths, writeSecurely } from "@leemour/cli-core";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
/** Enough to cover any restart's catch-up; older ids are past the catch-up start and never answered anyway. */
|
|
6
|
+
export const ANSWERED_KEPT = 1000;
|
|
7
|
+
const times = v.record(v.string(), v.array(v.string()));
|
|
8
|
+
const stateFile = v.object({
|
|
9
|
+
paused: v.boolean(),
|
|
10
|
+
/** `<chat>:<message>`, oldest first. */
|
|
11
|
+
answered: v.array(v.string()),
|
|
12
|
+
/** Per rule, when it replied, by chat and by person: what its limits count. */
|
|
13
|
+
sent: v.record(v.string(), v.object({ chats: times, people: times })),
|
|
14
|
+
});
|
|
15
|
+
export const emptyState = () => ({ paused: false, answered: [], sent: {} });
|
|
16
|
+
export const answeredKey = (message) => `${message.chatId}:${message.id}`;
|
|
17
|
+
/**
|
|
18
|
+
* What the rules did, apart from the rules: editing the rules file never forgets what was already
|
|
19
|
+
* answered. Read on every message, so `pause` stops a running `serve` without a restart.
|
|
20
|
+
*/
|
|
21
|
+
export const repliesStatePathFor = (app, profile, env = process.env) => join(resolvePaths({ appName: app.appName, prefix: app.envPrefix, env }).state, `${profile}.replies-state.json`);
|
|
22
|
+
/** A file that does not check out refuses: guessing would forget what was answered, and answer it twice. */
|
|
23
|
+
export const readRepliesState = (path) => {
|
|
24
|
+
if (!existsSync(path))
|
|
25
|
+
return emptyState();
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw broken(path, error instanceof Error ? error.message : String(error));
|
|
32
|
+
}
|
|
33
|
+
const checked = v.safeParse(stateFile, parsed);
|
|
34
|
+
if (!checked.success) {
|
|
35
|
+
throw broken(path, checked.issues.map((issue) => `${v.getDotPath(issue) ?? "file"}: ${issue.message}`).join("; "));
|
|
36
|
+
}
|
|
37
|
+
return checked.output;
|
|
38
|
+
};
|
|
39
|
+
export const writeRepliesState = (path, state) => writeSecurely(path, `${JSON.stringify(state)}\n`, 0o600);
|
|
40
|
+
export const paused = (state, on) => ({ ...state, paused: on });
|
|
41
|
+
/**
|
|
42
|
+
* The state after `rule` replied to `message` at `now`: the message answered, the reply counted for
|
|
43
|
+
* its chat and its sender. Counts older than the rule's longest limit are dropped, since no limit
|
|
44
|
+
* reads them.
|
|
45
|
+
*/
|
|
46
|
+
export const recordReply = (state, rule, message, now) => {
|
|
47
|
+
const oldest = now - Math.max(rule.limits.perChat.ms, rule.limits.perPerson.ms);
|
|
48
|
+
const kept = (all, key) => {
|
|
49
|
+
const recent = Object.fromEntries(Object.entries(all)
|
|
50
|
+
.map(([id, at]) => [id, at.filter((one) => Date.parse(one) > oldest)])
|
|
51
|
+
.filter(([, at]) => at.length > 0));
|
|
52
|
+
if (key === null)
|
|
53
|
+
return recent;
|
|
54
|
+
return { ...recent, [key]: [...(recent[key] ?? []), new Date(now).toISOString()] };
|
|
55
|
+
};
|
|
56
|
+
const before = state.sent[rule.id] ?? { chats: {}, people: {} };
|
|
57
|
+
return {
|
|
58
|
+
...state,
|
|
59
|
+
answered: [...state.answered.filter((one) => one !== answeredKey(message)), answeredKey(message)].slice(-ANSWERED_KEPT),
|
|
60
|
+
sent: {
|
|
61
|
+
...state.sent,
|
|
62
|
+
[rule.id]: { chats: kept(before.chats, message.chatId), people: kept(before.people, message.senderId) },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
const broken = (path, why) => new CliError("configuration_error", `the reply state ${path} cannot be read (${why}) — fix or move the file`);
|
|
67
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/replies/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAIxF,iFAAiF;AACjF,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAA;AAE9F,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAA;AAEpD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;IAC7C,sGAAsG;IACtG,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,CAC5B,YAAY,EACZ,kBAAkB,GAAG,YAAY,GAAG,gBAAgB,GAAG,cAAc,GAAG,YAAY,GAAG,gBAAgB,CACxG,CAAA;AAkCD;;;;GAIG;AACH,eAAO,MAAM,MAAM,UACV,WAAW,SACX,SAAS,SACT,WAAW,qBACS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,KAC7D,OAAO,CAAC,YAAY,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAIxF,iFAAiF;AACjF,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAA;AAE9F,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAA;AAEpD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;IAC7C,sGAAsG;IACtG,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,CAC5B,YAAY,EACZ,kBAAkB,GAAG,YAAY,GAAG,gBAAgB,GAAG,cAAc,GAAG,YAAY,GAAG,gBAAgB,CACxG,CAAA;AAkCD;;;;GAIG;AACH,eAAO,MAAM,MAAM,UACV,WAAW,SACX,SAAS,SACT,WAAW,qBACS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,KAC7D,OAAO,CAAC,YAAY,CAwCtB,CAAA"}
|
package/dist/search/search.js
CHANGED
|
@@ -25,9 +25,10 @@ const corrected = (query, corrections) => ({
|
|
|
25
25
|
* runs only when the one before found nothing. Until the word index is built, substring alone.
|
|
26
26
|
*/
|
|
27
27
|
export const search = async (store, query, scope, { limit, newest = false }) => {
|
|
28
|
+
const wordsReady = (await store.searchIndexState())?.ready === true;
|
|
28
29
|
const answer = (found, rest = {}) => ({
|
|
29
30
|
corrections: [],
|
|
30
|
-
wordsReady
|
|
31
|
+
wordsReady,
|
|
31
32
|
...found,
|
|
32
33
|
...rest,
|
|
33
34
|
});
|
|
@@ -35,9 +36,9 @@ export const search = async (store, query, scope, { limit, newest = false }) =>
|
|
|
35
36
|
const page = await store.matchFilters(scope, { limit });
|
|
36
37
|
return answer({ items: tagged(page, "filters"), hasMore: page.hasMore });
|
|
37
38
|
}
|
|
38
|
-
if (!
|
|
39
|
+
if (!wordsReady) {
|
|
39
40
|
const page = await store.matchSubstring(query, scope, { limit });
|
|
40
|
-
return answer({ items: tagged(page, "substring"), hasMore: page.hasMore }
|
|
41
|
+
return answer({ items: tagged(page, "substring"), hasMore: page.hasMore });
|
|
41
42
|
}
|
|
42
43
|
const options = { limit, newest };
|
|
43
44
|
const found = await everyWord(store, query, scope, options, { whole: "words", beginnings: "beginnings" });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/services/archive.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAE3D,OAAO,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/services/archive.ts"],"names":[],"mappings":"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"}
|
package/dist/services/archive.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
2
|
import { CliError } from "@leemour/cli-core";
|
|
3
3
|
import { capability } from "../cli/messenger/port.js";
|
|
4
|
-
import { historyStartKey } from "../store/store.js";
|
|
4
|
+
import { fetchedKey, historyStartKey, } from "../store/store.js";
|
|
5
5
|
import { estimateBackfill } from "./backfill-estimate.js";
|
|
6
6
|
import { storedChatId } from "./messages.js";
|
|
7
7
|
import { patiently } from "./patience.js";
|
|
@@ -15,7 +15,7 @@ const pushed = (deps, what) => {
|
|
|
15
15
|
/** The most messages a provider hands out per history request — Telegram's cap. */
|
|
16
16
|
export const PAGE = 100;
|
|
17
17
|
/** How `store fetch` reads a messenger's history, where it says nothing of its own. */
|
|
18
|
-
export const FETCHING = { page: PAGE, pause: "1s", maxPages: 10, orderBy: "id" };
|
|
18
|
+
export const FETCHING = { page: PAGE, maxPageSize: PAGE, pause: "1s", maxPages: 10, orderBy: "id" };
|
|
19
19
|
/**
|
|
20
20
|
* What a held stretch is keyed by, for `store fetch` and `download --all` alike: the message id, or its
|
|
21
21
|
* send time in milliseconds. Not a safe integer means the messenger's ids do not order a chat.
|
|
@@ -144,6 +144,8 @@ export const fetchInto = async ({ history, store, account, fetching, limit, page
|
|
|
144
144
|
fetched += fresh;
|
|
145
145
|
// This run's pages are contiguous, so everything from `low` to its first message is held.
|
|
146
146
|
const held = await store.markRange(account, chatId, low, top);
|
|
147
|
+
if (before === undefined)
|
|
148
|
+
await store.setSyncState(account, fetchedKey(chatId), String(top));
|
|
147
149
|
onPage({ fetched, chatId, oldest: held.from });
|
|
148
150
|
// Nothing new: by id the messenger ignored `before`; by time a second such page did after the step past.
|
|
149
151
|
// Repeats do not count towards the limit, so without this the run would never end.
|