@adriangalilea/utils 0.12.0 → 0.13.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/README.md +33 -6
- package/dist/bot/access-control.d.ts +1 -1
- package/dist/bot/access-control.js +1 -1
- package/dist/bot/index.d.ts +2 -3
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +2 -3
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/llm.d.ts +426 -0
- package/dist/bot/llm.d.ts.map +1 -0
- package/dist/bot/{llm-stream.js → llm.js} +134 -20
- package/dist/bot/llm.js.map +1 -0
- package/dist/bot/menu.d.ts +8 -5
- package/dist/bot/menu.d.ts.map +1 -1
- package/dist/bot/menu.js +9 -6
- package/dist/bot/menu.js.map +1 -1
- package/package.json +4 -8
- package/dist/bot/llm-stream.d.ts +0 -142
- package/dist/bot/llm-stream.d.ts.map +0 -1
- package/dist/bot/llm-stream.js.map +0 -1
- package/dist/bot/message-history.d.ts +0 -279
- package/dist/bot/message-history.d.ts.map +0 -1
- package/dist/bot/message-history.js +0 -142
- package/dist/bot/message-history.js.map +0 -1
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-user rolling message history for GramIO bots — opt-in, with
|
|
3
|
-
* retention, **sharded by thread**.
|
|
4
|
-
*
|
|
5
|
-
* Each user has one session record. Inside that record, `history` keeps
|
|
6
|
-
* a separate ring buffer per thread:
|
|
7
|
-
*
|
|
8
|
-
* storage[userId].history.shards = {
|
|
9
|
-
* 'general': [ ...entries from no-thread messages ],
|
|
10
|
-
* '12345': [ ...entries from message_thread_id=12345 ],
|
|
11
|
-
* '98765': [ ...entries from message_thread_id=98765 ],
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* This makes the plugin compatible with both forum-supergroup topics
|
|
15
|
-
* and BotFather's Threaded Mode for private chats (which is the whole
|
|
16
|
-
* point of those features: parallel conversations with separate
|
|
17
|
-
* context). `ctx.history` returns ONLY the slice for the current
|
|
18
|
-
* thread; `ctx.allHistory` returns the full sharded map when you need
|
|
19
|
-
* a cross-thread view (e.g. for `/export`).
|
|
20
|
-
*
|
|
21
|
-
* Thread key: `String(ctx.threadId)`, or `'general'` when no thread.
|
|
22
|
-
*
|
|
23
|
-
* ## What this plugin owns
|
|
24
|
-
*
|
|
25
|
-
* - Appends each incoming user message to the shard for its thread
|
|
26
|
-
* - Prunes per-shard by `retentionDays` and `maxMessages`
|
|
27
|
-
* - Exposes `ctx.history` (current thread's pruned slice) and
|
|
28
|
-
* `ctx.allHistory` (full map) to handlers
|
|
29
|
-
*
|
|
30
|
-
* ## GDPR caveat — retention IS personal data
|
|
31
|
-
*
|
|
32
|
-
* Unlike `bot/language` (preference data, covered by Telegram's standard
|
|
33
|
-
* privacy policy), retaining user **message content** is the one thing
|
|
34
|
-
* the [standard policy](https://telegram.org/privacy-tpa) does NOT cover
|
|
35
|
-
* by default. If you extend `messageHistory`, you should:
|
|
36
|
-
*
|
|
37
|
-
* 1. Set a custom `privacy` URL on your `botMenu` describing what you
|
|
38
|
-
* retain and for how long.
|
|
39
|
-
* 2. Pass `personalData: { storage }` to your `botMenu` so 🗑 Forget
|
|
40
|
-
* and 📥 Export buttons appear — letting users see and delete
|
|
41
|
-
* the data you keep about them.
|
|
42
|
-
*
|
|
43
|
-
* These are not enforced by this plugin (would couple it to menu); they
|
|
44
|
-
* are documented as the bot author's legal responsibility.
|
|
45
|
-
*
|
|
46
|
-
* Peer deps: `gramio`, `@gramio/session`.
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* import { Bot } from 'gramio'
|
|
50
|
-
* import { session } from '@gramio/session'
|
|
51
|
-
* import { redisStorage } from '@gramio/storage-redis'
|
|
52
|
-
* import { messageHistory } from '@adriangalilea/utils/bot/message-history'
|
|
53
|
-
*
|
|
54
|
-
* const userSession = session({ storage: redisStorage(), key: 'session', initial: () => ({}) })
|
|
55
|
-
*
|
|
56
|
-
* const history = messageHistory({
|
|
57
|
-
* session: userSession,
|
|
58
|
-
* maxMessages: 100, // cap per-thread
|
|
59
|
-
* retentionDays: 7,
|
|
60
|
-
* })
|
|
61
|
-
*
|
|
62
|
-
* const bot = new Bot(process.env.BOT_TOKEN!)
|
|
63
|
-
* .extend(userSession)
|
|
64
|
-
* .extend(history.plugin)
|
|
65
|
-
* .command('replay', (ctx) => {
|
|
66
|
-
* const last = ctx.history.slice(-3).map((e) => e.text).join('\n---\n')
|
|
67
|
-
* return ctx.send(last || '(no history in this thread)')
|
|
68
|
-
* })
|
|
69
|
-
*/
|
|
70
|
-
import { type DeriveDefinitions, Plugin } from 'gramio';
|
|
71
|
-
import { session } from '@gramio/session';
|
|
72
|
-
export type HistoryEntry = {
|
|
73
|
-
/** Telegram message id. */
|
|
74
|
-
messageId: number;
|
|
75
|
-
/** Unix seconds (Telegram's `message.date`). */
|
|
76
|
-
date: number;
|
|
77
|
-
/** Message text, or empty string if non-text. */
|
|
78
|
-
text: string;
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Per-thread shards. Key is `String(ctx.threadId)` or `'general'`
|
|
82
|
-
* when no thread. Each shard is an independently capped + pruned
|
|
83
|
-
* ring buffer.
|
|
84
|
-
*/
|
|
85
|
-
export type HistoryRecord = {
|
|
86
|
-
shards: {
|
|
87
|
-
[threadKey: string]: HistoryEntry[];
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
/** Loose session shape — this plugin only touches the `history` field. */
|
|
91
|
-
type SessionLike = {
|
|
92
|
-
history?: HistoryRecord;
|
|
93
|
-
};
|
|
94
|
-
/** @internal — kept unexported so it doesn't clash with peers' refs. */
|
|
95
|
-
type HistorySessionPluginRef = ReturnType<typeof session<SessionLike, 'session'>>;
|
|
96
|
-
export type MessageHistoryOptions = {
|
|
97
|
-
/**
|
|
98
|
-
* Shared session plugin. This plugin extends it for the type flow;
|
|
99
|
-
* gramio's runtime dedup ensures it only runs once per update.
|
|
100
|
-
*/
|
|
101
|
-
session: HistorySessionPluginRef;
|
|
102
|
-
/** Ring buffer cap **per thread**. Oldest entries dropped when exceeded. */
|
|
103
|
-
maxMessages: number;
|
|
104
|
-
/** Entries older than this (in days) are dropped on read. */
|
|
105
|
-
retentionDays: number;
|
|
106
|
-
};
|
|
107
|
-
export type MessageHistoryFeature = {
|
|
108
|
-
plugin: ReturnType<typeof buildHistoryPlugin>;
|
|
109
|
-
};
|
|
110
|
-
type HistoryDerives = {
|
|
111
|
-
/** Pruned snapshot for the CURRENT thread only. */
|
|
112
|
-
history: ReadonlyArray<HistoryEntry>;
|
|
113
|
-
/**
|
|
114
|
-
* Pruned snapshot of all threads, keyed by thread (`'general'` or
|
|
115
|
-
* stringified threadId). Use for cross-thread views (e.g. /export).
|
|
116
|
-
*/
|
|
117
|
-
allHistory: Readonly<{
|
|
118
|
-
[threadKey: string]: ReadonlyArray<HistoryEntry>;
|
|
119
|
-
}>;
|
|
120
|
-
};
|
|
121
|
-
export declare const messageHistory: (opts: MessageHistoryOptions) => MessageHistoryFeature;
|
|
122
|
-
declare const buildHistoryPlugin: (args: {
|
|
123
|
-
sessionPlugin: HistorySessionPluginRef;
|
|
124
|
-
maxMessages: number;
|
|
125
|
-
retentionDays: number;
|
|
126
|
-
}) => Plugin<{}, DeriveDefinitions & {
|
|
127
|
-
global: HistoryDerives;
|
|
128
|
-
} & {
|
|
129
|
-
message: {
|
|
130
|
-
session: SessionLike & {
|
|
131
|
-
$clear: () => Promise<void>;
|
|
132
|
-
};
|
|
133
|
-
};
|
|
134
|
-
channel_post: {
|
|
135
|
-
session: SessionLike & {
|
|
136
|
-
$clear: () => Promise<void>;
|
|
137
|
-
};
|
|
138
|
-
};
|
|
139
|
-
inline_query: {
|
|
140
|
-
session: SessionLike & {
|
|
141
|
-
$clear: () => Promise<void>;
|
|
142
|
-
};
|
|
143
|
-
};
|
|
144
|
-
chosen_inline_result: {
|
|
145
|
-
session: SessionLike & {
|
|
146
|
-
$clear: () => Promise<void>;
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
callback_query: {
|
|
150
|
-
session: SessionLike & {
|
|
151
|
-
$clear: () => Promise<void>;
|
|
152
|
-
};
|
|
153
|
-
};
|
|
154
|
-
shipping_query: {
|
|
155
|
-
session: SessionLike & {
|
|
156
|
-
$clear: () => Promise<void>;
|
|
157
|
-
};
|
|
158
|
-
};
|
|
159
|
-
pre_checkout_query: {
|
|
160
|
-
session: SessionLike & {
|
|
161
|
-
$clear: () => Promise<void>;
|
|
162
|
-
};
|
|
163
|
-
};
|
|
164
|
-
poll_answer: {
|
|
165
|
-
session: SessionLike & {
|
|
166
|
-
$clear: () => Promise<void>;
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
chat_join_request: {
|
|
170
|
-
session: SessionLike & {
|
|
171
|
-
$clear: () => Promise<void>;
|
|
172
|
-
};
|
|
173
|
-
};
|
|
174
|
-
new_chat_members: {
|
|
175
|
-
session: SessionLike & {
|
|
176
|
-
$clear: () => Promise<void>;
|
|
177
|
-
};
|
|
178
|
-
};
|
|
179
|
-
new_chat_title: {
|
|
180
|
-
session: SessionLike & {
|
|
181
|
-
$clear: () => Promise<void>;
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
new_chat_photo: {
|
|
185
|
-
session: SessionLike & {
|
|
186
|
-
$clear: () => Promise<void>;
|
|
187
|
-
};
|
|
188
|
-
};
|
|
189
|
-
delete_chat_photo: {
|
|
190
|
-
session: SessionLike & {
|
|
191
|
-
$clear: () => Promise<void>;
|
|
192
|
-
};
|
|
193
|
-
};
|
|
194
|
-
group_chat_created: {
|
|
195
|
-
session: SessionLike & {
|
|
196
|
-
$clear: () => Promise<void>;
|
|
197
|
-
};
|
|
198
|
-
};
|
|
199
|
-
message_auto_delete_timer_changed: {
|
|
200
|
-
session: SessionLike & {
|
|
201
|
-
$clear: () => Promise<void>;
|
|
202
|
-
};
|
|
203
|
-
};
|
|
204
|
-
migrate_to_chat_id: {
|
|
205
|
-
session: SessionLike & {
|
|
206
|
-
$clear: () => Promise<void>;
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
migrate_from_chat_id: {
|
|
210
|
-
session: SessionLike & {
|
|
211
|
-
$clear: () => Promise<void>;
|
|
212
|
-
};
|
|
213
|
-
};
|
|
214
|
-
pinned_message: {
|
|
215
|
-
session: SessionLike & {
|
|
216
|
-
$clear: () => Promise<void>;
|
|
217
|
-
};
|
|
218
|
-
};
|
|
219
|
-
invoice: {
|
|
220
|
-
session: SessionLike & {
|
|
221
|
-
$clear: () => Promise<void>;
|
|
222
|
-
};
|
|
223
|
-
};
|
|
224
|
-
successful_payment: {
|
|
225
|
-
session: SessionLike & {
|
|
226
|
-
$clear: () => Promise<void>;
|
|
227
|
-
};
|
|
228
|
-
};
|
|
229
|
-
chat_shared: {
|
|
230
|
-
session: SessionLike & {
|
|
231
|
-
$clear: () => Promise<void>;
|
|
232
|
-
};
|
|
233
|
-
};
|
|
234
|
-
proximity_alert_triggered: {
|
|
235
|
-
session: SessionLike & {
|
|
236
|
-
$clear: () => Promise<void>;
|
|
237
|
-
};
|
|
238
|
-
};
|
|
239
|
-
video_chat_scheduled: {
|
|
240
|
-
session: SessionLike & {
|
|
241
|
-
$clear: () => Promise<void>;
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
video_chat_started: {
|
|
245
|
-
session: SessionLike & {
|
|
246
|
-
$clear: () => Promise<void>;
|
|
247
|
-
};
|
|
248
|
-
};
|
|
249
|
-
video_chat_ended: {
|
|
250
|
-
session: SessionLike & {
|
|
251
|
-
$clear: () => Promise<void>;
|
|
252
|
-
};
|
|
253
|
-
};
|
|
254
|
-
video_chat_participants_invited: {
|
|
255
|
-
session: SessionLike & {
|
|
256
|
-
$clear: () => Promise<void>;
|
|
257
|
-
};
|
|
258
|
-
};
|
|
259
|
-
web_app_data: {
|
|
260
|
-
session: SessionLike & {
|
|
261
|
-
$clear: () => Promise<void>;
|
|
262
|
-
};
|
|
263
|
-
};
|
|
264
|
-
location: {
|
|
265
|
-
session: SessionLike & {
|
|
266
|
-
$clear: () => Promise<void>;
|
|
267
|
-
};
|
|
268
|
-
};
|
|
269
|
-
passport_data: {
|
|
270
|
-
session: SessionLike & {
|
|
271
|
-
$clear: () => Promise<void>;
|
|
272
|
-
};
|
|
273
|
-
};
|
|
274
|
-
} & {
|
|
275
|
-
message: HistoryDerives;
|
|
276
|
-
callback_query: HistoryDerives;
|
|
277
|
-
}, {}>;
|
|
278
|
-
export {};
|
|
279
|
-
//# sourceMappingURL=message-history.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message-history.d.ts","sourceRoot":"","sources":["../../src/bot/message-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAIzC,MAAM,MAAM,YAAY,GAAG;IACzB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAAA;KAAE,CAAA;CAChD,CAAA;AAaD,0EAA0E;AAC1E,KAAK,WAAW,GAAG;IAAE,OAAO,CAAC,EAAE,aAAa,CAAA;CAAE,CAAA;AAE9C,wEAAwE;AACxE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAA;AAEjF,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;OAGG;IACH,OAAO,EAAE,uBAAuB,CAAA;IAChC,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IACnB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;CAC9C,CAAA;AAID,KAAK,cAAc,GAAG;IACpB,mDAAmD;IACnD,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;IACpC;;;OAGG;IACH,UAAU,EAAE,QAAQ,CAAC;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,CAAA;KAAE,CAAC,CAAA;CAC3E,CAAA;AA6BD,eAAO,MAAM,cAAc,GAAI,MAAM,qBAAqB,KAAG,qBAW5D,CAAA;AAID,QAAA,MAAM,kBAAkB,GAAI,MAAM;IAChC,aAAa,EAAE,uBAAuB,CAAA;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;CACtB;YAGqD,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqCnE,CAAA"}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-user rolling message history for GramIO bots — opt-in, with
|
|
3
|
-
* retention, **sharded by thread**.
|
|
4
|
-
*
|
|
5
|
-
* Each user has one session record. Inside that record, `history` keeps
|
|
6
|
-
* a separate ring buffer per thread:
|
|
7
|
-
*
|
|
8
|
-
* storage[userId].history.shards = {
|
|
9
|
-
* 'general': [ ...entries from no-thread messages ],
|
|
10
|
-
* '12345': [ ...entries from message_thread_id=12345 ],
|
|
11
|
-
* '98765': [ ...entries from message_thread_id=98765 ],
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* This makes the plugin compatible with both forum-supergroup topics
|
|
15
|
-
* and BotFather's Threaded Mode for private chats (which is the whole
|
|
16
|
-
* point of those features: parallel conversations with separate
|
|
17
|
-
* context). `ctx.history` returns ONLY the slice for the current
|
|
18
|
-
* thread; `ctx.allHistory` returns the full sharded map when you need
|
|
19
|
-
* a cross-thread view (e.g. for `/export`).
|
|
20
|
-
*
|
|
21
|
-
* Thread key: `String(ctx.threadId)`, or `'general'` when no thread.
|
|
22
|
-
*
|
|
23
|
-
* ## What this plugin owns
|
|
24
|
-
*
|
|
25
|
-
* - Appends each incoming user message to the shard for its thread
|
|
26
|
-
* - Prunes per-shard by `retentionDays` and `maxMessages`
|
|
27
|
-
* - Exposes `ctx.history` (current thread's pruned slice) and
|
|
28
|
-
* `ctx.allHistory` (full map) to handlers
|
|
29
|
-
*
|
|
30
|
-
* ## GDPR caveat — retention IS personal data
|
|
31
|
-
*
|
|
32
|
-
* Unlike `bot/language` (preference data, covered by Telegram's standard
|
|
33
|
-
* privacy policy), retaining user **message content** is the one thing
|
|
34
|
-
* the [standard policy](https://telegram.org/privacy-tpa) does NOT cover
|
|
35
|
-
* by default. If you extend `messageHistory`, you should:
|
|
36
|
-
*
|
|
37
|
-
* 1. Set a custom `privacy` URL on your `botMenu` describing what you
|
|
38
|
-
* retain and for how long.
|
|
39
|
-
* 2. Pass `personalData: { storage }` to your `botMenu` so 🗑 Forget
|
|
40
|
-
* and 📥 Export buttons appear — letting users see and delete
|
|
41
|
-
* the data you keep about them.
|
|
42
|
-
*
|
|
43
|
-
* These are not enforced by this plugin (would couple it to menu); they
|
|
44
|
-
* are documented as the bot author's legal responsibility.
|
|
45
|
-
*
|
|
46
|
-
* Peer deps: `gramio`, `@gramio/session`.
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* import { Bot } from 'gramio'
|
|
50
|
-
* import { session } from '@gramio/session'
|
|
51
|
-
* import { redisStorage } from '@gramio/storage-redis'
|
|
52
|
-
* import { messageHistory } from '@adriangalilea/utils/bot/message-history'
|
|
53
|
-
*
|
|
54
|
-
* const userSession = session({ storage: redisStorage(), key: 'session', initial: () => ({}) })
|
|
55
|
-
*
|
|
56
|
-
* const history = messageHistory({
|
|
57
|
-
* session: userSession,
|
|
58
|
-
* maxMessages: 100, // cap per-thread
|
|
59
|
-
* retentionDays: 7,
|
|
60
|
-
* })
|
|
61
|
-
*
|
|
62
|
-
* const bot = new Bot(process.env.BOT_TOKEN!)
|
|
63
|
-
* .extend(userSession)
|
|
64
|
-
* .extend(history.plugin)
|
|
65
|
-
* .command('replay', (ctx) => {
|
|
66
|
-
* const last = ctx.history.slice(-3).map((e) => e.text).join('\n---\n')
|
|
67
|
-
* return ctx.send(last || '(no history in this thread)')
|
|
68
|
-
* })
|
|
69
|
-
*/
|
|
70
|
-
import { Plugin } from 'gramio';
|
|
71
|
-
const GENERAL_THREAD = 'general';
|
|
72
|
-
const threadKey = (ctx) => {
|
|
73
|
-
// Message events: ctx.threadId. Callback events: ctx.message.threadId.
|
|
74
|
-
const tid = ctx.threadId ?? ctx.message?.threadId;
|
|
75
|
-
return tid !== undefined ? String(tid) : GENERAL_THREAD;
|
|
76
|
-
};
|
|
77
|
-
// ─── helpers ───────────────────────────────────────────────────────
|
|
78
|
-
const prune = (items, maxMessages, retentionDays) => {
|
|
79
|
-
const cutoffSec = Math.floor(Date.now() / 1000) - retentionDays * 86400;
|
|
80
|
-
const fresh = items.filter((e) => e.date >= cutoffSec);
|
|
81
|
-
return fresh.slice(-maxMessages);
|
|
82
|
-
};
|
|
83
|
-
const pruneAll = (shards, maxMessages, retentionDays) => {
|
|
84
|
-
const out = {};
|
|
85
|
-
for (const k of Object.keys(shards)) {
|
|
86
|
-
const pruned = prune(shards[k], maxMessages, retentionDays);
|
|
87
|
-
if (pruned.length > 0)
|
|
88
|
-
out[k] = pruned;
|
|
89
|
-
}
|
|
90
|
-
return out;
|
|
91
|
-
};
|
|
92
|
-
// ─── feature factory ───────────────────────────────────────────────
|
|
93
|
-
export const messageHistory = (opts) => {
|
|
94
|
-
if (opts.maxMessages <= 0)
|
|
95
|
-
throw new Error('messageHistory: maxMessages must be > 0');
|
|
96
|
-
if (opts.retentionDays <= 0)
|
|
97
|
-
throw new Error('messageHistory: retentionDays must be > 0');
|
|
98
|
-
const plugin = buildHistoryPlugin({
|
|
99
|
-
sessionPlugin: opts.session,
|
|
100
|
-
maxMessages: opts.maxMessages,
|
|
101
|
-
retentionDays: opts.retentionDays,
|
|
102
|
-
});
|
|
103
|
-
return { plugin };
|
|
104
|
-
};
|
|
105
|
-
// ─── plugin builder ────────────────────────────────────────────────
|
|
106
|
-
const buildHistoryPlugin = (args) => {
|
|
107
|
-
const { sessionPlugin, maxMessages, retentionDays } = args;
|
|
108
|
-
return new Plugin('@adriangalilea/utils/bot/message-history')
|
|
109
|
-
.extend(sessionPlugin)
|
|
110
|
-
// Record incoming messages with text into their thread's shard.
|
|
111
|
-
// Service messages, edits, and callback queries don't append —
|
|
112
|
-
// only direct user input.
|
|
113
|
-
.on('message', async (ctx, next) => {
|
|
114
|
-
if (ctx.text !== undefined) {
|
|
115
|
-
const entry = {
|
|
116
|
-
messageId: ctx.id,
|
|
117
|
-
date: ctx.payload.date,
|
|
118
|
-
text: ctx.text,
|
|
119
|
-
};
|
|
120
|
-
const key = threadKey(ctx);
|
|
121
|
-
const shards = { ...(ctx.session.history?.shards ?? {}) };
|
|
122
|
-
const cur = shards[key] ?? [];
|
|
123
|
-
shards[key] = [
|
|
124
|
-
...prune(cur, maxMessages, retentionDays),
|
|
125
|
-
entry,
|
|
126
|
-
].slice(-maxMessages);
|
|
127
|
-
ctx.session.history = { shards };
|
|
128
|
-
}
|
|
129
|
-
return next();
|
|
130
|
-
})
|
|
131
|
-
// Read-only views for handlers downstream.
|
|
132
|
-
.derive(['message', 'callback_query'], (ctx) => {
|
|
133
|
-
const shards = ctx.session.history?.shards ?? {};
|
|
134
|
-
const allPruned = pruneAll(shards, maxMessages, retentionDays);
|
|
135
|
-
const key = threadKey(ctx);
|
|
136
|
-
return {
|
|
137
|
-
history: (allPruned[key] ?? []),
|
|
138
|
-
allHistory: allPruned,
|
|
139
|
-
};
|
|
140
|
-
});
|
|
141
|
-
};
|
|
142
|
-
//# sourceMappingURL=message-history.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message-history.js","sourceRoot":"","sources":["../../src/bot/message-history.ts"],"names":[],"mappings":"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"}
|