@wrongstack/telegram 0.320.1 → 1.0.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/inbox.d.ts CHANGED
@@ -26,12 +26,36 @@ export declare class TelegramInbox {
26
26
  private readonly deps;
27
27
  readonly buffer: TelegramIncomingMessage[];
28
28
  constructor(deps: TelegramInboxDeps);
29
+ /**
30
+ * Replace the inbound identity policy sets. Called by the plugin's
31
+ * hot-reload path (api.onConfigChange) so changes to `inboundMode`,
32
+ * `allowedUsers`, and `allowedChats` — all classified `hot` — take effect
33
+ * on the live gate without a plugin restart. The new sets carry the same
34
+ * semantics as construction (empty set = that dimension unrestricted,
35
+ * non-empty = mandatory constraint, fail closed on missing identity).
36
+ */
37
+ updateAllowlist(allowedUsers: Set<string>, allowedChats: Set<string>): void;
29
38
  /** Return buffered messages, newest first. Optionally filter by chat. */
30
39
  getMessages(opts?: {
31
40
  chatId?: string | number | undefined;
32
41
  limit?: number | undefined;
33
42
  }): TelegramIncomingMessage[];
34
- /** Drop messages older than or equal to the given message ID from the buffer (optionally scoped to a specific chat). */
43
+ /**
44
+ * Drop messages older than or equal to the given message ID from the buffer
45
+ * (optionally scoped to a specific chat).
46
+ *
47
+ * Telegram `message_id` is a PER-CHAT counter: ids are ordered only inside
48
+ * one chat and are never comparable across chats. With an explicit
49
+ * `chatId`, the drop is scoped to that chat. Without one, the drop is
50
+ * scoped to the chat(s) that actually contain a buffered message with this
51
+ * exact id — the anchor names a message in a specific chat, and only that
52
+ * chat's `<= anchor` range is meaningful. Other chats keep their mail, so
53
+ * the documented read→ack_last pattern (read newest-first across all
54
+ * chats, ack the highest id seen) can never destroy mail from a chat the
55
+ * agent never read — including messages truncated away by `limit`. A
56
+ * single-chat deployment is unaffected: the one chat owns the anchor,
57
+ * exactly as before.
58
+ */
35
59
  acknowledge(lastMessageId: number, chatId?: string | number | undefined): number;
36
60
  get bufferCount(): number;
37
61
  /**
package/dist/index.js CHANGED
@@ -419,6 +419,18 @@ var TelegramInbox = class {
419
419
  constructor(deps) {
420
420
  this.deps = deps;
421
421
  }
422
+ /**
423
+ * Replace the inbound identity policy sets. Called by the plugin's
424
+ * hot-reload path (api.onConfigChange) so changes to `inboundMode`,
425
+ * `allowedUsers`, and `allowedChats` — all classified `hot` — take effect
426
+ * on the live gate without a plugin restart. The new sets carry the same
427
+ * semantics as construction (empty set = that dimension unrestricted,
428
+ * non-empty = mandatory constraint, fail closed on missing identity).
429
+ */
430
+ updateAllowlist(allowedUsers, allowedChats) {
431
+ this.deps.allowedUsers = allowedUsers;
432
+ this.deps.allowedChats = allowedChats;
433
+ }
422
434
  /** Return buffered messages, newest first. Optionally filter by chat. */
423
435
  getMessages(opts) {
424
436
  let msgs = [...this.buffer].reverse();
@@ -429,17 +441,35 @@ var TelegramInbox = class {
429
441
  const limit = opts?.limit ?? 20;
430
442
  return msgs.slice(0, limit);
431
443
  }
432
- /** Drop messages older than or equal to the given message ID from the buffer (optionally scoped to a specific chat). */
444
+ /**
445
+ * Drop messages older than or equal to the given message ID from the buffer
446
+ * (optionally scoped to a specific chat).
447
+ *
448
+ * Telegram `message_id` is a PER-CHAT counter: ids are ordered only inside
449
+ * one chat and are never comparable across chats. With an explicit
450
+ * `chatId`, the drop is scoped to that chat. Without one, the drop is
451
+ * scoped to the chat(s) that actually contain a buffered message with this
452
+ * exact id — the anchor names a message in a specific chat, and only that
453
+ * chat's `<= anchor` range is meaningful. Other chats keep their mail, so
454
+ * the documented read→ack_last pattern (read newest-first across all
455
+ * chats, ack the highest id seen) can never destroy mail from a chat the
456
+ * agent never read — including messages truncated away by `limit`. A
457
+ * single-chat deployment is unaffected: the one chat owns the anchor,
458
+ * exactly as before.
459
+ */
433
460
  acknowledge(lastMessageId, chatId) {
434
461
  const before = this.buffer.length;
435
462
  const cid = chatId !== void 0 && chatId !== null && String(chatId).trim() !== "" ? String(chatId).trim() : void 0;
463
+ const anchorChats = cid === void 0 ? new Set(
464
+ this.buffer.filter((buffered) => buffered.messageId === lastMessageId).map((buffered) => String(buffered.chatId))
465
+ ) : void 0;
436
466
  const remaining = [];
437
467
  for (const buffered of this.buffer) {
438
468
  if (cid !== void 0) {
439
469
  if (String(buffered.chatId) === cid && buffered.messageId <= lastMessageId) {
440
470
  continue;
441
471
  }
442
- } else if (buffered.messageId <= lastMessageId) {
472
+ } else if (anchorChats?.has(String(buffered.chatId)) && buffered.messageId <= lastMessageId) {
443
473
  continue;
444
474
  }
445
475
  remaining.push(buffered);
@@ -2551,6 +2581,10 @@ var plugin = {
2551
2581
  for (const [key, apply] of HOT_APPLIERS) {
2552
2582
  if (hotSet.has(key)) apply(runtimeCfg, fresh);
2553
2583
  }
2584
+ if (hotSet.has("inboundMode") || hotSet.has("allowedUsers") || hotSet.has("allowedChats")) {
2585
+ const sets = inboundAllowlist(nextTg);
2586
+ bot.inbox.updateAllowlist(sets.allowedUsers, sets.allowedChats);
2587
+ }
2554
2588
  if (restartKeys.length > 0) {
2555
2589
  log.warn(
2556
2590
  "Telegram config changed restart-required keys \u2014 restart the plugin for these to take effect",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/telegram",
3
- "version": "0.320.1",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack plugin — Telegram bridge: send messages, receive prompts, get notified.",
6
6
  "repository": {
@@ -26,11 +26,11 @@
26
26
  "!dist/**/*.map"
27
27
  ],
28
28
  "peerDependencies": {
29
- "@wrongstack/core": "0.320.1"
29
+ "@wrongstack/core": "1.0.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^26.2.0",
33
- "@wrongstack/core": "0.320.1",
33
+ "@wrongstack/core": "1.0.0",
34
34
  "typescript": "^7.0.2"
35
35
  },
36
36
  "publishConfig": {