@goodandready/dsh-messenger-gateway 0.3.14 → 0.3.18
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 +6 -0
- package/lib/adapters/telegram.js +46 -3
- package/lib/client.js +1307 -629
- package/lib/content-guard.js +14 -0
- package/lib/gateway.js +44 -14
- package/lib/index.js +49 -15
- package/lib/models.js +4 -3
- package/lib/outbound.js +2 -1
- package/lib/photos.js +2 -1
- package/lib/session-ops.js +14 -4
- package/lib/telegram-errors.js +51 -41
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -104,6 +104,12 @@ In addition to Telegram, outbound messages can be dispatched to Discord and Slac
|
|
|
104
104
|
- `notifyBridge` — forward non-messenger web session events to a home
|
|
105
105
|
- Bot token is a DSH secret field — never commit it
|
|
106
106
|
|
|
107
|
+
## Client UI & Settings Card
|
|
108
|
+
|
|
109
|
+
- Mounted into `settings.plugin.item` on the Plugins tab (`key: dsh-messenger-gateway`).
|
|
110
|
+
- Configuration is managed reactively via `settingsScope.bind({ namespace: 'dsh-messenger-gateway' })` with snapshot status checking (`loading`, `unavailable`, `ready`).
|
|
111
|
+
- Protected dictionary registration: duplicate registration attempts on page reload are safely caught with non-fatal warnings, ensuring the settings card never fails to mount.
|
|
112
|
+
|
|
107
113
|
## Requirements
|
|
108
114
|
|
|
109
115
|
- DeepSeek Harness web (or compatible) profile
|
package/lib/adapters/telegram.js
CHANGED
|
@@ -11,7 +11,7 @@ import { normalizeThreadId, telegramThreadParams } from '../topics.js'
|
|
|
11
11
|
import {
|
|
12
12
|
shouldProcessTelegramMessage, stripBotCommandSuffix,
|
|
13
13
|
} from '../groups.js'
|
|
14
|
-
import { isResendSafeNetworkError, isPollingConflict } from '../telegram-errors.js'
|
|
14
|
+
import { isResendSafeNetworkError, isPollingConflict, computePollBackoffMs } from '../telegram-errors.js'
|
|
15
15
|
|
|
16
16
|
const API = 'https://api.telegram.org'
|
|
17
17
|
const TELEGRAM_MAX = 4096
|
|
@@ -55,6 +55,7 @@ export class TelegramAdapter {
|
|
|
55
55
|
this.sendRetryMax = 2
|
|
56
56
|
this.sendRetryBaseMs = 400
|
|
57
57
|
this.pollingConflict = false
|
|
58
|
+
this.pollErrorCount = 0
|
|
58
59
|
this.webhookUrl = String(opts.webhookUrl || '').trim()
|
|
59
60
|
this.webhookSecret = String(opts.webhookSecret || '').trim()
|
|
60
61
|
this.offset = 0
|
|
@@ -181,9 +182,10 @@ export class TelegramAdapter {
|
|
|
181
182
|
if (this.statusIndicator) this.setStatusIndicator(this.statusOffline).catch(() => {})
|
|
182
183
|
}
|
|
183
184
|
|
|
184
|
-
schedulePoll() {
|
|
185
|
+
schedulePoll(delayMs) {
|
|
185
186
|
if (this.stopped) return
|
|
186
|
-
|
|
187
|
+
const delay = delayMs !== undefined ? delayMs : this.pollIntervalMs
|
|
188
|
+
this.pollTimer = setTimeout(() => this.poll(), delay)
|
|
187
189
|
this.pollTimer.unref?.()
|
|
188
190
|
}
|
|
189
191
|
|
|
@@ -196,6 +198,7 @@ export class TelegramAdapter {
|
|
|
196
198
|
allowed_updates: ['message', 'callback_query'],
|
|
197
199
|
})
|
|
198
200
|
this.pollingConflict = false
|
|
201
|
+
this.pollErrorCount = 0
|
|
199
202
|
for (const update of updates || []) {
|
|
200
203
|
this.offset = Math.max(this.offset, update.update_id + 1)
|
|
201
204
|
await this.dispatchUpdate(update)
|
|
@@ -579,6 +582,46 @@ export class TelegramAdapter {
|
|
|
579
582
|
return this.sendReply(chatId, undefined, payload, normalizeThreadId(opts.threadId))
|
|
580
583
|
}
|
|
581
584
|
|
|
585
|
+
async probeHealth(timeoutMs = 10000) {
|
|
586
|
+
if (!this.token) {
|
|
587
|
+
return { ok: false, error: 'Telegram bot token is empty' }
|
|
588
|
+
}
|
|
589
|
+
const start = Date.now()
|
|
590
|
+
try {
|
|
591
|
+
const res = await fetch(`${API}/bot${this.token}/getMe`, {
|
|
592
|
+
method: 'POST',
|
|
593
|
+
headers: { 'Content-Type': 'application/json' },
|
|
594
|
+
body: JSON.stringify({}),
|
|
595
|
+
signal: AbortSignal.timeout(Math.max(1000, Number(timeoutMs) || 10000)),
|
|
596
|
+
})
|
|
597
|
+
const latencyMs = Date.now() - start
|
|
598
|
+
const json = await res.json().catch(() => ({}))
|
|
599
|
+
if (!res.ok || json.ok === false) {
|
|
600
|
+
return {
|
|
601
|
+
ok: false,
|
|
602
|
+
latencyMs,
|
|
603
|
+
error: json.description || `HTTP ${res.status}`,
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
const me = json.result || {}
|
|
607
|
+
this.botId = Number(me.id) || this.botId
|
|
608
|
+
this.botUsername = String(me.username || this.botUsername)
|
|
609
|
+
return {
|
|
610
|
+
ok: true,
|
|
611
|
+
latencyMs,
|
|
612
|
+
botId: this.botId,
|
|
613
|
+
botUsername: this.botUsername,
|
|
614
|
+
firstName: me.first_name || '',
|
|
615
|
+
}
|
|
616
|
+
} catch (err) {
|
|
617
|
+
return {
|
|
618
|
+
ok: false,
|
|
619
|
+
latencyMs: Date.now() - start,
|
|
620
|
+
error: err instanceof Error ? err.message : String(err),
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
582
625
|
async createForumTopic(chatId, name, opts = {}) {
|
|
583
626
|
return this.call('createForumTopic', {
|
|
584
627
|
chat_id: chatId,
|