@symerian/symi 3.0.20 → 3.0.21
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/{audio-preflight-BaCdNfrk.js → audio-preflight-D7BVT-ls.js} +4 -4
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{chrome-UfmVM0xR.js → chrome-B5CO2vB5.js} +7 -7
- package/dist/{deliver-BqXdac6W.js → deliver-CrwjsDwv.js} +1 -1
- package/dist/extensionAPI.js +7 -7
- package/dist/{image-DIWsXYcW.js → image-Csu7WcLW.js} +1 -1
- package/dist/{manager-DW3SxcPr.js → manager-BkkVjTO8.js} +1 -1
- package/dist/{pi-embedded-BNch0U5F.js → pi-embedded-Dhp64z5l.js} +16 -16
- package/dist/{pi-embedded-helpers-IkHl02JF.js → pi-embedded-helpers-840E4hop.js} +4 -4
- package/dist/{pw-ai-nMkA-oDJ.js → pw-ai-CBgJf_RR.js} +1 -1
- package/dist/{runner-DNEC58JI.js → runner-BbFKo1ne.js} +1 -1
- package/dist/{synthesis-BWAr0sZ9.js → synthesis-DoEM0E8_.js} +7 -7
- package/dist/{web-7a-m_UxL.js → web-BYXJn-Ps.js} +7 -7
- package/package.json +1 -1
- package/extensions/imessage/index.ts +0 -17
- package/extensions/imessage/node_modules/.bin/symi +0 -21
- package/extensions/imessage/package.json +0 -15
- package/extensions/imessage/src/channel.outbound.test.ts +0 -66
- package/extensions/imessage/src/channel.ts +0 -298
- package/extensions/imessage/src/runtime.ts +0 -14
- package/extensions/imessage/symi.plugin.json +0 -9
- package/extensions/line/index.ts +0 -19
- package/extensions/line/node_modules/.bin/symi +0 -21
- package/extensions/line/package.json +0 -30
- package/extensions/line/src/card-command.ts +0 -344
- package/extensions/line/src/channel.logout.test.ts +0 -133
- package/extensions/line/src/channel.sendPayload.test.ts +0 -312
- package/extensions/line/src/channel.startup.test.ts +0 -133
- package/extensions/line/src/channel.ts +0 -801
- package/extensions/line/src/runtime.ts +0 -14
- package/extensions/line/symi.plugin.json +0 -9
- package/extensions/signal/index.ts +0 -17
- package/extensions/signal/node_modules/.bin/symi +0 -21
- package/extensions/signal/package.json +0 -15
- package/extensions/signal/src/channel.ts +0 -302
- package/extensions/signal/src/runtime.ts +0 -14
- package/extensions/signal/symi.plugin.json +0 -9
- package/extensions/telegram/index.ts +0 -17
- package/extensions/telegram/node_modules/.bin/symi +0 -21
- package/extensions/telegram/package.json +0 -15
- package/extensions/telegram/src/channel.test.ts +0 -125
- package/extensions/telegram/src/channel.ts +0 -560
- package/extensions/telegram/src/runtime.ts +0 -14
- package/extensions/telegram/symi.plugin.json +0 -9
- package/extensions/whatsapp/index.ts +0 -17
- package/extensions/whatsapp/node_modules/.bin/symi +0 -21
- package/extensions/whatsapp/package.json +0 -15
- package/extensions/whatsapp/src/channel.ts +0 -465
- package/extensions/whatsapp/src/resolve-target.test.ts +0 -170
- package/extensions/whatsapp/src/runtime.ts +0 -14
- package/extensions/whatsapp/symi.plugin.json +0 -9
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { PluginRuntime } from "symi/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
let runtime: PluginRuntime | null = null;
|
|
4
|
-
|
|
5
|
-
export function setLineRuntime(r: PluginRuntime): void {
|
|
6
|
-
runtime = r;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function getLineRuntime(): PluginRuntime {
|
|
10
|
-
if (!runtime) {
|
|
11
|
-
throw new Error("LINE runtime not initialized - plugin not registered");
|
|
12
|
-
}
|
|
13
|
-
return runtime;
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { SymiPluginApi } from "symi/plugin-sdk";
|
|
2
|
-
import { emptyPluginConfigSchema } from "symi/plugin-sdk";
|
|
3
|
-
import { signalPlugin } from "./src/channel.js";
|
|
4
|
-
import { setSignalRuntime } from "./src/runtime.js";
|
|
5
|
-
|
|
6
|
-
const plugin = {
|
|
7
|
-
id: "signal",
|
|
8
|
-
name: "Signal",
|
|
9
|
-
description: "Signal channel plugin",
|
|
10
|
-
configSchema: emptyPluginConfigSchema(),
|
|
11
|
-
register(api: SymiPluginApi) {
|
|
12
|
-
setSignalRuntime(api.runtime);
|
|
13
|
-
api.registerChannel({ plugin: signalPlugin });
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default plugin;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/symi/projects/symi/node_modules:/home/symi/projects/node_modules:/home/symi/node_modules:/home/node_modules:/node_modules:/home/symi/projects/symi/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/symi/projects/symi/node_modules:/home/symi/projects/node_modules:/home/symi/node_modules:/home/node_modules:/node_modules:/home/symi/projects/symi/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../@symerian/symi/symi.mjs" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../@symerian/symi/symi.mjs" "$@"
|
|
21
|
-
fi
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@symi/signal",
|
|
3
|
-
"version": "3.0.9",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "Symi Signal channel plugin",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"devDependencies": {
|
|
8
|
-
"@symerian/symi": "workspace:*"
|
|
9
|
-
},
|
|
10
|
-
"symi": {
|
|
11
|
-
"extensions": [
|
|
12
|
-
"./index.ts"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
applyAccountNameToChannelSection,
|
|
3
|
-
buildBaseChannelStatusSummary,
|
|
4
|
-
buildChannelConfigSchema,
|
|
5
|
-
collectStatusIssuesFromLastError,
|
|
6
|
-
createDefaultChannelRuntimeState,
|
|
7
|
-
DEFAULT_ACCOUNT_ID,
|
|
8
|
-
deleteAccountFromConfigSection,
|
|
9
|
-
formatPairingApproveHint,
|
|
10
|
-
getChatChannelMeta,
|
|
11
|
-
listSignalAccountIds,
|
|
12
|
-
looksLikeSignalTargetId,
|
|
13
|
-
migrateBaseNameToDefaultAccount,
|
|
14
|
-
normalizeAccountId,
|
|
15
|
-
normalizeE164,
|
|
16
|
-
normalizeSignalMessagingTarget,
|
|
17
|
-
PAIRING_APPROVED_MESSAGE,
|
|
18
|
-
resolveChannelMediaMaxBytes,
|
|
19
|
-
resolveDefaultSignalAccountId,
|
|
20
|
-
resolveSignalAccount,
|
|
21
|
-
setAccountEnabledInConfigSection,
|
|
22
|
-
signalOnboardingAdapter,
|
|
23
|
-
SignalConfigSchema,
|
|
24
|
-
type ChannelMessageActionAdapter,
|
|
25
|
-
type ChannelPlugin,
|
|
26
|
-
type ResolvedSignalAccount,
|
|
27
|
-
} from "symi/plugin-sdk";
|
|
28
|
-
import { getSignalRuntime } from "./runtime.js";
|
|
29
|
-
|
|
30
|
-
const signalMessageActions: ChannelMessageActionAdapter = {
|
|
31
|
-
listActions: (ctx) => getSignalRuntime().channel.signal.messageActions?.listActions?.(ctx) ?? [],
|
|
32
|
-
supportsAction: (ctx) =>
|
|
33
|
-
getSignalRuntime().channel.signal.messageActions?.supportsAction?.(ctx) ?? false,
|
|
34
|
-
handleAction: async (ctx) => {
|
|
35
|
-
const ma = getSignalRuntime().channel.signal.messageActions;
|
|
36
|
-
if (!ma?.handleAction) {
|
|
37
|
-
throw new Error("Signal message actions not available");
|
|
38
|
-
}
|
|
39
|
-
return ma.handleAction(ctx);
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const meta = getChatChannelMeta("signal");
|
|
44
|
-
|
|
45
|
-
export const signalPlugin: ChannelPlugin<ResolvedSignalAccount> = {
|
|
46
|
-
id: "signal",
|
|
47
|
-
meta: {
|
|
48
|
-
...meta,
|
|
49
|
-
},
|
|
50
|
-
onboarding: signalOnboardingAdapter,
|
|
51
|
-
pairing: {
|
|
52
|
-
idLabel: "signalNumber",
|
|
53
|
-
normalizeAllowEntry: (entry) => entry.replace(/^signal:/i, ""),
|
|
54
|
-
notifyApproval: async ({ id }) => {
|
|
55
|
-
await getSignalRuntime().channel.signal.sendMessageSignal(id, PAIRING_APPROVED_MESSAGE);
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
capabilities: {
|
|
59
|
-
chatTypes: ["direct", "group"],
|
|
60
|
-
media: true,
|
|
61
|
-
reactions: true,
|
|
62
|
-
},
|
|
63
|
-
actions: signalMessageActions,
|
|
64
|
-
streaming: {
|
|
65
|
-
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
|
|
66
|
-
},
|
|
67
|
-
reload: { configPrefixes: ["channels.signal"] },
|
|
68
|
-
configSchema: buildChannelConfigSchema(SignalConfigSchema),
|
|
69
|
-
config: {
|
|
70
|
-
listAccountIds: (cfg) => listSignalAccountIds(cfg),
|
|
71
|
-
resolveAccount: (cfg, accountId) => resolveSignalAccount({ cfg, accountId }),
|
|
72
|
-
defaultAccountId: (cfg) => resolveDefaultSignalAccountId(cfg),
|
|
73
|
-
setAccountEnabled: ({ cfg, accountId, enabled }) =>
|
|
74
|
-
setAccountEnabledInConfigSection({
|
|
75
|
-
cfg,
|
|
76
|
-
sectionKey: "signal",
|
|
77
|
-
accountId,
|
|
78
|
-
enabled,
|
|
79
|
-
allowTopLevel: true,
|
|
80
|
-
}),
|
|
81
|
-
deleteAccount: ({ cfg, accountId }) =>
|
|
82
|
-
deleteAccountFromConfigSection({
|
|
83
|
-
cfg,
|
|
84
|
-
sectionKey: "signal",
|
|
85
|
-
accountId,
|
|
86
|
-
clearBaseFields: ["account", "httpUrl", "httpHost", "httpPort", "cliPath", "name"],
|
|
87
|
-
}),
|
|
88
|
-
isConfigured: (account) => account.configured,
|
|
89
|
-
describeAccount: (account) => ({
|
|
90
|
-
accountId: account.accountId,
|
|
91
|
-
name: account.name,
|
|
92
|
-
enabled: account.enabled,
|
|
93
|
-
configured: account.configured,
|
|
94
|
-
baseUrl: account.baseUrl,
|
|
95
|
-
}),
|
|
96
|
-
resolveAllowFrom: ({ cfg, accountId }) =>
|
|
97
|
-
(resolveSignalAccount({ cfg, accountId }).config.allowFrom ?? []).map((entry) =>
|
|
98
|
-
String(entry),
|
|
99
|
-
),
|
|
100
|
-
formatAllowFrom: ({ allowFrom }) =>
|
|
101
|
-
allowFrom
|
|
102
|
-
.map((entry) => String(entry).trim())
|
|
103
|
-
.filter(Boolean)
|
|
104
|
-
.map((entry) => (entry === "*" ? "*" : normalizeE164(entry.replace(/^signal:/i, ""))))
|
|
105
|
-
.filter(Boolean),
|
|
106
|
-
resolveDefaultTo: ({ cfg, accountId }) =>
|
|
107
|
-
resolveSignalAccount({ cfg, accountId }).config.defaultTo?.trim() || undefined,
|
|
108
|
-
},
|
|
109
|
-
security: {
|
|
110
|
-
resolveDmPolicy: ({ cfg, accountId, account }) => {
|
|
111
|
-
const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
112
|
-
const useAccountPath = Boolean(cfg.channels?.signal?.accounts?.[resolvedAccountId]);
|
|
113
|
-
const basePath = useAccountPath
|
|
114
|
-
? `channels.signal.accounts.${resolvedAccountId}.`
|
|
115
|
-
: "channels.signal.";
|
|
116
|
-
return {
|
|
117
|
-
policy: account.config.dmPolicy ?? "pairing",
|
|
118
|
-
allowFrom: account.config.allowFrom ?? [],
|
|
119
|
-
policyPath: `${basePath}dmPolicy`,
|
|
120
|
-
allowFromPath: basePath,
|
|
121
|
-
approveHint: formatPairingApproveHint("signal"),
|
|
122
|
-
normalizeEntry: (raw) => normalizeE164(raw.replace(/^signal:/i, "").trim()),
|
|
123
|
-
};
|
|
124
|
-
},
|
|
125
|
-
collectWarnings: ({ account, cfg }) => {
|
|
126
|
-
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
|
127
|
-
const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
|
|
128
|
-
if (groupPolicy !== "open") {
|
|
129
|
-
return [];
|
|
130
|
-
}
|
|
131
|
-
return [
|
|
132
|
-
`- Signal groups: groupPolicy="open" allows any member to trigger the bot. Set channels.signal.groupPolicy="allowlist" + channels.signal.groupAllowFrom to restrict senders.`,
|
|
133
|
-
];
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
messaging: {
|
|
137
|
-
normalizeTarget: normalizeSignalMessagingTarget,
|
|
138
|
-
targetResolver: {
|
|
139
|
-
looksLikeId: looksLikeSignalTargetId,
|
|
140
|
-
hint: "<E.164|uuid:ID|group:ID|signal:group:ID|signal:+E.164>",
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
setup: {
|
|
144
|
-
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
|
|
145
|
-
applyAccountName: ({ cfg, accountId, name }) =>
|
|
146
|
-
applyAccountNameToChannelSection({
|
|
147
|
-
cfg,
|
|
148
|
-
channelKey: "signal",
|
|
149
|
-
accountId,
|
|
150
|
-
name,
|
|
151
|
-
}),
|
|
152
|
-
validateInput: ({ input }) => {
|
|
153
|
-
if (
|
|
154
|
-
!input.signalNumber &&
|
|
155
|
-
!input.httpUrl &&
|
|
156
|
-
!input.httpHost &&
|
|
157
|
-
!input.httpPort &&
|
|
158
|
-
!input.cliPath
|
|
159
|
-
) {
|
|
160
|
-
return "Signal requires --signal-number or --http-url/--http-host/--http-port/--cli-path.";
|
|
161
|
-
}
|
|
162
|
-
return null;
|
|
163
|
-
},
|
|
164
|
-
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
165
|
-
const namedConfig = applyAccountNameToChannelSection({
|
|
166
|
-
cfg,
|
|
167
|
-
channelKey: "signal",
|
|
168
|
-
accountId,
|
|
169
|
-
name: input.name,
|
|
170
|
-
});
|
|
171
|
-
const next =
|
|
172
|
-
accountId !== DEFAULT_ACCOUNT_ID
|
|
173
|
-
? migrateBaseNameToDefaultAccount({
|
|
174
|
-
cfg: namedConfig,
|
|
175
|
-
channelKey: "signal",
|
|
176
|
-
})
|
|
177
|
-
: namedConfig;
|
|
178
|
-
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
179
|
-
return {
|
|
180
|
-
...next,
|
|
181
|
-
channels: {
|
|
182
|
-
...next.channels,
|
|
183
|
-
signal: {
|
|
184
|
-
...next.channels?.signal,
|
|
185
|
-
enabled: true,
|
|
186
|
-
...(input.signalNumber ? { account: input.signalNumber } : {}),
|
|
187
|
-
...(input.cliPath ? { cliPath: input.cliPath } : {}),
|
|
188
|
-
...(input.httpUrl ? { httpUrl: input.httpUrl } : {}),
|
|
189
|
-
...(input.httpHost ? { httpHost: input.httpHost } : {}),
|
|
190
|
-
...(input.httpPort ? { httpPort: Number(input.httpPort) } : {}),
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
return {
|
|
196
|
-
...next,
|
|
197
|
-
channels: {
|
|
198
|
-
...next.channels,
|
|
199
|
-
signal: {
|
|
200
|
-
...next.channels?.signal,
|
|
201
|
-
enabled: true,
|
|
202
|
-
accounts: {
|
|
203
|
-
...next.channels?.signal?.accounts,
|
|
204
|
-
[accountId]: {
|
|
205
|
-
...next.channels?.signal?.accounts?.[accountId],
|
|
206
|
-
enabled: true,
|
|
207
|
-
...(input.signalNumber ? { account: input.signalNumber } : {}),
|
|
208
|
-
...(input.cliPath ? { cliPath: input.cliPath } : {}),
|
|
209
|
-
...(input.httpUrl ? { httpUrl: input.httpUrl } : {}),
|
|
210
|
-
...(input.httpHost ? { httpHost: input.httpHost } : {}),
|
|
211
|
-
...(input.httpPort ? { httpPort: Number(input.httpPort) } : {}),
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
};
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
outbound: {
|
|
220
|
-
deliveryMode: "direct",
|
|
221
|
-
chunker: (text, limit) => getSignalRuntime().channel.text.chunkText(text, limit),
|
|
222
|
-
chunkerMode: "text",
|
|
223
|
-
textChunkLimit: 4000,
|
|
224
|
-
sendText: async ({ cfg, to, text, accountId, deps }) => {
|
|
225
|
-
const send = deps?.sendSignal ?? getSignalRuntime().channel.signal.sendMessageSignal;
|
|
226
|
-
const maxBytes = resolveChannelMediaMaxBytes({
|
|
227
|
-
cfg,
|
|
228
|
-
resolveChannelLimitMb: ({ cfg, accountId }) =>
|
|
229
|
-
cfg.channels?.signal?.accounts?.[accountId]?.mediaMaxMb ??
|
|
230
|
-
cfg.channels?.signal?.mediaMaxMb,
|
|
231
|
-
accountId,
|
|
232
|
-
});
|
|
233
|
-
const result = await send(to, text, {
|
|
234
|
-
maxBytes,
|
|
235
|
-
accountId: accountId ?? undefined,
|
|
236
|
-
});
|
|
237
|
-
return { channel: "signal", ...result };
|
|
238
|
-
},
|
|
239
|
-
sendMedia: async ({ cfg, to, text, mediaUrl, accountId, deps }) => {
|
|
240
|
-
const send = deps?.sendSignal ?? getSignalRuntime().channel.signal.sendMessageSignal;
|
|
241
|
-
const maxBytes = resolveChannelMediaMaxBytes({
|
|
242
|
-
cfg,
|
|
243
|
-
resolveChannelLimitMb: ({ cfg, accountId }) =>
|
|
244
|
-
cfg.channels?.signal?.accounts?.[accountId]?.mediaMaxMb ??
|
|
245
|
-
cfg.channels?.signal?.mediaMaxMb,
|
|
246
|
-
accountId,
|
|
247
|
-
});
|
|
248
|
-
const result = await send(to, text, {
|
|
249
|
-
mediaUrl,
|
|
250
|
-
maxBytes,
|
|
251
|
-
accountId: accountId ?? undefined,
|
|
252
|
-
});
|
|
253
|
-
return { channel: "signal", ...result };
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
status: {
|
|
257
|
-
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
|
|
258
|
-
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("signal", accounts),
|
|
259
|
-
buildChannelSummary: ({ snapshot }) => ({
|
|
260
|
-
...buildBaseChannelStatusSummary(snapshot),
|
|
261
|
-
baseUrl: snapshot.baseUrl ?? null,
|
|
262
|
-
probe: snapshot.probe,
|
|
263
|
-
lastProbeAt: snapshot.lastProbeAt ?? null,
|
|
264
|
-
}),
|
|
265
|
-
probeAccount: async ({ account, timeoutMs }) => {
|
|
266
|
-
const baseUrl = account.baseUrl;
|
|
267
|
-
return await getSignalRuntime().channel.signal.probeSignal(baseUrl, timeoutMs);
|
|
268
|
-
},
|
|
269
|
-
buildAccountSnapshot: ({ account, runtime, probe }) => ({
|
|
270
|
-
accountId: account.accountId,
|
|
271
|
-
name: account.name,
|
|
272
|
-
enabled: account.enabled,
|
|
273
|
-
configured: account.configured,
|
|
274
|
-
baseUrl: account.baseUrl,
|
|
275
|
-
running: runtime?.running ?? false,
|
|
276
|
-
lastStartAt: runtime?.lastStartAt ?? null,
|
|
277
|
-
lastStopAt: runtime?.lastStopAt ?? null,
|
|
278
|
-
lastError: runtime?.lastError ?? null,
|
|
279
|
-
probe,
|
|
280
|
-
lastInboundAt: runtime?.lastInboundAt ?? null,
|
|
281
|
-
lastOutboundAt: runtime?.lastOutboundAt ?? null,
|
|
282
|
-
}),
|
|
283
|
-
},
|
|
284
|
-
gateway: {
|
|
285
|
-
startAccount: async (ctx) => {
|
|
286
|
-
const account = ctx.account;
|
|
287
|
-
ctx.setStatus({
|
|
288
|
-
accountId: account.accountId,
|
|
289
|
-
baseUrl: account.baseUrl,
|
|
290
|
-
});
|
|
291
|
-
ctx.log?.info(`[${account.accountId}] starting provider (${account.baseUrl})`);
|
|
292
|
-
// Lazy import: the monitor pulls the reply pipeline; avoid ESM init cycles.
|
|
293
|
-
return getSignalRuntime().channel.signal.monitorSignalProvider({
|
|
294
|
-
accountId: account.accountId,
|
|
295
|
-
config: ctx.cfg,
|
|
296
|
-
runtime: ctx.runtime,
|
|
297
|
-
abortSignal: ctx.abortSignal,
|
|
298
|
-
mediaMaxMb: account.config.mediaMaxMb,
|
|
299
|
-
});
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { PluginRuntime } from "symi/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
let runtime: PluginRuntime | null = null;
|
|
4
|
-
|
|
5
|
-
export function setSignalRuntime(next: PluginRuntime) {
|
|
6
|
-
runtime = next;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function getSignalRuntime(): PluginRuntime {
|
|
10
|
-
if (!runtime) {
|
|
11
|
-
throw new Error("Signal runtime not initialized");
|
|
12
|
-
}
|
|
13
|
-
return runtime;
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { ChannelPlugin, SymiPluginApi } from "symi/plugin-sdk";
|
|
2
|
-
import { emptyPluginConfigSchema } from "symi/plugin-sdk";
|
|
3
|
-
import { telegramPlugin } from "./src/channel.js";
|
|
4
|
-
import { setTelegramRuntime } from "./src/runtime.js";
|
|
5
|
-
|
|
6
|
-
const plugin = {
|
|
7
|
-
id: "telegram",
|
|
8
|
-
name: "Telegram",
|
|
9
|
-
description: "Telegram channel plugin",
|
|
10
|
-
configSchema: emptyPluginConfigSchema(),
|
|
11
|
-
register(api: SymiPluginApi) {
|
|
12
|
-
setTelegramRuntime(api.runtime);
|
|
13
|
-
api.registerChannel({ plugin: telegramPlugin as ChannelPlugin });
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default plugin;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/symi/projects/symi/node_modules:/home/symi/projects/node_modules:/home/symi/node_modules:/home/node_modules:/node_modules:/home/symi/projects/symi/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/symi/projects/symi/node_modules:/home/symi/projects/node_modules:/home/symi/node_modules:/home/node_modules:/node_modules:/home/symi/projects/symi/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../@symerian/symi/symi.mjs" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../@symerian/symi/symi.mjs" "$@"
|
|
21
|
-
fi
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@symi/telegram",
|
|
3
|
-
"version": "3.0.9",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "Symi Telegram channel plugin",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"devDependencies": {
|
|
8
|
-
"@symerian/symi": "workspace:*"
|
|
9
|
-
},
|
|
10
|
-
"symi": {
|
|
11
|
-
"extensions": [
|
|
12
|
-
"./index.ts"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ChannelAccountSnapshot,
|
|
3
|
-
ChannelGatewayContext,
|
|
4
|
-
SymiConfig,
|
|
5
|
-
PluginRuntime,
|
|
6
|
-
ResolvedTelegramAccount,
|
|
7
|
-
RuntimeEnv,
|
|
8
|
-
} from "symi/plugin-sdk";
|
|
9
|
-
import { describe, expect, it, vi } from "vitest";
|
|
10
|
-
import { telegramPlugin } from "./channel.js";
|
|
11
|
-
import { setTelegramRuntime } from "./runtime.js";
|
|
12
|
-
|
|
13
|
-
function createCfg(): SymiConfig {
|
|
14
|
-
return {
|
|
15
|
-
channels: {
|
|
16
|
-
telegram: {
|
|
17
|
-
enabled: true,
|
|
18
|
-
accounts: {
|
|
19
|
-
alerts: { botToken: "token-shared" },
|
|
20
|
-
work: { botToken: "token-shared" },
|
|
21
|
-
ops: { botToken: "token-ops" },
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
} as SymiConfig;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function createRuntimeEnv(): RuntimeEnv {
|
|
29
|
-
return {
|
|
30
|
-
log: vi.fn(),
|
|
31
|
-
error: vi.fn(),
|
|
32
|
-
exit: vi.fn((code: number): never => {
|
|
33
|
-
throw new Error(`exit ${code}`);
|
|
34
|
-
}),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function createStartAccountCtx(params: {
|
|
39
|
-
cfg: SymiConfig;
|
|
40
|
-
accountId: string;
|
|
41
|
-
runtime: RuntimeEnv;
|
|
42
|
-
}): ChannelGatewayContext<ResolvedTelegramAccount> {
|
|
43
|
-
const account = telegramPlugin.config.resolveAccount(
|
|
44
|
-
params.cfg,
|
|
45
|
-
params.accountId,
|
|
46
|
-
) as ResolvedTelegramAccount;
|
|
47
|
-
const snapshot: ChannelAccountSnapshot = {
|
|
48
|
-
accountId: params.accountId,
|
|
49
|
-
configured: true,
|
|
50
|
-
enabled: true,
|
|
51
|
-
running: false,
|
|
52
|
-
};
|
|
53
|
-
return {
|
|
54
|
-
accountId: params.accountId,
|
|
55
|
-
account,
|
|
56
|
-
cfg: params.cfg,
|
|
57
|
-
runtime: params.runtime,
|
|
58
|
-
abortSignal: new AbortController().signal,
|
|
59
|
-
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
60
|
-
getStatus: () => snapshot,
|
|
61
|
-
setStatus: vi.fn(),
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
describe("telegramPlugin duplicate token guard", () => {
|
|
66
|
-
it("marks secondary account as not configured when token is shared", async () => {
|
|
67
|
-
const cfg = createCfg();
|
|
68
|
-
const alertsAccount = telegramPlugin.config.resolveAccount(cfg, "alerts");
|
|
69
|
-
const workAccount = telegramPlugin.config.resolveAccount(cfg, "work");
|
|
70
|
-
const opsAccount = telegramPlugin.config.resolveAccount(cfg, "ops");
|
|
71
|
-
|
|
72
|
-
expect(await telegramPlugin.config.isConfigured!(alertsAccount, cfg)).toBe(true);
|
|
73
|
-
expect(await telegramPlugin.config.isConfigured!(workAccount, cfg)).toBe(false);
|
|
74
|
-
expect(await telegramPlugin.config.isConfigured!(opsAccount, cfg)).toBe(true);
|
|
75
|
-
|
|
76
|
-
expect(telegramPlugin.config.unconfiguredReason?.(workAccount, cfg)).toContain(
|
|
77
|
-
'account "alerts"',
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("surfaces duplicate-token reason in status snapshot", async () => {
|
|
82
|
-
const cfg = createCfg();
|
|
83
|
-
const workAccount = telegramPlugin.config.resolveAccount(cfg, "work");
|
|
84
|
-
const snapshot = await telegramPlugin.status!.buildAccountSnapshot!({
|
|
85
|
-
account: workAccount,
|
|
86
|
-
cfg,
|
|
87
|
-
runtime: undefined,
|
|
88
|
-
probe: undefined,
|
|
89
|
-
audit: undefined,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(snapshot.configured).toBe(false);
|
|
93
|
-
expect(snapshot.lastError).toContain('account "alerts"');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("blocks startup for duplicate token accounts before polling starts", async () => {
|
|
97
|
-
const monitorTelegramProvider = vi.fn(async () => undefined);
|
|
98
|
-
const probeTelegram = vi.fn(async () => ({ ok: true, bot: { username: "bot" } }));
|
|
99
|
-
const runtime = {
|
|
100
|
-
channel: {
|
|
101
|
-
telegram: {
|
|
102
|
-
monitorTelegramProvider,
|
|
103
|
-
probeTelegram,
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
logging: {
|
|
107
|
-
shouldLogVerbose: () => false,
|
|
108
|
-
},
|
|
109
|
-
} as unknown as PluginRuntime;
|
|
110
|
-
setTelegramRuntime(runtime);
|
|
111
|
-
|
|
112
|
-
await expect(
|
|
113
|
-
telegramPlugin.gateway!.startAccount!(
|
|
114
|
-
createStartAccountCtx({
|
|
115
|
-
cfg: createCfg(),
|
|
116
|
-
accountId: "work",
|
|
117
|
-
runtime: createRuntimeEnv(),
|
|
118
|
-
}),
|
|
119
|
-
),
|
|
120
|
-
).rejects.toThrow("Duplicate Telegram bot token");
|
|
121
|
-
|
|
122
|
-
expect(probeTelegram).not.toHaveBeenCalled();
|
|
123
|
-
expect(monitorTelegramProvider).not.toHaveBeenCalled();
|
|
124
|
-
});
|
|
125
|
-
});
|