@openclaw/zalo 2026.7.1 → 2026.7.2-beta.2
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 +1 -1
- package/dist/{channel-BOWhJVyl.js → channel-CBPOM3Pc.js} +43 -55
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-CEPgF8Zo.js → channel.runtime-BsZBukDW.js} +1 -1
- package/dist/{monitor-fgcJhAZL.js → monitor-DTi243P3.js} +12 -7
- package/dist/{monitor.webhook-AYcIUBBP.js → monitor.webhook-BFkM-Syx.js} +22 -24
- package/dist/{secret-contract-Bno_huZF.js → secret-contract-Bxvjh0Hq.js} +6 -47
- package/dist/secret-contract-api.js +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as zaloDmPolicy, r as zaloSetupAdapter, t as createZaloSetupWizardProxy } from "./setup-core-fwCh0QUi.js";
|
|
2
|
-
import { t as zaloPlugin } from "./channel-
|
|
2
|
+
import { t as zaloPlugin } from "./channel-CBPOM3Pc.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,5 +1,5 @@
|
|
|
1
1
|
import { c as listZaloAccountIds, f as buildSecretInputSchema, l as resolveDefaultZaloAccountId, r as zaloSetupAdapter, s as listEnabledZaloAccounts, t as createZaloSetupWizardProxy, u as resolveZaloAccount } from "./setup-core-fwCh0QUi.js";
|
|
2
|
-
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-
|
|
2
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Bxvjh0Hq.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";
|
|
@@ -7,25 +7,26 @@ import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createSco
|
|
|
7
7
|
import { buildChannelConfigSchema, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
8
8
|
import { defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
9
|
import { buildOpenGroupPolicyRestrictSendersWarning, buildOpenGroupPolicyWarning, createOpenProviderGroupPolicyWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
10
|
-
import {
|
|
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";
|
|
13
13
|
import { createChannelDirectoryAdapter, listResolvedDirectoryUserEntriesFromAllowFrom } from "openclaw/plugin-sdk/directory-runtime";
|
|
14
14
|
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
|
|
15
15
|
import { sendPayloadWithChunkedTextAndMedia } from "openclaw/plugin-sdk/reply-payload";
|
|
16
|
-
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
16
|
+
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState, standardDmPolicyOpenIssue } from "openclaw/plugin-sdk/status-helpers";
|
|
17
17
|
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
18
18
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
19
|
import { buildChannelOutboundSessionRoute, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/core";
|
|
20
20
|
import { jsonResult, readStringParam } from "openclaw/plugin-sdk/channel-actions";
|
|
21
21
|
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
|
|
22
|
-
import {
|
|
23
|
-
import { AllowFromListSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema,
|
|
22
|
+
import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
23
|
+
import { AllowFromListSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildMultiAccountChannelSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
24
24
|
import { z } from "zod";
|
|
25
25
|
import { coerceStatusIssueAccountId, readStatusIssueFields } from "openclaw/plugin-sdk/extension-shared";
|
|
26
26
|
//#region extensions/zalo/src/actions.ts
|
|
27
27
|
const loadZaloActionsRuntime = createLazyRuntimeNamedExport(() => import("./actions.runtime-OmfJFYZn.js"), "zaloActionsRuntime");
|
|
28
28
|
const providerId = "zalo";
|
|
29
|
+
const ZALO_ACTIONS = /* @__PURE__ */ new Set(["send"]);
|
|
29
30
|
function listEnabledAccounts(cfg, accountId) {
|
|
30
31
|
return (accountId ? [resolveZaloAccount({
|
|
31
32
|
cfg,
|
|
@@ -35,12 +36,12 @@ function listEnabledAccounts(cfg, accountId) {
|
|
|
35
36
|
const zaloMessageActions = {
|
|
36
37
|
describeMessageTool: ({ cfg, accountId }) => {
|
|
37
38
|
if (listEnabledAccounts(cfg, accountId).length === 0) return null;
|
|
38
|
-
const actions = /* @__PURE__ */ new Set(["send"]);
|
|
39
39
|
return {
|
|
40
|
-
actions: Array.from(
|
|
40
|
+
actions: Array.from(ZALO_ACTIONS),
|
|
41
41
|
capabilities: []
|
|
42
42
|
};
|
|
43
43
|
},
|
|
44
|
+
supportsAction: ({ action }) => ZALO_ACTIONS.has(action),
|
|
44
45
|
extractToolSend: ({ args }) => extractToolSend(args, "sendMessage"),
|
|
45
46
|
handleAction: async ({ action, params, cfg, accountId }) => {
|
|
46
47
|
if (action === "send") {
|
|
@@ -75,21 +76,17 @@ function normalizeZaloApproverId(value) {
|
|
|
75
76
|
const normalized = String(value).trim().replace(/^(zalo|zl):/i, "").trim();
|
|
76
77
|
return /^\d+$/.test(normalized) ? normalized : void 0;
|
|
77
78
|
}
|
|
78
|
-
const zaloApprovalAuth =
|
|
79
|
+
const zaloApprovalAuth = createChannelApprovalAuth({
|
|
79
80
|
channelLabel: "Zalo",
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
resolveInputs: ({ cfg, accountId }) => {
|
|
82
|
+
return { allowFrom: resolveZaloAccount({
|
|
82
83
|
cfg,
|
|
83
84
|
accountId
|
|
84
|
-
}).config;
|
|
85
|
-
return resolveApprovalApprovers({
|
|
86
|
-
allowFrom: account.allowFrom,
|
|
87
|
-
normalizeApprover: normalizeZaloApproverId
|
|
88
|
-
});
|
|
85
|
+
}).config.allowFrom };
|
|
89
86
|
},
|
|
90
|
-
|
|
91
|
-
});
|
|
92
|
-
const ZaloConfigSchema =
|
|
87
|
+
normalizeApprover: normalizeZaloApproverId
|
|
88
|
+
}).approvalAuth;
|
|
89
|
+
const ZaloConfigSchema = buildMultiAccountChannelSchema(z.object({
|
|
93
90
|
name: z.string().optional(),
|
|
94
91
|
enabled: z.boolean().optional(),
|
|
95
92
|
markdown: MarkdownConfigSchema,
|
|
@@ -105,7 +102,7 @@ const ZaloConfigSchema = buildCatchallMultiAccountChannelSchema(z.object({
|
|
|
105
102
|
mediaMaxMb: z.number().optional(),
|
|
106
103
|
proxy: z.string().optional(),
|
|
107
104
|
responsePrefix: z.string().optional()
|
|
108
|
-
}));
|
|
105
|
+
}), { accountsMode: "catchall" });
|
|
109
106
|
//#endregion
|
|
110
107
|
//#region extensions/zalo/src/session-route.ts
|
|
111
108
|
function resolveZaloOutboundSessionRoute(params) {
|
|
@@ -148,13 +145,12 @@ function collectZaloStatusIssues(accounts) {
|
|
|
148
145
|
const enabled = account.enabled !== false;
|
|
149
146
|
const configured = account.configured === true;
|
|
150
147
|
if (!enabled || !configured) continue;
|
|
151
|
-
if (account.dmPolicy === "open") issues.push({
|
|
148
|
+
if (account.dmPolicy === "open") issues.push(standardDmPolicyOpenIssue({
|
|
152
149
|
channel: "zalo",
|
|
153
150
|
accountId,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
});
|
|
151
|
+
channelLabel: "Zalo",
|
|
152
|
+
configPath: "channels.zalo"
|
|
153
|
+
}));
|
|
158
154
|
}
|
|
159
155
|
return issues;
|
|
160
156
|
}
|
|
@@ -180,24 +176,27 @@ function looksLikeZaloChatId(raw, normalized) {
|
|
|
180
176
|
const target = normalizeZaloMessagingTarget(normalized ?? raw);
|
|
181
177
|
return Boolean(target);
|
|
182
178
|
}
|
|
183
|
-
const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
179
|
+
const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-BsZBukDW.js"));
|
|
184
180
|
const zaloSetupWizard = createZaloSetupWizardProxy(async () => (await import("./setup-surface-8eRimod9.js")).zaloSetupWizard);
|
|
185
181
|
const zaloTextChunkLimit = 2e3;
|
|
186
|
-
|
|
182
|
+
async function sendZaloDelivery(ctx) {
|
|
183
|
+
const result = await (await loadZaloChannelRuntime()).sendZaloText({
|
|
184
|
+
to: ctx.to,
|
|
185
|
+
text: ctx.text,
|
|
186
|
+
accountId: ctx.accountId ?? void 0,
|
|
187
|
+
mediaUrl: ctx.mediaUrl,
|
|
188
|
+
cfg: ctx.cfg
|
|
189
|
+
});
|
|
190
|
+
if (!result.ok) throw new Error(result.error ?? `Failed to send Zalo ${ctx.mediaUrl ? "media" : "message"}`);
|
|
191
|
+
return {
|
|
192
|
+
messageId: result.messageId ?? "",
|
|
193
|
+
receipt: result.receipt
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const zaloSendResultAdapter = createAttachedChannelResultAdapter({
|
|
187
197
|
channel: "zalo",
|
|
188
|
-
sendText:
|
|
189
|
-
|
|
190
|
-
text,
|
|
191
|
-
accountId: accountId ?? void 0,
|
|
192
|
-
cfg
|
|
193
|
-
}),
|
|
194
|
-
sendMedia: async ({ to, text, mediaUrl, accountId, cfg }) => await (await loadZaloChannelRuntime()).sendZaloText({
|
|
195
|
-
to,
|
|
196
|
-
text,
|
|
197
|
-
accountId: accountId ?? void 0,
|
|
198
|
-
mediaUrl,
|
|
199
|
-
cfg
|
|
200
|
-
})
|
|
198
|
+
sendText: sendZaloDelivery,
|
|
199
|
+
sendMedia: sendZaloDelivery
|
|
201
200
|
});
|
|
202
201
|
const zaloMessageAdapter = defineChannelMessageAdapter({
|
|
203
202
|
id: "zalo",
|
|
@@ -207,19 +206,8 @@ const zaloMessageAdapter = defineChannelMessageAdapter({
|
|
|
207
206
|
messageSendingHooks: true
|
|
208
207
|
} },
|
|
209
208
|
send: {
|
|
210
|
-
text:
|
|
211
|
-
|
|
212
|
-
text,
|
|
213
|
-
accountId: accountId ?? void 0,
|
|
214
|
-
cfg
|
|
215
|
-
}),
|
|
216
|
-
media: async ({ to, text, mediaUrl, accountId, cfg }) => await (await loadZaloChannelRuntime()).sendZaloText({
|
|
217
|
-
to,
|
|
218
|
-
text,
|
|
219
|
-
accountId: accountId ?? void 0,
|
|
220
|
-
mediaUrl,
|
|
221
|
-
cfg
|
|
222
|
-
})
|
|
209
|
+
text: sendZaloDelivery,
|
|
210
|
+
media: sendZaloDelivery
|
|
223
211
|
}
|
|
224
212
|
});
|
|
225
213
|
const zaloConfigAdapter = createScopedChannelConfigAdapter({
|
|
@@ -363,12 +351,12 @@ const zaloPlugin = createChatChannelPlugin({
|
|
|
363
351
|
ctx,
|
|
364
352
|
textChunkLimit: zaloTextChunkLimit,
|
|
365
353
|
chunker: chunkTextForOutbound,
|
|
366
|
-
sendText: (nextCtx) =>
|
|
367
|
-
sendMedia: (nextCtx) =>
|
|
354
|
+
sendText: (nextCtx) => zaloSendResultAdapter.sendText(nextCtx),
|
|
355
|
+
sendMedia: (nextCtx) => zaloSendResultAdapter.sendMedia(nextCtx),
|
|
368
356
|
emptyResult: createEmptyChannelResult("zalo"),
|
|
369
357
|
onResult: ctx.onDeliveryResult
|
|
370
358
|
}),
|
|
371
|
-
...
|
|
359
|
+
...zaloSendResultAdapter
|
|
372
360
|
}
|
|
373
361
|
});
|
|
374
362
|
//#endregion
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as zaloPlugin } from "./channel-
|
|
1
|
+
import { t as zaloPlugin } from "./channel-CBPOM3Pc.js";
|
|
2
2
|
export { zaloPlugin };
|
|
@@ -86,7 +86,7 @@ async function startZaloGatewayAccount(ctx) {
|
|
|
86
86
|
setStatus: ctx.setStatus
|
|
87
87
|
});
|
|
88
88
|
ctx.log?.info(`[${account.accountId}] starting provider${zaloBotLabel} mode=${mode}`);
|
|
89
|
-
const { monitorZaloProvider } = await import("./monitor-
|
|
89
|
+
const { monitorZaloProvider } = await import("./monitor-DTi243P3.js");
|
|
90
90
|
return monitorZaloProvider({
|
|
91
91
|
token,
|
|
92
92
|
account,
|
|
@@ -12,8 +12,9 @@ import { registerPluginHttpRoute, resolveWebhookPath } from "openclaw/plugin-sdk
|
|
|
12
12
|
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
13
13
|
import { formatInboundMediaUnavailableText } from "openclaw/plugin-sdk/channel-inbound";
|
|
14
14
|
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
15
|
-
import { waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
|
|
15
|
+
import { sleepWithAbort, waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
|
|
16
16
|
import { createHostedOutboundMediaStore } from "openclaw/plugin-sdk/outbound-media";
|
|
17
|
+
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
17
18
|
//#region extensions/zalo/src/monitor-durable.ts
|
|
18
19
|
function prepareZaloDurableReplyPayload(params) {
|
|
19
20
|
if (!params.payload.text) return params.payload;
|
|
@@ -129,7 +130,7 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
|
129
130
|
res.end("Expired");
|
|
130
131
|
return true;
|
|
131
132
|
}
|
|
132
|
-
if (url.searchParams.get("token")
|
|
133
|
+
if (!safeEqualSecret(url.searchParams.get("token"), entry.metadata.token)) {
|
|
133
134
|
res.statusCode = 401;
|
|
134
135
|
res.end("Unauthorized");
|
|
135
136
|
return true;
|
|
@@ -150,6 +151,10 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
|
150
151
|
}
|
|
151
152
|
//#endregion
|
|
152
153
|
//#region extensions/zalo/src/monitor.ts
|
|
154
|
+
/** Default idle timeout for Zalo inbound photo downloads (30 seconds). */
|
|
155
|
+
const ZALO_MEDIA_READ_IDLE_TIMEOUT_MS = 3e4;
|
|
156
|
+
/** Maximum wait for Zalo inbound photo response headers (120 seconds). */
|
|
157
|
+
const ZALO_MEDIA_RESPONSE_HEADER_TIMEOUT_MS = 12e4;
|
|
153
158
|
const ZALO_TEXT_LIMIT = 2e3;
|
|
154
159
|
const DEFAULT_MEDIA_MAX_MB = 5;
|
|
155
160
|
const WEBHOOK_CLEANUP_TIMEOUT_MS = 5e3;
|
|
@@ -160,7 +165,7 @@ function resolveZaloTimestampMs(date) {
|
|
|
160
165
|
if (!date) return;
|
|
161
166
|
return date >= UNIX_MILLISECONDS_THRESHOLD ? date : date * 1e3;
|
|
162
167
|
}
|
|
163
|
-
const loadZaloWebhookModule = createLazyRuntimeModule(() => import("./monitor.webhook-
|
|
168
|
+
const loadZaloWebhookModule = createLazyRuntimeModule(() => import("./monitor.webhook-BFkM-Syx.js"));
|
|
164
169
|
function releaseSharedHostedMediaRouteRef(routePath) {
|
|
165
170
|
const current = hostedMediaRouteRefs.get(routePath);
|
|
166
171
|
if (!current) return;
|
|
@@ -270,9 +275,7 @@ function startPollingLoop(params) {
|
|
|
270
275
|
} catch (err) {
|
|
271
276
|
if (err instanceof ZaloApiError && err.isPollingTimeout) {} else if (!isStopped() && !abortSignal.aborted) {
|
|
272
277
|
runtime.error?.(`[${account.accountId}] Zalo polling error: ${formatZaloError(err)}`);
|
|
273
|
-
await
|
|
274
|
-
setTimeout(resolve, 5e3);
|
|
275
|
-
});
|
|
278
|
+
await sleepWithAbort(5e3, abortSignal).catch(() => void 0);
|
|
276
279
|
}
|
|
277
280
|
}
|
|
278
281
|
if (!isStopped() && !abortSignal.aborted) setImmediate(() => {
|
|
@@ -347,7 +350,9 @@ async function handleImageMessage(params) {
|
|
|
347
350
|
const maxBytes = mediaMaxMb * 1024 * 1024;
|
|
348
351
|
const saved = await core.channel.media.saveRemoteMedia({
|
|
349
352
|
url: photo_url,
|
|
350
|
-
maxBytes
|
|
353
|
+
maxBytes,
|
|
354
|
+
responseHeaderTimeoutMs: ZALO_MEDIA_RESPONSE_HEADER_TIMEOUT_MS,
|
|
355
|
+
readIdleTimeoutMs: ZALO_MEDIA_READ_IDLE_TIMEOUT_MS
|
|
351
356
|
});
|
|
352
357
|
mediaPath = saved.path;
|
|
353
358
|
mediaType = saved.contentType;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { B as registerWebhookTargetWithPluginRoute, I as readJsonWebhookBodyOrReject, K as resolveWebhookTargetWithAuthOrRejectSync, Q as withResolvedWebhookRequestPipeline, V as resolveClientIp, 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-CAA4ZtqF.js";
|
|
2
|
-
import { createClaimableDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
3
2
|
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
3
|
+
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
4
|
+
import { runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
|
|
4
5
|
//#region extensions/zalo/src/monitor.webhook.ts
|
|
5
6
|
const ZALO_WEBHOOK_REPLAY_WINDOW_MS = 5 * 6e4;
|
|
6
7
|
const webhookTargets = /* @__PURE__ */ new Map();
|
|
@@ -9,10 +10,6 @@ const webhookRateLimiter = createFixedWindowRateLimiter({
|
|
|
9
10
|
maxRequests: WEBHOOK_RATE_LIMIT_DEFAULTS.maxRequests,
|
|
10
11
|
maxTrackedKeys: WEBHOOK_RATE_LIMIT_DEFAULTS.maxTrackedKeys
|
|
11
12
|
});
|
|
12
|
-
const recentWebhookEvents = createClaimableDedupe({
|
|
13
|
-
ttlMs: ZALO_WEBHOOK_REPLAY_WINDOW_MS,
|
|
14
|
-
memoryMaxSize: 5e3
|
|
15
|
-
});
|
|
16
13
|
const webhookAnomalyTracker = createWebhookAnomalyTracker({
|
|
17
14
|
maxTrackedKeys: WEBHOOK_ANOMALY_COUNTER_DEFAULTS.maxTrackedKeys,
|
|
18
15
|
ttlMs: WEBHOOK_ANOMALY_COUNTER_DEFAULTS.ttlMs,
|
|
@@ -43,6 +40,13 @@ function buildReplayEventCacheKey(target, update) {
|
|
|
43
40
|
messageId
|
|
44
41
|
]);
|
|
45
42
|
}
|
|
43
|
+
const recentWebhookEvents = createChannelReplayGuard({
|
|
44
|
+
dedupe: {
|
|
45
|
+
ttlMs: ZALO_WEBHOOK_REPLAY_WINDOW_MS,
|
|
46
|
+
memoryMaxSize: 5e3
|
|
47
|
+
},
|
|
48
|
+
buildReplayKey: ({ target, update }) => buildReplayEventCacheKey(target, update)
|
|
49
|
+
});
|
|
46
50
|
var ZaloRetryableWebhookError = class extends Error {
|
|
47
51
|
constructor(message, options) {
|
|
48
52
|
super(message, options);
|
|
@@ -50,23 +54,17 @@ var ZaloRetryableWebhookError = class extends Error {
|
|
|
50
54
|
}
|
|
51
55
|
};
|
|
52
56
|
async function processZaloReplayGuardedUpdate(params) {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await params.processUpdate(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return "processed";
|
|
65
|
-
} catch (error) {
|
|
66
|
-
if (replayEventKey) if (error instanceof ZaloRetryableWebhookError) recentWebhookEvents.release(replayEventKey, { error });
|
|
67
|
-
else await recentWebhookEvents.commit(replayEventKey);
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
57
|
+
const event = {
|
|
58
|
+
target: params.target,
|
|
59
|
+
update: params.update
|
|
60
|
+
};
|
|
61
|
+
return (await recentWebhookEvents.processGuarded(event, async () => {
|
|
62
|
+
params.target.statusSink?.({ lastInboundAt: Date.now() });
|
|
63
|
+
await params.processUpdate(event);
|
|
64
|
+
}, {
|
|
65
|
+
dedupe: { now: params.nowMs },
|
|
66
|
+
onError: (error) => error instanceof ZaloRetryableWebhookError ? "release" : "commit"
|
|
67
|
+
})).kind === "processed" ? "processed" : "duplicate";
|
|
70
68
|
}
|
|
71
69
|
function recordWebhookStatus(runtime, path, statusCode) {
|
|
72
70
|
webhookAnomalyTracker.record({
|
|
@@ -154,12 +152,12 @@ async function handleZaloWebhookRequest(req, res, processUpdate) {
|
|
|
154
152
|
recordWebhookStatus(target.runtime, path, res.statusCode);
|
|
155
153
|
return true;
|
|
156
154
|
}
|
|
157
|
-
processZaloReplayGuardedUpdate({
|
|
155
|
+
runDetachedWebhookWork(() => processZaloReplayGuardedUpdate({
|
|
158
156
|
target,
|
|
159
157
|
update,
|
|
160
158
|
processUpdate,
|
|
161
159
|
nowMs
|
|
162
|
-
}).catch((err) => {
|
|
160
|
+
})).catch((err) => {
|
|
163
161
|
target.runtime.error?.(`[${target.account.accountId}] Zalo webhook failed: ${String(err)}`);
|
|
164
162
|
});
|
|
165
163
|
res.statusCode = 200;
|
|
@@ -1,51 +1,10 @@
|
|
|
1
|
-
import { collectConditionalChannelFieldAssignments, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
1
|
+
import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
2
|
//#region extensions/zalo/src/secret-contract.ts
|
|
3
|
-
const secretTargetRegistryEntries =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
pathPattern: "channels.zalo.accounts.*.botToken",
|
|
9
|
-
secretShape: "secret_input",
|
|
10
|
-
expectedResolvedValue: "string",
|
|
11
|
-
includeInPlan: true,
|
|
12
|
-
includeInConfigure: true,
|
|
13
|
-
includeInAudit: true
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
id: "channels.zalo.accounts.*.webhookSecret",
|
|
17
|
-
targetType: "channels.zalo.accounts.*.webhookSecret",
|
|
18
|
-
configFile: "openclaw.json",
|
|
19
|
-
pathPattern: "channels.zalo.accounts.*.webhookSecret",
|
|
20
|
-
secretShape: "secret_input",
|
|
21
|
-
expectedResolvedValue: "string",
|
|
22
|
-
includeInPlan: true,
|
|
23
|
-
includeInConfigure: true,
|
|
24
|
-
includeInAudit: true
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
id: "channels.zalo.botToken",
|
|
28
|
-
targetType: "channels.zalo.botToken",
|
|
29
|
-
configFile: "openclaw.json",
|
|
30
|
-
pathPattern: "channels.zalo.botToken",
|
|
31
|
-
secretShape: "secret_input",
|
|
32
|
-
expectedResolvedValue: "string",
|
|
33
|
-
includeInPlan: true,
|
|
34
|
-
includeInConfigure: true,
|
|
35
|
-
includeInAudit: true
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
id: "channels.zalo.webhookSecret",
|
|
39
|
-
targetType: "channels.zalo.webhookSecret",
|
|
40
|
-
configFile: "openclaw.json",
|
|
41
|
-
pathPattern: "channels.zalo.webhookSecret",
|
|
42
|
-
secretShape: "secret_input",
|
|
43
|
-
expectedResolvedValue: "string",
|
|
44
|
-
includeInPlan: true,
|
|
45
|
-
includeInConfigure: true,
|
|
46
|
-
includeInAudit: true
|
|
47
|
-
}
|
|
48
|
-
];
|
|
3
|
+
const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
|
|
4
|
+
channelKey: "zalo",
|
|
5
|
+
account: ["botToken", "webhookSecret"],
|
|
6
|
+
channel: ["botToken", "webhookSecret"]
|
|
7
|
+
});
|
|
49
8
|
function collectRuntimeConfigAssignments(params) {
|
|
50
9
|
const resolved = getChannelSurface(params.config, "zalo");
|
|
51
10
|
if (!resolved) return;
|
|
@@ -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-Bxvjh0Hq.js";
|
|
2
2
|
export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/zalo",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/zalo",
|
|
9
|
-
"version": "2026.7.
|
|
9
|
+
"version": "2026.7.2-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.7.
|
|
14
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependenciesMeta": {
|
|
17
17
|
"openclaw": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/zalo",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.2-beta.2",
|
|
4
4
|
"description": "OpenClaw Zalo channel plugin for bot and webhook chats.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"openclaw": ">=2026.7.
|
|
11
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
12
12
|
},
|
|
13
13
|
"peerDependenciesMeta": {
|
|
14
14
|
"openclaw": {
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"minHostVersion": ">=2026.4.10"
|
|
40
40
|
},
|
|
41
41
|
"compat": {
|
|
42
|
-
"pluginApi": ">=2026.7.
|
|
42
|
+
"pluginApi": ">=2026.7.2-beta.2"
|
|
43
43
|
},
|
|
44
44
|
"build": {
|
|
45
|
-
"openclawVersion": "2026.7.
|
|
45
|
+
"openclawVersion": "2026.7.2-beta.2"
|
|
46
46
|
},
|
|
47
47
|
"release": {
|
|
48
48
|
"publishToClawHub": true,
|