@openclaw/zalo 2026.7.2-beta.7 → 2026.8.1-beta.3
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/{actions.runtime-BYBjeo4Q.js → actions.runtime-DUY9_6Ss.js} +1 -1
- package/dist/api.js +2 -2
- package/dist/{channel-idqJI6YK.js → channel-Vdxu1Y3k.js} +19 -9
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-DsaLk085.js → channel.runtime-UD-M7eDb.js} +18 -35
- package/dist/{monitor-C5cximHM.js → monitor-JdVVhnCm.js} +134 -81
- package/dist/{monitor.webhook-D56OCa3C.js → monitor.webhook-cl1sV6j0.js} +2 -6
- package/dist/runtime-api.js +1 -1
- package/dist/{secret-contract-Bxvjh0Hq.js → secret-contract-Cpsqe5Cv.js} +2 -2
- package/dist/secret-contract-api.js +1 -1
- package/dist/{send-BUvbbedq.js → send-DVMIplpy.js} +6 -4
- package/dist/setup-api.js +2 -2
- package/dist/{setup-core-LzhuTlsD.js → setup-core-CcCJ1E26.js} +19 -25
- package/dist/{setup-surface-CQMbpZye.js → setup-surface-CIpp_MDf.js} +3 -2
- package/dist/setup-surface.js +3 -0
- package/dist/webhook-spool-Bdnu4GjY.js +180 -0
- package/openclaw.plugin.json +99 -0
- package/package.json +8 -5
- package/dist/webhook-spool-DzCPbb3O.js +0 -121
- package/dist/{runtime-api-qxdOyk3M.js → runtime-api-BNim5FCa.js} +1 -1
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as zaloDmPolicy, r as zaloSetupAdapter, t as createZaloSetupWizardProxy } from "./setup-core-
|
|
2
|
-
import { t as zaloPlugin } from "./channel-
|
|
1
|
+
import { n as zaloDmPolicy, r as zaloSetupAdapter, t as createZaloSetupWizardProxy } from "./setup-core-CcCJ1E26.js";
|
|
2
|
+
import { t as zaloPlugin } from "./channel-Vdxu1Y3k.js";
|
|
3
3
|
import { n as resolveZaloRuntimeGroupPolicy } from "./group-access-8qHRzDHx.js";
|
|
4
4
|
import { zaloSetupWizard } from "./setup-api.js";
|
|
5
5
|
export { createZaloSetupWizardProxy, resolveZaloRuntimeGroupPolicy, zaloDmPolicy, zaloPlugin, zaloSetupAdapter, zaloSetupWizard };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { c as inspectZaloAccount, d as resolveZaloAccount, i as zaloSetupContract, l as listZaloAccountIds, p as buildSecretInputSchema,
|
|
2
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-
|
|
1
|
+
import { c as inspectZaloAccount, d as resolveZaloAccount, i as zaloSetupContract, l as listZaloAccountIds, p as buildSecretInputSchema, t as createZaloSetupWizardProxy, u as resolveDefaultZaloAccountId } from "./setup-core-CcCJ1E26.js";
|
|
2
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Cpsqe5Cv.js";
|
|
3
3
|
import { describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
4
4
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
5
5
|
import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
|
|
6
6
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver, mapAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
7
7
|
import { buildChannelConfigSchema, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
8
8
|
import { defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
|
-
import { buildOpenGroupPolicyRestrictSendersWarning, buildOpenGroupPolicyWarning, createOpenProviderGroupPolicyWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
9
|
+
import { buildOpenGroupPolicyRestrictSendersWarning, buildOpenGroupPolicyWarning, createConditionalWarningCollector, createOpenProviderGroupPolicyWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
10
10
|
import { createAttachedChannelResultAdapter, createEmptyChannelResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
11
11
|
import { buildTokenChannelStatusSummary } from "openclaw/plugin-sdk/channel-status";
|
|
12
12
|
import { createStaticReplyToModeResolver } from "openclaw/plugin-sdk/conversation-runtime";
|
|
@@ -16,15 +16,15 @@ import { sendPayloadWithChunkedTextAndMedia } from "openclaw/plugin-sdk/reply-pa
|
|
|
16
16
|
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState, standardDmPolicyOpenIssue } from "openclaw/plugin-sdk/status-helpers";
|
|
17
17
|
import { chunkTextForOutbound, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
18
18
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
|
-
import { buildChannelOutboundSessionRoute, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/core";
|
|
20
19
|
import { jsonResult, readStringParam } from "openclaw/plugin-sdk/channel-actions";
|
|
21
20
|
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
22
21
|
import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
23
22
|
import { AllowFromListSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildMultiAccountChannelSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
24
23
|
import { z } from "zod";
|
|
24
|
+
import { buildChannelOutboundSessionRoute, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/core";
|
|
25
25
|
import { coerceStatusIssueAccountId, readStatusIssueFields } from "openclaw/plugin-sdk/extension-shared";
|
|
26
26
|
//#region extensions/zalo/src/actions.ts
|
|
27
|
-
const loadZaloActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-
|
|
27
|
+
const loadZaloActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-DUY9_6Ss.js"), "zaloActionsRuntime");
|
|
28
28
|
const providerId = "zalo";
|
|
29
29
|
const ZALO_ACTIONS = /* @__PURE__ */ new Set(["send"]);
|
|
30
30
|
function listEnabledAccounts(cfg, accountId) {
|
|
@@ -92,6 +92,7 @@ const zaloApprovalAuth = createChannelApprovalAuth({
|
|
|
92
92
|
const ZaloConfigSchema = buildMultiAccountChannelSchema(z.object({
|
|
93
93
|
name: z.string().optional(),
|
|
94
94
|
enabled: z.boolean().optional(),
|
|
95
|
+
configWrites: z.boolean().optional(),
|
|
95
96
|
markdown: MarkdownConfigSchema,
|
|
96
97
|
botToken: buildSecretInputSchema().optional(),
|
|
97
98
|
tokenFile: z.string().optional(),
|
|
@@ -179,8 +180,8 @@ function looksLikeZaloChatId(raw, normalized) {
|
|
|
179
180
|
const target = normalizeZaloMessagingTarget(normalized ?? raw);
|
|
180
181
|
return Boolean(target);
|
|
181
182
|
}
|
|
182
|
-
const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
183
|
-
const zaloSetupWizard = createZaloSetupWizardProxy(async () => (await import("./setup-surface-
|
|
183
|
+
const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-UD-M7eDb.js"));
|
|
184
|
+
const zaloSetupWizard = createZaloSetupWizardProxy(async () => (await import("./setup-surface-CIpp_MDf.js").then((n) => n.t)).zaloSetupWizard);
|
|
184
185
|
const zaloTextChunkLimit = 2e3;
|
|
185
186
|
async function sendZaloDelivery(ctx) {
|
|
186
187
|
const result = await (await loadZaloChannelRuntime()).sendZaloText({
|
|
@@ -259,11 +260,16 @@ const collectZaloSecurityWarnings = createOpenProviderGroupPolicyWarningCollecto
|
|
|
259
260
|
})];
|
|
260
261
|
}
|
|
261
262
|
});
|
|
263
|
+
const collectZaloOpenGroupFindings = createConditionalWarningCollector.findings({
|
|
264
|
+
collectWarnings: collectZaloSecurityWarnings,
|
|
265
|
+
checkId: "channels.zalo.groups.open",
|
|
266
|
+
severity: "critical",
|
|
267
|
+
title: "Zalo security warning"
|
|
268
|
+
});
|
|
262
269
|
const zaloPlugin = createChatChannelPlugin({
|
|
263
270
|
base: {
|
|
264
271
|
id: "zalo",
|
|
265
272
|
meta,
|
|
266
|
-
setup: zaloSetupAdapter,
|
|
267
273
|
setupContract: zaloSetupContract,
|
|
268
274
|
setupWizard: zaloSetupWizard,
|
|
269
275
|
capabilities: {
|
|
@@ -301,6 +307,10 @@ const zaloPlugin = createChatChannelPlugin({
|
|
|
301
307
|
messaging: {
|
|
302
308
|
targetPrefixes: ["zalo", "zl"],
|
|
303
309
|
normalizeTarget: normalizeZaloMessagingTarget,
|
|
310
|
+
inferTargetChatType: ({ to }) => {
|
|
311
|
+
const target = normalizeZaloMessagingTarget(to);
|
|
312
|
+
return target ? /^group:/i.test(target) ? "group" : "direct" : void 0;
|
|
313
|
+
},
|
|
304
314
|
resolveOutboundSessionRoute: (params) => resolveZaloOutboundSessionRoute(params),
|
|
305
315
|
targetResolver: {
|
|
306
316
|
looksLikeId: looksLikeZaloChatId,
|
|
@@ -345,7 +355,7 @@ const zaloPlugin = createChatChannelPlugin({
|
|
|
345
355
|
},
|
|
346
356
|
security: {
|
|
347
357
|
resolveDmPolicy: resolveZaloDmPolicy,
|
|
348
|
-
collectWarnings:
|
|
358
|
+
collectWarnings: collectZaloOpenGroupFindings
|
|
349
359
|
},
|
|
350
360
|
pairing: { text: {
|
|
351
361
|
idLabel: "zaloUserId",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as zaloPlugin } from "./channel-
|
|
1
|
+
import { t as zaloPlugin } from "./channel-Vdxu1Y3k.js";
|
|
2
2
|
export { zaloPlugin };
|
|
@@ -1,58 +1,41 @@
|
|
|
1
|
-
import { m as normalizeSecretInputString } from "./setup-core-
|
|
2
|
-
import { i as PAIRING_APPROVED_MESSAGE } from "./runtime-api-
|
|
3
|
-
import { a as getMe, n as resolveZaloProxyFetch, r as ZaloApiError, t as sendMessageZalo } from "./send-
|
|
1
|
+
import { m as normalizeSecretInputString } from "./setup-core-CcCJ1E26.js";
|
|
2
|
+
import { i as PAIRING_APPROVED_MESSAGE } from "./runtime-api-BNim5FCa.js";
|
|
3
|
+
import { a as getMe, n as resolveZaloProxyFetch, r as ZaloApiError, t as sendMessageZalo } from "./send-DVMIplpy.js";
|
|
4
4
|
import { createAccountStatusSink } from "openclaw/plugin-sdk/channel-outbound";
|
|
5
|
+
import { runChannelProbe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
5
6
|
//#region extensions/zalo/src/probe.ts
|
|
7
|
+
function formatZaloProbeError(error, timeoutMs) {
|
|
8
|
+
if (error instanceof ZaloApiError) return error.description ?? error.message;
|
|
9
|
+
if (error instanceof Error) return error.name === "AbortError" ? `Request timed out after ${timeoutMs}ms` : error.message;
|
|
10
|
+
return String(error);
|
|
11
|
+
}
|
|
6
12
|
async function probeZalo(token, timeoutMs = 5e3, fetcher) {
|
|
7
13
|
if (!token?.trim()) return {
|
|
8
14
|
ok: false,
|
|
9
15
|
error: "No token provided",
|
|
10
16
|
elapsedMs: 0
|
|
11
17
|
};
|
|
12
|
-
|
|
13
|
-
try {
|
|
18
|
+
return await runChannelProbe(void 0, async ({ elapsedMs }) => {
|
|
14
19
|
const response = await getMe(token.trim(), timeoutMs, fetcher);
|
|
15
|
-
const elapsedMs = Date.now() - startTime;
|
|
16
20
|
if (response.ok && response.result) return {
|
|
17
21
|
ok: true,
|
|
18
22
|
bot: response.result,
|
|
19
|
-
elapsedMs
|
|
23
|
+
elapsedMs: elapsedMs()
|
|
20
24
|
};
|
|
21
25
|
return {
|
|
22
26
|
ok: false,
|
|
23
27
|
error: "Invalid response from Zalo API",
|
|
24
|
-
elapsedMs
|
|
25
|
-
};
|
|
26
|
-
} catch (err) {
|
|
27
|
-
const elapsedMs = Date.now() - startTime;
|
|
28
|
-
if (err instanceof ZaloApiError) return {
|
|
29
|
-
ok: false,
|
|
30
|
-
error: err.description ?? err.message,
|
|
31
|
-
elapsedMs
|
|
28
|
+
elapsedMs: elapsedMs()
|
|
32
29
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
elapsedMs
|
|
38
|
-
};
|
|
39
|
-
return {
|
|
40
|
-
ok: false,
|
|
41
|
-
error: err.message,
|
|
42
|
-
elapsedMs
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
ok: false,
|
|
47
|
-
error: String(err),
|
|
48
|
-
elapsedMs
|
|
49
|
-
};
|
|
50
|
-
}
|
|
30
|
+
}, (error) => ({
|
|
31
|
+
ok: false,
|
|
32
|
+
error: formatZaloProbeError(error, timeoutMs)
|
|
33
|
+
}));
|
|
51
34
|
}
|
|
52
35
|
//#endregion
|
|
53
36
|
//#region extensions/zalo/src/channel.runtime.ts
|
|
54
37
|
async function notifyZaloPairingApproval(params) {
|
|
55
|
-
const { resolveZaloAccount } = await import("./setup-core-
|
|
38
|
+
const { resolveZaloAccount } = await import("./setup-core-CcCJ1E26.js").then((n) => n.s);
|
|
56
39
|
const account = resolveZaloAccount({ cfg: params.cfg });
|
|
57
40
|
if (!account.token) throw new Error("Zalo token not configured");
|
|
58
41
|
await sendMessageZalo(params.id, PAIRING_APPROVED_MESSAGE, { token: account.token });
|
|
@@ -86,7 +69,7 @@ async function startZaloGatewayAccount(ctx) {
|
|
|
86
69
|
setStatus: ctx.setStatus
|
|
87
70
|
});
|
|
88
71
|
ctx.log?.info(`[${account.accountId}] starting provider${zaloBotLabel} mode=${mode}`);
|
|
89
|
-
const { monitorZaloProvider } = await import("./monitor-
|
|
72
|
+
const { monitorZaloProvider } = await import("./monitor-JdVVhnCm.js");
|
|
90
73
|
return monitorZaloProvider({
|
|
91
74
|
token,
|
|
92
75
|
account,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { n as resolveZaloRuntimeGroupPolicy, t as normalizeZaloAllowEntry } from "./group-access-8qHRzDHx.js";
|
|
2
|
-
import { t as getZaloRuntime } from "./runtime-api-
|
|
3
|
-
import { c as sendChatAction, d as setWebhook, f as ZALO_OUTBOUND_MEDIA_TTL_MS, i as deleteWebhook, l as sendMessage, n as resolveZaloProxyFetch, o as getUpdates, r as ZaloApiError, s as getWebhookInfo, u as sendPhoto } from "./send-
|
|
2
|
+
import { t as getZaloRuntime } from "./runtime-api-BNim5FCa.js";
|
|
3
|
+
import { c as sendChatAction, d as setWebhook, f as ZALO_OUTBOUND_MEDIA_TTL_MS, i as deleteWebhook, l as sendMessage, n as resolveZaloProxyFetch, o as getUpdates, r as ZaloApiError, s as getWebhookInfo, u as sendPhoto } from "./send-DVMIplpy.js";
|
|
4
|
+
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
|
|
4
5
|
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
|
|
5
6
|
import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
6
7
|
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
8
|
import { resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
8
9
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
9
10
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
|
|
10
|
-
import { registerPluginHttpRoute, resolveWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
|
|
11
|
+
import { canonicalizeWebhookRouteKey, registerPluginHttpRoute, resolveWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
|
|
11
12
|
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
12
|
-
import { formatInboundMediaUnavailableText, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
|
|
13
|
+
import { createChannelPartialDeliveryError, formatInboundMediaUnavailableText, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
|
|
13
14
|
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
15
|
+
import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
14
16
|
import { sleepWithAbort, waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
|
|
15
17
|
import { createHostedOutboundMediaStore } from "openclaw/plugin-sdk/outbound-media";
|
|
16
18
|
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
@@ -115,35 +117,44 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
|
115
117
|
res.end("Expired");
|
|
116
118
|
return true;
|
|
117
119
|
}
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
120
|
+
const metadata = await store.readMetadata(id, now);
|
|
121
|
+
if (!metadata || metadata.routePath !== routePath) {
|
|
120
122
|
res.statusCode = 404;
|
|
121
123
|
res.end("Not Found");
|
|
122
124
|
return true;
|
|
123
125
|
}
|
|
124
|
-
const expiresAt = asDateTimestampMs(
|
|
126
|
+
const expiresAt = asDateTimestampMs(metadata.expiresAt);
|
|
125
127
|
if (expiresAt === void 0 || expiresAt <= now) {
|
|
126
128
|
await store.delete(id);
|
|
127
129
|
res.statusCode = 410;
|
|
128
130
|
res.end("Expired");
|
|
129
131
|
return true;
|
|
130
132
|
}
|
|
131
|
-
|
|
133
|
+
const token = url.searchParams.get("token");
|
|
134
|
+
if (!safeEqualSecret(token, metadata.token)) {
|
|
132
135
|
res.statusCode = 401;
|
|
133
136
|
res.end("Unauthorized");
|
|
134
137
|
return true;
|
|
135
138
|
}
|
|
136
|
-
|
|
139
|
+
let servedMetadata = metadata;
|
|
140
|
+
let body;
|
|
141
|
+
if (method === "GET") {
|
|
142
|
+
const entry = await store.read(id, now);
|
|
143
|
+
if (!entry || entry.metadata.routePath !== routePath || !safeEqualSecret(token, entry.metadata.token)) {
|
|
144
|
+
res.statusCode = 404;
|
|
145
|
+
res.end("Not Found");
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
servedMetadata = entry.metadata;
|
|
149
|
+
body = entry.buffer;
|
|
150
|
+
}
|
|
151
|
+
if (servedMetadata.contentType) res.setHeader("Content-Type", servedMetadata.contentType);
|
|
137
152
|
res.setHeader("Cache-Control", "no-store");
|
|
138
153
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
139
|
-
res.setHeader("Content-Length", String(
|
|
140
|
-
if (method === "HEAD") {
|
|
141
|
-
res.statusCode = 200;
|
|
142
|
-
res.end();
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
154
|
+
res.setHeader("Content-Length", String(servedMetadata.byteLength));
|
|
145
155
|
res.statusCode = 200;
|
|
146
|
-
res.end(
|
|
156
|
+
res.end(body);
|
|
157
|
+
if (method === "HEAD") return true;
|
|
147
158
|
await store.delete(id);
|
|
148
159
|
return true;
|
|
149
160
|
}
|
|
@@ -163,31 +174,23 @@ function resolveZaloTimestampMs(date) {
|
|
|
163
174
|
if (!date) return;
|
|
164
175
|
return date >= UNIX_MILLISECONDS_THRESHOLD ? date : date * 1e3;
|
|
165
176
|
}
|
|
166
|
-
const loadZaloWebhookRuntime = createLazyRuntimeNamedExport(() => import("./monitor.webhook-
|
|
167
|
-
const loadZaloWebhookIngressRuntime = createLazyRuntimeNamedExport(() => import("./webhook-spool-
|
|
177
|
+
const loadZaloWebhookRuntime = createLazyRuntimeNamedExport(() => import("./monitor.webhook-cl1sV6j0.js"), "zaloWebhookRuntime");
|
|
178
|
+
const loadZaloWebhookIngressRuntime = createLazyRuntimeNamedExport(() => import("./webhook-spool-Bdnu4GjY.js"), "zaloWebhookIngressRuntime");
|
|
168
179
|
const loadZaloWebhookModule = createLazyRuntimeModule(async () => ({
|
|
169
180
|
...await loadZaloWebhookRuntime(),
|
|
170
181
|
...await loadZaloWebhookIngressRuntime()
|
|
171
182
|
}));
|
|
172
|
-
function releaseSharedHostedMediaRouteRef(routePath) {
|
|
173
|
-
const current = hostedMediaRouteRefs.get(routePath);
|
|
174
|
-
if (!current) return;
|
|
175
|
-
if (current.count > 1) {
|
|
176
|
-
current.count -= 1;
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
hostedMediaRouteRefs.delete(routePath);
|
|
180
|
-
for (const unregisterHandle of current.unregisters) unregisterHandle();
|
|
181
|
-
}
|
|
182
183
|
function registerSharedHostedMediaRoute(params) {
|
|
184
|
+
const routeKey = canonicalizeWebhookRouteKey(params.path);
|
|
183
185
|
const unregister = registerPluginHttpRoute({
|
|
184
186
|
auth: "plugin",
|
|
185
187
|
match: "prefix",
|
|
186
188
|
path: params.path,
|
|
187
189
|
pluginId: "zalo",
|
|
188
190
|
source: "zalo-hosted-media",
|
|
189
|
-
accountId: params.accountId,
|
|
190
191
|
log: params.log,
|
|
192
|
+
reuseExistingSameOwner: true,
|
|
193
|
+
throwOnFailure: true,
|
|
191
194
|
handler: async (req, res) => {
|
|
192
195
|
if (!await tryHandleHostedZaloMediaRequest(req, res) && !res.headersSent) {
|
|
193
196
|
res.statusCode = 404;
|
|
@@ -196,17 +199,23 @@ function registerSharedHostedMediaRoute(params) {
|
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
});
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
202
|
+
const acquired = hostedMediaRouteRefs.get(routeKey) ?? {
|
|
203
|
+
count: 0,
|
|
204
|
+
unregisters: []
|
|
205
|
+
};
|
|
206
|
+
if (acquired.count === 0) hostedMediaRouteRefs.set(routeKey, acquired);
|
|
207
|
+
acquired.count += 1;
|
|
208
|
+
acquired.unregisters.push(unregister);
|
|
209
|
+
let released = false;
|
|
210
|
+
return () => {
|
|
211
|
+
if (released) return;
|
|
212
|
+
released = true;
|
|
213
|
+
if (hostedMediaRouteRefs.get(routeKey) !== acquired) return;
|
|
214
|
+
acquired.count -= 1;
|
|
215
|
+
if (acquired.count > 0) return;
|
|
216
|
+
hostedMediaRouteRefs.delete(routeKey);
|
|
217
|
+
for (const unregisterHandle of acquired.unregisters) unregisterHandle();
|
|
218
|
+
};
|
|
210
219
|
}
|
|
211
220
|
function formatZaloError(error) {
|
|
212
221
|
if (error instanceof Error) return error.stack ?? `${error.name}: ${error.message}`;
|
|
@@ -253,6 +262,7 @@ function startPollingLoop(params) {
|
|
|
253
262
|
try {
|
|
254
263
|
const response = await getUpdates(token, { timeout: pollTimeout }, fetcher);
|
|
255
264
|
if (isStopped() || abortSignal.aborted) return;
|
|
265
|
+
if (response.ok) statusSink?.(channelReadyPatch());
|
|
256
266
|
if (response.ok && response.result) {
|
|
257
267
|
statusSink?.({ lastInboundAt: Date.now() });
|
|
258
268
|
await processUpdate({
|
|
@@ -262,7 +272,13 @@ function startPollingLoop(params) {
|
|
|
262
272
|
}
|
|
263
273
|
} catch (err) {
|
|
264
274
|
if (err instanceof ZaloApiError && err.isPollingTimeout) {} else if (!isStopped() && !abortSignal.aborted) {
|
|
265
|
-
|
|
275
|
+
const error = formatZaloError(err);
|
|
276
|
+
runtime.error?.(`[${account.accountId}] Zalo polling error: ${error}`);
|
|
277
|
+
statusSink?.({
|
|
278
|
+
connected: false,
|
|
279
|
+
lifecycle: "recovering",
|
|
280
|
+
lastError: error
|
|
281
|
+
});
|
|
266
282
|
await sleepWithAbort(5e3, abortSignal).catch(() => void 0);
|
|
267
283
|
}
|
|
268
284
|
}
|
|
@@ -385,7 +401,7 @@ async function authorizeZaloMessage(params) {
|
|
|
385
401
|
defaultGroupPolicy
|
|
386
402
|
});
|
|
387
403
|
const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, config);
|
|
388
|
-
const
|
|
404
|
+
const resolveChannelIngress = async (contextBinding) => await resolveStableChannelMessageIngress({
|
|
389
405
|
channelId: "zalo",
|
|
390
406
|
accountId: account.accountId,
|
|
391
407
|
identity: {
|
|
@@ -401,6 +417,7 @@ async function authorizeZaloMessage(params) {
|
|
|
401
417
|
kind: isGroup ? "group" : "direct",
|
|
402
418
|
id: chatId
|
|
403
419
|
},
|
|
420
|
+
contextBinding,
|
|
404
421
|
providerMissingFallbackApplied,
|
|
405
422
|
dmPolicy,
|
|
406
423
|
groupPolicy,
|
|
@@ -409,6 +426,7 @@ async function authorizeZaloMessage(params) {
|
|
|
409
426
|
groupAllowFrom: normalizeStringEntries(account.config.groupAllowFrom),
|
|
410
427
|
command: shouldComputeAuth ? {} : void 0
|
|
411
428
|
});
|
|
429
|
+
const access = await resolveChannelIngress();
|
|
412
430
|
const senderAccess = access.senderAccess;
|
|
413
431
|
if (isGroup) {
|
|
414
432
|
warnMissingProviderGroupPolicyFallbackOnce({
|
|
@@ -451,6 +469,8 @@ async function authorizeZaloMessage(params) {
|
|
|
451
469
|
return;
|
|
452
470
|
}
|
|
453
471
|
return {
|
|
472
|
+
channelIngress: access,
|
|
473
|
+
resolveChannelIngress,
|
|
454
474
|
chatId,
|
|
455
475
|
commandAuthorized: access.commandAccess.requested ? access.commandAccess.authorized : void 0,
|
|
456
476
|
isGroup,
|
|
@@ -468,7 +488,7 @@ async function processMessageWithPipeline(params) {
|
|
|
468
488
|
mediaType
|
|
469
489
|
});
|
|
470
490
|
if (!authorization) return;
|
|
471
|
-
const { isGroup, chatId, senderId, senderName, rawBody
|
|
491
|
+
const { isGroup, chatId, senderId, senderName, rawBody } = authorization;
|
|
472
492
|
const agentBody = agentBodyOverride ?? rawBody;
|
|
473
493
|
const { route, buildEnvelope } = resolveChannelInboundRouteEnvelope({
|
|
474
494
|
cfg: config,
|
|
@@ -479,6 +499,17 @@ async function processMessageWithPipeline(params) {
|
|
|
479
499
|
id: chatId
|
|
480
500
|
}
|
|
481
501
|
});
|
|
502
|
+
const channelIngress = await authorization.resolveChannelIngress({
|
|
503
|
+
agentId: route.agentId,
|
|
504
|
+
sessionKey: route.sessionKey,
|
|
505
|
+
messageId: message_id,
|
|
506
|
+
inboundEventKind: "user_request"
|
|
507
|
+
});
|
|
508
|
+
if (!channelIngress.senderAccess.allowed) {
|
|
509
|
+
logVerbose(core, runtime, `zalo: authorization changed before dispatch for ${senderId}`);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
const commandAuthorized = channelIngress.commandAccess.requested ? channelIngress.commandAccess.authorized : void 0;
|
|
482
513
|
if (isGroup && core.channel.commands.isControlCommandMessage(rawBody, config) && commandAuthorized !== true) {
|
|
483
514
|
logVerbose(core, runtime, `zalo: drop control command from unauthorized sender ${senderId}`);
|
|
484
515
|
return;
|
|
@@ -492,6 +523,7 @@ async function processMessageWithPipeline(params) {
|
|
|
492
523
|
body: agentBody
|
|
493
524
|
});
|
|
494
525
|
const ctxPayload = core.channel.inbound.buildContext({
|
|
526
|
+
channelIngress,
|
|
495
527
|
channel: "zalo",
|
|
496
528
|
accountId: route.accountId,
|
|
497
529
|
messageId: message_id,
|
|
@@ -561,7 +593,6 @@ async function processMessageWithPipeline(params) {
|
|
|
561
593
|
payload,
|
|
562
594
|
token,
|
|
563
595
|
chatId,
|
|
564
|
-
runtime,
|
|
565
596
|
core,
|
|
566
597
|
config,
|
|
567
598
|
webhookUrl: params.webhookUrl,
|
|
@@ -575,8 +606,8 @@ async function processMessageWithPipeline(params) {
|
|
|
575
606
|
tableMode: "off"
|
|
576
607
|
});
|
|
577
608
|
},
|
|
578
|
-
onDelivered: () => {
|
|
579
|
-
statusSink?.({ lastOutboundAt: Date.now() });
|
|
609
|
+
onDelivered: (_payload, _info, result) => {
|
|
610
|
+
if (result?.visibleReplySent !== false) statusSink?.({ lastOutboundAt: Date.now() });
|
|
580
611
|
},
|
|
581
612
|
onError: (err, info) => {
|
|
582
613
|
runtime.error?.(`[${account.accountId}] Zalo ${info.kind} reply failed: ${String(err)}`);
|
|
@@ -606,49 +637,64 @@ async function processMessageWithPipeline(params) {
|
|
|
606
637
|
});
|
|
607
638
|
}
|
|
608
639
|
async function deliverZaloReply(params) {
|
|
609
|
-
const { payload, token, chatId,
|
|
640
|
+
const { payload, token, chatId, core, config, webhookUrl, webhookPath, proxyUrl, mediaMaxBytes, canHostMedia, accountId, statusSink, fetcher } = params;
|
|
610
641
|
const tableMode = params.tableMode ?? "code";
|
|
611
642
|
const reply = resolveSendableOutboundReplyParts(payload, { text: core.channel.text.convertMarkdownTables(payload.text ?? "", tableMode) });
|
|
612
643
|
const chunkMode = core.channel.text.resolveChunkMode(config, "zalo", accountId);
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
644
|
+
const acceptedMessageIds = [];
|
|
645
|
+
let visibleReplySent = false;
|
|
646
|
+
const recordAcceptedSend = (result) => {
|
|
647
|
+
const messageId = result.result?.message_id;
|
|
648
|
+
if (messageId) acceptedMessageIds.push(messageId);
|
|
649
|
+
visibleReplySent = true;
|
|
650
|
+
statusSink?.({ lastOutboundAt: Date.now() });
|
|
651
|
+
};
|
|
652
|
+
try {
|
|
653
|
+
await deliverTextOrMediaReply({
|
|
654
|
+
payload,
|
|
655
|
+
text: reply.text,
|
|
656
|
+
chunkText: (value) => core.channel.text.chunkMarkdownTextWithMode(value, ZALO_TEXT_LIMIT, chunkMode),
|
|
657
|
+
sendText: async (chunk) => {
|
|
658
|
+
recordAcceptedSend(await sendMessage(token, {
|
|
620
659
|
chat_id: chatId,
|
|
621
660
|
text: chunk
|
|
622
|
-
}, fetcher);
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
661
|
+
}, fetcher));
|
|
662
|
+
},
|
|
663
|
+
sendMedia: async ({ mediaUrl, caption }) => {
|
|
664
|
+
const sendableMediaUrl = canHostMedia && webhookUrl && webhookPath ? await prepareHostedZaloMediaUrl({
|
|
665
|
+
mediaUrl,
|
|
666
|
+
webhookUrl,
|
|
667
|
+
webhookPath,
|
|
668
|
+
maxBytes: mediaMaxBytes,
|
|
669
|
+
proxyUrl
|
|
670
|
+
}) : mediaUrl;
|
|
671
|
+
recordAcceptedSend(await sendPhoto(token, {
|
|
672
|
+
chat_id: chatId,
|
|
673
|
+
photo: sendableMediaUrl,
|
|
674
|
+
caption
|
|
675
|
+
}, fetcher));
|
|
626
676
|
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
},
|
|
643
|
-
onMediaError: (error) => {
|
|
644
|
-
runtime.error?.(`Zalo photo send failed: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
|
|
645
|
-
}
|
|
646
|
-
});
|
|
677
|
+
});
|
|
678
|
+
} catch (error) {
|
|
679
|
+
if (!visibleReplySent) throw error;
|
|
680
|
+
throw createChannelPartialDeliveryError(error, {
|
|
681
|
+
messageIds: acceptedMessageIds,
|
|
682
|
+
receipt: createMessageReceiptFromOutboundResults({
|
|
683
|
+
results: acceptedMessageIds.map((messageId) => ({
|
|
684
|
+
channel: "zalo",
|
|
685
|
+
messageId
|
|
686
|
+
})),
|
|
687
|
+
kind: reply.hasMedia ? "media" : "text"
|
|
688
|
+
}),
|
|
689
|
+
visibleReplySent: true
|
|
690
|
+
});
|
|
691
|
+
}
|
|
647
692
|
}
|
|
648
693
|
async function monitorZaloProvider(options) {
|
|
649
694
|
const { token, account, config, runtime, abortSignal, useWebhook, webhookUrl, webhookSecret, webhookPath, statusSink, fetcher: fetcherOverride } = options;
|
|
650
695
|
const core = getZaloRuntime();
|
|
651
|
-
const
|
|
696
|
+
const configuredMediaMaxMb = account.config.mediaMaxMb;
|
|
697
|
+
const effectiveMediaMaxMb = typeof configuredMediaMaxMb === "number" && configuredMediaMaxMb > 0 ? configuredMediaMaxMb : DEFAULT_MEDIA_MAX_MB;
|
|
652
698
|
const fetcher = fetcherOverride ?? resolveZaloProxyFetch(account.config.proxy);
|
|
653
699
|
const mode = useWebhook ? "webhook" : "polling";
|
|
654
700
|
const effectiveWebhookUrl = normalizeWebhookUrl(webhookUrl ?? account.config.webhookUrl);
|
|
@@ -684,7 +730,6 @@ async function monitorZaloProvider(options) {
|
|
|
684
730
|
if (hostedMediaRoutePath) {
|
|
685
731
|
const unregisterHostedMediaRoute = registerSharedHostedMediaRoute({
|
|
686
732
|
path: hostedMediaRoutePath,
|
|
687
|
-
accountId: account.accountId,
|
|
688
733
|
log: runtime.log
|
|
689
734
|
});
|
|
690
735
|
stopHandlers.push(unregisterHostedMediaRoute);
|
|
@@ -735,6 +780,7 @@ async function monitorZaloProvider(options) {
|
|
|
735
780
|
source: "zalo-webhook",
|
|
736
781
|
accountId: account.accountId,
|
|
737
782
|
log: runtime.log,
|
|
783
|
+
throwOnFailure: true,
|
|
738
784
|
handler: async (req, res) => {
|
|
739
785
|
if (!await handleZaloWebhookRequest(req, res) && !res.headersSent) {
|
|
740
786
|
res.statusCode = 404;
|
|
@@ -748,6 +794,7 @@ async function monitorZaloProvider(options) {
|
|
|
748
794
|
url: effectiveWebhookUrl,
|
|
749
795
|
secret_token: webhookSecret
|
|
750
796
|
}, fetcher);
|
|
797
|
+
statusSink?.(channelReadyPatch());
|
|
751
798
|
let webhookCleanupPromise;
|
|
752
799
|
cleanupWebhook = async () => {
|
|
753
800
|
if (!webhookCleanupPromise) webhookCleanupPromise = (async () => {
|
|
@@ -800,7 +847,13 @@ async function monitorZaloProvider(options) {
|
|
|
800
847
|
});
|
|
801
848
|
await waitForAbortSignal(abortSignal);
|
|
802
849
|
} catch (err) {
|
|
803
|
-
|
|
850
|
+
const error = formatZaloError(err);
|
|
851
|
+
runtime.error?.(`[${account.accountId}] Zalo provider startup failed mode=${mode}: ${error}`);
|
|
852
|
+
statusSink?.({
|
|
853
|
+
connected: false,
|
|
854
|
+
lifecycle: "recovering",
|
|
855
|
+
lastError: error
|
|
856
|
+
});
|
|
804
857
|
throw err;
|
|
805
858
|
} finally {
|
|
806
859
|
abortSignal.removeEventListener("abort", stopOnAbort);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as registerWebhookTargetWithPluginRoute, G as resolveWebhookTargetWithAuthOrRejectSync, V as resolveClientIp, Z as withResolvedWebhookRequestPipeline, a as WEBHOOK_ANOMALY_COUNTER_DEFAULTS, b as createFixedWindowRateLimiter, l as applyBasicWebhookRequestGuards, o as WEBHOOK_RATE_LIMIT_DEFAULTS, x as createWebhookAnomalyTracker, z as registerWebhookTarget } from "./runtime-api-
|
|
2
|
-
import { ZaloWebhookPayloadError } from "./webhook-spool-
|
|
1
|
+
import { B as registerWebhookTargetWithPluginRoute, G as resolveWebhookTargetWithAuthOrRejectSync, V as resolveClientIp, Z as withResolvedWebhookRequestPipeline, a as WEBHOOK_ANOMALY_COUNTER_DEFAULTS, b as createFixedWindowRateLimiter, l as applyBasicWebhookRequestGuards, o as WEBHOOK_RATE_LIMIT_DEFAULTS, x as createWebhookAnomalyTracker, z as registerWebhookTarget } from "./runtime-api-BNim5FCa.js";
|
|
2
|
+
import { ZaloWebhookPayloadError } from "./webhook-spool-Bdnu4GjY.js";
|
|
3
3
|
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
4
4
|
import { readWebhookBodyOrReject } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
5
5
|
//#region extensions/zalo/src/monitor.webhook.ts
|
|
@@ -20,9 +20,6 @@ function clearZaloWebhookSecurityStateForTest() {
|
|
|
20
20
|
webhookRateLimiter.clear();
|
|
21
21
|
webhookAnomalyTracker.clear();
|
|
22
22
|
}
|
|
23
|
-
function getZaloWebhookRateLimitStateSizeForTest() {
|
|
24
|
-
return webhookRateLimiter.size();
|
|
25
|
-
}
|
|
26
23
|
function getZaloWebhookStatusCounterSizeForTest() {
|
|
27
24
|
return webhookAnomalyTracker.size();
|
|
28
25
|
}
|
|
@@ -119,7 +116,6 @@ async function handleZaloWebhookRequest(req, res) {
|
|
|
119
116
|
}
|
|
120
117
|
const zaloWebhookRuntime = {
|
|
121
118
|
clearZaloWebhookSecurityStateForTest,
|
|
122
|
-
getZaloWebhookRateLimitStateSizeForTest,
|
|
123
119
|
getZaloWebhookStatusCounterSizeForTest,
|
|
124
120
|
handleZaloWebhookRequest,
|
|
125
121
|
registerZaloWebhookTarget
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as mergeAllowFromEntries, B as registerWebhookTargetWithPluginRoute, C as formatAllowFromLowercase, D as isNumericTargetId, E as isNormalizedSenderAllowed, F as promptSingleChannelSecretInput, G as resolveWebhookTargetWithAuthOrRejectSync, H as resolveDefaultGroupPolicy, I as readJsonWebhookBodyOrReject, J as setTopLevelChannelDmPolicyWithAllowFrom, K as runSingleChannelSecretStep, L as readStringParam, M as normalizeAccountId, N as normalizeResolvedSecretInputString, O as jsonResult, P as normalizeSecretInputString, R as registerPluginHttpRoute, S as deliverTextOrMediaReply, T as hasConfiguredSecretInput, U as resolveOpenProviderRuntimeGroupPolicy, V as resolveClientIp, W as resolveWebhookPath, X as warnMissingProviderGroupPolicyFallbackOnce, Y as waitForAbortSignal, Z as withResolvedWebhookRequestPipeline, _ as createChannelMessageReplyPipeline, a as WEBHOOK_ANOMALY_COUNTER_DEFAULTS, b as createFixedWindowRateLimiter, c as applyAccountNameToChannelSection, d as buildBaseAccountStatusSnapshot, f as buildChannelConfigSchema, g as chunkTextForOutbound, h as buildTokenChannelStatusSummary, i as PAIRING_APPROVED_MESSAGE, j as migrateBaseNameToDefaultAccount, k as logTypingFailure, l as applyBasicWebhookRequestGuards, m as buildSingleChannelSecretPromptState, n as setZaloRuntime, o as WEBHOOK_RATE_LIMIT_DEFAULTS, p as buildSecretInputSchema, q as sendPayloadWithChunkedTextAndMedia, r as DEFAULT_ACCOUNT_ID, s as addWildcardAllowFrom, u as applySetupAccountConfigPatch, v as createChannelPairingController, w as formatPairingApproveHint, x as createWebhookAnomalyTracker, y as createDedupeCache, z as registerWebhookTarget } from "./runtime-api-
|
|
1
|
+
import { A as mergeAllowFromEntries, B as registerWebhookTargetWithPluginRoute, C as formatAllowFromLowercase, D as isNumericTargetId, E as isNormalizedSenderAllowed, F as promptSingleChannelSecretInput, G as resolveWebhookTargetWithAuthOrRejectSync, H as resolveDefaultGroupPolicy, I as readJsonWebhookBodyOrReject, J as setTopLevelChannelDmPolicyWithAllowFrom, K as runSingleChannelSecretStep, L as readStringParam, M as normalizeAccountId, N as normalizeResolvedSecretInputString, O as jsonResult, P as normalizeSecretInputString, R as registerPluginHttpRoute, S as deliverTextOrMediaReply, T as hasConfiguredSecretInput, U as resolveOpenProviderRuntimeGroupPolicy, V as resolveClientIp, W as resolveWebhookPath, X as warnMissingProviderGroupPolicyFallbackOnce, Y as waitForAbortSignal, Z as withResolvedWebhookRequestPipeline, _ as createChannelMessageReplyPipeline, a as WEBHOOK_ANOMALY_COUNTER_DEFAULTS, b as createFixedWindowRateLimiter, c as applyAccountNameToChannelSection, d as buildBaseAccountStatusSnapshot, f as buildChannelConfigSchema, g as chunkTextForOutbound, h as buildTokenChannelStatusSummary, i as PAIRING_APPROVED_MESSAGE, j as migrateBaseNameToDefaultAccount, k as logTypingFailure, l as applyBasicWebhookRequestGuards, m as buildSingleChannelSecretPromptState, n as setZaloRuntime, o as WEBHOOK_RATE_LIMIT_DEFAULTS, p as buildSecretInputSchema, q as sendPayloadWithChunkedTextAndMedia, r as DEFAULT_ACCOUNT_ID, s as addWildcardAllowFrom, u as applySetupAccountConfigPatch, v as createChannelPairingController, w as formatPairingApproveHint, x as createWebhookAnomalyTracker, y as createDedupeCache, z as registerWebhookTarget } from "./runtime-api-BNim5FCa.js";
|
|
2
2
|
export { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE, WEBHOOK_ANOMALY_COUNTER_DEFAULTS, WEBHOOK_RATE_LIMIT_DEFAULTS, addWildcardAllowFrom, applyAccountNameToChannelSection, applyBasicWebhookRequestGuards, applySetupAccountConfigPatch, buildBaseAccountStatusSnapshot, buildChannelConfigSchema, buildSecretInputSchema, buildSingleChannelSecretPromptState, buildTokenChannelStatusSummary, chunkTextForOutbound, createChannelMessageReplyPipeline, createChannelPairingController, createDedupeCache, createFixedWindowRateLimiter, createWebhookAnomalyTracker, deliverTextOrMediaReply, formatAllowFromLowercase, formatPairingApproveHint, hasConfiguredSecretInput, isNormalizedSenderAllowed, isNumericTargetId, jsonResult, logTypingFailure, mergeAllowFromEntries, migrateBaseNameToDefaultAccount, normalizeAccountId, normalizeResolvedSecretInputString, normalizeSecretInputString, promptSingleChannelSecretInput, readJsonWebhookBodyOrReject, readStringParam, registerPluginHttpRoute, registerWebhookTarget, registerWebhookTargetWithPluginRoute, resolveClientIp, resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, resolveWebhookPath, resolveWebhookTargetWithAuthOrRejectSync, runSingleChannelSecretStep, sendPayloadWithChunkedTextAndMedia, setTopLevelChannelDmPolicyWithAllowFrom, setZaloRuntime, waitForAbortSignal, warnMissingProviderGroupPolicyFallbackOnce, withResolvedWebhookRequestPipeline };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
1
|
+
import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty, normalizeSecretStringValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
2
|
//#region extensions/zalo/src/secret-contract.ts
|
|
3
3
|
const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
|
4
4
|
channelKey: "zalo",
|
|
@@ -17,7 +17,7 @@ function collectRuntimeConfigAssignments(params) {
|
|
|
17
17
|
defaults: params.defaults,
|
|
18
18
|
context: params.context,
|
|
19
19
|
topLevelActiveWithoutAccounts: true,
|
|
20
|
-
topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "botToken"),
|
|
20
|
+
topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "botToken") && !normalizeSecretStringValue(account.tokenFile),
|
|
21
21
|
accountActive: ({ enabled }) => enabled,
|
|
22
22
|
topInactiveReason: "no enabled Zalo surface inherits this top-level botToken.",
|
|
23
23
|
accountInactiveReason: "Zalo account is disabled."
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-
|
|
1
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-Cpsqe5Cv.js";
|
|
2
2
|
export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
|