@openclaw/synology-chat 2026.5.7-beta.1 → 2026.5.9-beta.1
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/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as setSynologyRuntime, t as synologyChatPlugin } from "./channel-
|
|
1
|
+
import { n as setSynologyRuntime, t as synologyChatPlugin } from "./channel-eRS88UFd.js";
|
|
2
2
|
import { t as collectSynologyChatSecurityAuditFindings } from "./security-audit-Zu_nkF2x.js";
|
|
3
3
|
export { collectSynologyChatSecurityAuditFindings, setSynologyRuntime, synologyChatPlugin };
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { i as resolveAccount, n as synologyChatSetupWizard, r as listAccountIds, t as synologyChatSetupAdapter } from "./setup-surface-
|
|
1
|
+
import { i as resolveAccount, n as synologyChatSetupWizard, r as listAccountIds, t as synologyChatSetupAdapter } from "./setup-surface-daP5yN4Y.js";
|
|
2
2
|
import { t as collectSynologyChatSecurityAuditFindings } from "./security-audit-Zu_nkF2x.js";
|
|
3
3
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
4
4
|
import { createHybridChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
5
5
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
6
6
|
import { waitUntilAbort } from "openclaw/plugin-sdk/channel-lifecycle";
|
|
7
|
+
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-message";
|
|
7
8
|
import { composeWarningCollectors, createConditionalWarningCollector, projectAccountConfigWarningCollector, projectAccountWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
8
|
-
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
9
9
|
import { createEmptyChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
|
|
10
|
+
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
|
10
11
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/account-resolution";
|
|
11
12
|
import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
12
13
|
import * as http from "node:http";
|
|
13
14
|
import * as https from "node:https";
|
|
14
15
|
import { safeParseJsonWithSchema, safeParseWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
16
|
+
import { sleep } from "openclaw/plugin-sdk/runtime-env";
|
|
15
17
|
import { formatErrorMessage, resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
16
|
-
import { z } from "zod";
|
|
18
|
+
import { z } from "openclaw/plugin-sdk/zod";
|
|
17
19
|
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
18
|
-
import { z as z$1 } from "openclaw/plugin-sdk/zod";
|
|
19
20
|
import { beginWebhookRequestPipelineOrReject, createFixedWindowRateLimiter, createWebhookInFlightLimiter, isRequestBodyLimitError, readRequestBodyWithLimit, registerPluginHttpRoute, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
|
|
20
21
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
21
22
|
import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
@@ -44,9 +45,6 @@ const synologyChatApprovalAuth = createResolvedApproverActionAuthAdapter({
|
|
|
44
45
|
*/
|
|
45
46
|
const MIN_SEND_INTERVAL_MS = 500;
|
|
46
47
|
let lastSendTime = 0;
|
|
47
|
-
function normalizeLowercaseStringOrEmpty$2(value) {
|
|
48
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
49
|
-
}
|
|
50
48
|
const ChatUserSchema = z.object({
|
|
51
49
|
user_id: z.number(),
|
|
52
50
|
username: z.string().optional(),
|
|
@@ -179,10 +177,10 @@ async function assertSafeWebhookFileUrl(fileUrl) {
|
|
|
179
177
|
*/
|
|
180
178
|
async function resolveLegacyWebhookNameToChatUserId(params) {
|
|
181
179
|
const users = await fetchChatUsers(params.incomingUrl, params.allowInsecureSsl, params.log);
|
|
182
|
-
const lower = normalizeLowercaseStringOrEmpty
|
|
183
|
-
const byNickname = users.find((u) => normalizeLowercaseStringOrEmpty
|
|
180
|
+
const lower = normalizeLowercaseStringOrEmpty(params.mutableWebhookUsername);
|
|
181
|
+
const byNickname = users.find((u) => normalizeLowercaseStringOrEmpty(u.nickname) === lower);
|
|
184
182
|
if (byNickname) return byNickname.user_id;
|
|
185
|
-
const byUsername = users.find((u) => normalizeLowercaseStringOrEmpty
|
|
183
|
+
const byUsername = users.find((u) => normalizeLowercaseStringOrEmpty(u.username) === lower);
|
|
186
184
|
if (byUsername) return byUsername.user_id;
|
|
187
185
|
}
|
|
188
186
|
function buildWebhookBody(payload, userId) {
|
|
@@ -230,14 +228,11 @@ function doPost(url, body, allowInsecureSsl = false) {
|
|
|
230
228
|
req.end();
|
|
231
229
|
});
|
|
232
230
|
}
|
|
233
|
-
function sleep(ms) {
|
|
234
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
235
|
-
}
|
|
236
231
|
//#endregion
|
|
237
232
|
//#region extensions/synology-chat/src/config-schema.ts
|
|
238
|
-
const SynologyChatChannelConfigSchema = buildChannelConfigSchema(z
|
|
239
|
-
dangerouslyAllowNameMatching: z
|
|
240
|
-
dangerouslyAllowInheritedWebhookPath: z
|
|
233
|
+
const SynologyChatChannelConfigSchema = buildChannelConfigSchema(z.object({
|
|
234
|
+
dangerouslyAllowNameMatching: z.boolean().optional(),
|
|
235
|
+
dangerouslyAllowInheritedWebhookPath: z.boolean().optional()
|
|
241
236
|
}).passthrough());
|
|
242
237
|
//#endregion
|
|
243
238
|
//#region extensions/synology-chat/src/runtime.ts
|
|
@@ -288,8 +283,8 @@ function resolveSynologyChatInboundRoute(params) {
|
|
|
288
283
|
}
|
|
289
284
|
async function deliverSynologyChatReply(params) {
|
|
290
285
|
const text = params.payload.text ?? params.payload.body;
|
|
291
|
-
if (!text) return;
|
|
292
|
-
await sendMessage(params.account.incomingUrl, text, params.sendUserId, params.account.allowInsecureSsl);
|
|
286
|
+
if (!text) return { visibleReplySent: false };
|
|
287
|
+
return { visibleReplySent: await sendMessage(params.account.incomingUrl, text, params.sendUserId, params.account.allowInsecureSsl) };
|
|
293
288
|
}
|
|
294
289
|
async function dispatchSynologyChatInboundTurn(params) {
|
|
295
290
|
const currentCfg = getSynologyRuntime().config.current();
|
|
@@ -364,13 +359,16 @@ async function dispatchSynologyChatInboundTurn(params) {
|
|
|
364
359
|
ctxPayload: msgCtx,
|
|
365
360
|
recordInboundSession: resolved.rt.channel.session.recordInboundSession,
|
|
366
361
|
dispatchReplyWithBufferedBlockDispatcher: resolved.rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher,
|
|
367
|
-
delivery: {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
362
|
+
delivery: {
|
|
363
|
+
durable: () => ({ to: sendUserId }),
|
|
364
|
+
deliver: async (payload) => {
|
|
365
|
+
return await deliverSynologyChatReply({
|
|
366
|
+
account: params.account,
|
|
367
|
+
sendUserId,
|
|
368
|
+
payload
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
},
|
|
374
372
|
dispatcherOptions: { onReplyStart: () => {
|
|
375
373
|
params.log?.info?.(`Agent reply started for ${params.msg.from}`);
|
|
376
374
|
} },
|
|
@@ -476,9 +474,6 @@ var RateLimiter = class {
|
|
|
476
474
|
};
|
|
477
475
|
//#endregion
|
|
478
476
|
//#region extensions/synology-chat/src/webhook-handler.ts
|
|
479
|
-
function normalizeLowercaseStringOrEmpty$1(value) {
|
|
480
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
481
|
-
}
|
|
482
477
|
const rateLimiters = /* @__PURE__ */ new Map();
|
|
483
478
|
const invalidTokenRateLimiters = /* @__PURE__ */ new Map();
|
|
484
479
|
const webhookInFlightLimiter = createWebhookInFlightLimiter();
|
|
@@ -642,7 +637,7 @@ function extractTokenFromHeaders(req) {
|
|
|
642
637
|
* - text <- text | message | content
|
|
643
638
|
*/
|
|
644
639
|
function parsePayload(req, body) {
|
|
645
|
-
const contentType = normalizeLowercaseStringOrEmpty
|
|
640
|
+
const contentType = normalizeLowercaseStringOrEmpty(req.headers["content-type"]);
|
|
646
641
|
let bodyFields = {};
|
|
647
642
|
if (contentType.includes("application/json")) bodyFields = parseJsonBody(body);
|
|
648
643
|
else if (contentType.includes("application/x-www-form-urlencoded")) bodyFields = parseFormBody(body);
|
|
@@ -1016,9 +1011,6 @@ function registerSynologyWebhookRoute(params) {
|
|
|
1016
1011
|
* Implements the ChannelPlugin interface following the LINE pattern.
|
|
1017
1012
|
*/
|
|
1018
1013
|
const CHANNEL_ID = "synology-chat";
|
|
1019
|
-
function normalizeLowercaseStringOrEmpty(value) {
|
|
1020
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
1021
|
-
}
|
|
1022
1014
|
const resolveSynologyChatDmPolicy = createScopedDmSecurityResolver({
|
|
1023
1015
|
channelKey: CHANNEL_ID,
|
|
1024
1016
|
resolvePolicy: (account) => account.dmPolicy,
|
|
@@ -1061,6 +1053,53 @@ function requireIncomingUrl(account) {
|
|
|
1061
1053
|
if (!account.incomingUrl) throw new Error("Synology Chat incoming URL not configured");
|
|
1062
1054
|
return account.incomingUrl;
|
|
1063
1055
|
}
|
|
1056
|
+
function createSynologyChatSendResult(params) {
|
|
1057
|
+
return {
|
|
1058
|
+
channel: CHANNEL_ID,
|
|
1059
|
+
messageId: params.messageId,
|
|
1060
|
+
chatId: params.chatId,
|
|
1061
|
+
receipt: createMessageReceiptFromOutboundResults({
|
|
1062
|
+
results: [{
|
|
1063
|
+
channel: CHANNEL_ID,
|
|
1064
|
+
messageId: params.messageId,
|
|
1065
|
+
chatId: params.chatId,
|
|
1066
|
+
conversationId: params.chatId
|
|
1067
|
+
}],
|
|
1068
|
+
threadId: params.chatId,
|
|
1069
|
+
kind: params.kind
|
|
1070
|
+
})
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
async function sendSynologyChatText(ctx) {
|
|
1074
|
+
const account = resolveOutboundAccount(ctx.cfg ?? {}, ctx.accountId);
|
|
1075
|
+
if (!await sendMessage(requireIncomingUrl(account), ctx.text, ctx.to, account.allowInsecureSsl)) throw new Error("Failed to send message to Synology Chat");
|
|
1076
|
+
return createSynologyChatSendResult({
|
|
1077
|
+
messageId: `sc-${Date.now()}`,
|
|
1078
|
+
chatId: ctx.to,
|
|
1079
|
+
kind: "text"
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
async function sendSynologyChatMedia(ctx) {
|
|
1083
|
+
const account = resolveOutboundAccount(ctx.cfg ?? {}, ctx.accountId);
|
|
1084
|
+
if (!await sendFileUrl(requireIncomingUrl(account), ctx.mediaUrl, ctx.to, account.allowInsecureSsl)) throw new Error("Failed to send media to Synology Chat");
|
|
1085
|
+
return createSynologyChatSendResult({
|
|
1086
|
+
messageId: `sc-${Date.now()}`,
|
|
1087
|
+
chatId: ctx.to,
|
|
1088
|
+
kind: "media"
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
const synologyChatMessageAdapter = defineChannelMessageAdapter({
|
|
1092
|
+
id: CHANNEL_ID,
|
|
1093
|
+
durableFinal: { capabilities: {
|
|
1094
|
+
text: true,
|
|
1095
|
+
media: true,
|
|
1096
|
+
messageSendingHooks: true
|
|
1097
|
+
} },
|
|
1098
|
+
send: {
|
|
1099
|
+
text: async (ctx) => await sendSynologyChatText(ctx),
|
|
1100
|
+
media: async (ctx) => await sendSynologyChatMedia(ctx)
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1064
1103
|
function createSynologyChatPlugin() {
|
|
1065
1104
|
return createChatChannelPlugin({
|
|
1066
1105
|
base: {
|
|
@@ -1160,7 +1199,8 @@ function createSynologyChatPlugin() {
|
|
|
1160
1199
|
"- Use line breaks to separate sections",
|
|
1161
1200
|
"- Use numbered or bulleted lists for clarity",
|
|
1162
1201
|
"- Wrap URLs with `<URL|label>` for user-friendly links"
|
|
1163
|
-
] }
|
|
1202
|
+
] },
|
|
1203
|
+
message: synologyChatMessageAdapter
|
|
1164
1204
|
},
|
|
1165
1205
|
pairing: { text: {
|
|
1166
1206
|
idLabel: "synologyChatUserId",
|
|
@@ -1180,22 +1220,12 @@ function createSynologyChatPlugin() {
|
|
|
1180
1220
|
outbound: {
|
|
1181
1221
|
deliveryMode: "gateway",
|
|
1182
1222
|
textChunkLimit: 2e3,
|
|
1183
|
-
sendText:
|
|
1184
|
-
|
|
1185
|
-
if (!
|
|
1186
|
-
return
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
});
|
|
1190
|
-
},
|
|
1191
|
-
sendMedia: async ({ to, mediaUrl, accountId, cfg }) => {
|
|
1192
|
-
const account = resolveOutboundAccount(cfg ?? {}, accountId);
|
|
1193
|
-
const incomingUrl = requireIncomingUrl(account);
|
|
1194
|
-
if (!mediaUrl) throw new Error("No media URL provided");
|
|
1195
|
-
if (!await sendFileUrl(incomingUrl, mediaUrl, to, account.allowInsecureSsl)) throw new Error("Failed to send media to Synology Chat");
|
|
1196
|
-
return attachChannelToResult(CHANNEL_ID, {
|
|
1197
|
-
messageId: `sc-${Date.now()}`,
|
|
1198
|
-
chatId: to
|
|
1223
|
+
sendText: sendSynologyChatText,
|
|
1224
|
+
sendMedia: async (ctx) => {
|
|
1225
|
+
if (!ctx.mediaUrl) throw new Error("Synology Chat media send requires mediaUrl");
|
|
1226
|
+
return await sendSynologyChatMedia({
|
|
1227
|
+
...ctx,
|
|
1228
|
+
mediaUrl: ctx.mediaUrl
|
|
1199
1229
|
});
|
|
1200
1230
|
}
|
|
1201
1231
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as synologyChatPlugin } from "./channel-
|
|
1
|
+
import { t as synologyChatPlugin } from "./channel-eRS88UFd.js";
|
|
2
2
|
export { synologyChatPlugin };
|
package/dist/setup-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as synologyChatSetupWizard, t as synologyChatSetupAdapter } from "./setup-surface-
|
|
1
|
+
import { n as synologyChatSetupWizard, t as synologyChatSetupAdapter } from "./setup-surface-daP5yN4Y.js";
|
|
2
2
|
export { synologyChatSetupAdapter, synologyChatSetupWizard };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
|
1
2
|
import { DEFAULT_ACCOUNT_ID, listCombinedAccountIds, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
2
3
|
import { resolveDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
3
4
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, createAllowFromSection, createStandardChannelSetupStatus, formatDocsLink, mergeAllowFromEntries, normalizeAccountId, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
@@ -114,10 +115,6 @@ const SYNOLOGY_ALLOW_FROM_HELP_LINES = [
|
|
|
114
115
|
"Multiple entries: comma-separated.",
|
|
115
116
|
`Docs: ${formatDocsLink("/channels/synology-chat", "channels/synology-chat")}`
|
|
116
117
|
];
|
|
117
|
-
function normalizeOptionalString(value) {
|
|
118
|
-
if (typeof value !== "string") return;
|
|
119
|
-
return value.trim() || void 0;
|
|
120
|
-
}
|
|
121
118
|
function getChannelConfig(cfg) {
|
|
122
119
|
return cfg.channels?.[channel] ?? {};
|
|
123
120
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/synology-chat",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.9-beta.1",
|
|
4
4
|
"description": "Synology Chat channel plugin for OpenClaw",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/openclaw/openclaw"
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"zod": "^4.4.3"
|
|
12
|
-
},
|
|
13
10
|
"devDependencies": {
|
|
14
11
|
"@openclaw/plugin-sdk": "workspace:*"
|
|
15
12
|
},
|
|
@@ -33,10 +30,10 @@
|
|
|
33
30
|
"minHostVersion": ">=2026.4.10"
|
|
34
31
|
},
|
|
35
32
|
"compat": {
|
|
36
|
-
"pluginApi": ">=2026.5.
|
|
33
|
+
"pluginApi": ">=2026.5.9-beta.1"
|
|
37
34
|
},
|
|
38
35
|
"build": {
|
|
39
|
-
"openclawVersion": "2026.5.
|
|
36
|
+
"openclawVersion": "2026.5.9-beta.1"
|
|
40
37
|
},
|
|
41
38
|
"release": {
|
|
42
39
|
"publishToClawHub": true,
|
|
@@ -52,7 +49,7 @@
|
|
|
52
49
|
"openclaw.plugin.json"
|
|
53
50
|
],
|
|
54
51
|
"peerDependencies": {
|
|
55
|
-
"openclaw": ">=2026.5.
|
|
52
|
+
"openclaw": ">=2026.5.9-beta.1"
|
|
56
53
|
},
|
|
57
54
|
"peerDependenciesMeta": {
|
|
58
55
|
"openclaw": {
|