@openclaw/zalo 2026.9.8 → 2026.10.1-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.
@@ -1,5 +1,5 @@
1
1
  import { n as zaloDmPolicy, r as zaloSetupAdapter, t as createZaloSetupWizardProxy } from "./setup-core-BE-EaCnS.mjs";
2
- import { t as zaloPlugin } from "./channel-COgJOEix.mjs";
2
+ import { t as zaloPlugin } from "./channel-f4tP7sv3.mjs";
3
3
  import { n as resolveZaloRuntimeGroupPolicy } from "./group-access-Blsyu-ot.mjs";
4
4
  import { zaloSetupWizard } from "../setup-api.js";
5
5
  import "../api.js";
@@ -1,5 +1,5 @@
1
1
  import { c as isZaloAccountConfigured, d as resolveZaloAccount, i as zaloSetupContract, l as listZaloAccountIds, p as buildSecretInputSchema, s as inspectZaloAccount, t as createZaloSetupWizardProxy, u as resolveDefaultZaloAccountId } from "./setup-core-BE-EaCnS.mjs";
2
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Cpsqe5Cv.mjs";
2
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DF_0WQX4.mjs";
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";
@@ -24,7 +24,7 @@ import { z } from "zod";
24
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("./send-sCQINy2G.mjs"), "sendMessageZalo");
27
+ const loadZaloActionsRuntime = createLazyRuntimeNamedExport(() => import("./send-Cj1YI36h.mjs"), "sendMessageZalo");
28
28
  const providerId = "zalo";
29
29
  const ZALO_ACTIONS = /* @__PURE__ */ new Set(["send"]);
30
30
  function listEnabledAccounts(cfg, accountId) {
@@ -186,7 +186,7 @@ function looksLikeZaloChatId(raw, normalized) {
186
186
  const target = normalizeZaloMessagingTarget(normalized ?? raw);
187
187
  return Boolean(target);
188
188
  }
189
- const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-F1ScBwNC.mjs"));
189
+ const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-I1gRRKZx.mjs"));
190
190
  const zaloSetupWizard = createZaloSetupWizardProxy(async () => (await import("./setup-surface-DMW4dLWX.mjs").then((n) => n.t)).zaloSetupWizard);
191
191
  const zaloTextChunkLimit = 2e3;
192
192
  async function sendZaloDelivery(ctx) {
@@ -1,5 +1,5 @@
1
1
  import { m as normalizeSecretInputString } from "./setup-core-BE-EaCnS.mjs";
2
- import { i as getMe, n as ZaloApiError, sendMessageZalo, t as resolveZaloProxyFetch } from "./send-sCQINy2G.mjs";
2
+ import { i as getMe, n as ZaloApiError, sendMessageZalo, t as resolveZaloProxyFetch } from "./send-Cj1YI36h.mjs";
3
3
  import { createAccountStatusSink } from "openclaw/plugin-sdk/channel-outbound";
4
4
  import { runChannelProbe } from "openclaw/plugin-sdk/text-utility-runtime";
5
5
  //#region extensions/zalo/src/probe.ts
@@ -62,7 +62,7 @@ async function startZaloGatewayAccount(ctx) {
62
62
  setStatus: ctx.setStatus
63
63
  });
64
64
  ctx.log?.info(`[${account.accountId}] starting provider${zaloBotLabel} mode=${mode}`);
65
- const { monitorZaloProvider } = await import("./monitor-BbW2wx_3.mjs");
65
+ const { monitorZaloProvider } = await import("./monitor-BcLcFy7k.mjs");
66
66
  return monitorZaloProvider({
67
67
  token,
68
68
  account,
@@ -1,10 +1,10 @@
1
1
  import { n as resolveZaloRuntimeGroupPolicy, t as normalizeZaloAllowEntry } from "./group-access-Blsyu-ot.mjs";
2
2
  import { t as getZaloRuntime } from "./runtime-Dfhzt7qb.mjs";
3
- import { a as getUpdates, c as sendMessage, d as ZALO_OUTBOUND_MEDIA_TTL_MS, l as sendPhoto, n as ZaloApiError, o as getWebhookInfo, r as deleteWebhook, s as sendChatAction, t as resolveZaloProxyFetch, u as setWebhook } from "./send-sCQINy2G.mjs";
3
+ import { a as getUpdates, c as sendMessage, d as ZALO_OUTBOUND_MEDIA_TTL_MS, l as sendPhoto, n as ZaloApiError, o as getWebhookInfo, r as deleteWebhook, s as sendChatAction, t as resolveZaloProxyFetch, u as setWebhook } from "./send-Cj1YI36h.mjs";
4
4
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
5
5
  import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
6
6
  import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
7
- import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
7
+ import { normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
9
9
  import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
10
10
  import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
@@ -159,9 +159,7 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
159
159
  }
160
160
  //#endregion
161
161
  //#region extensions/zalo/src/monitor.ts
162
- /** Default idle timeout for Zalo inbound photo downloads (30 seconds). */
163
162
  const ZALO_MEDIA_READ_IDLE_TIMEOUT_MS = 3e4;
164
- /** Maximum wait for Zalo inbound photo response headers (120 seconds). */
165
163
  const ZALO_MEDIA_RESPONSE_HEADER_TIMEOUT_MS = 12e4;
166
164
  const ZALO_TEXT_LIMIT = 2e3;
167
165
  const DEFAULT_MEDIA_MAX_MB = 5;
@@ -172,8 +170,8 @@ function resolveZaloTimestampMs(date) {
172
170
  if (!date) return;
173
171
  return date >= UNIX_MILLISECONDS_THRESHOLD ? date : date * 1e3;
174
172
  }
175
- const loadZaloWebhookRuntime = createLazyRuntimeNamedExport(() => import("./monitor.webhook-CaknDJfy.mjs"), "zaloWebhookRuntime");
176
- const loadZaloWebhookIngressRuntime = createLazyRuntimeNamedExport(() => import("./webhook-spool-CTCugbD_.mjs"), "zaloWebhookIngressRuntime");
173
+ const loadZaloWebhookRuntime = createLazyRuntimeNamedExport(() => import("./monitor.webhook-cIt_VYBI.mjs"), "zaloWebhookRuntime");
174
+ const loadZaloWebhookIngressRuntime = createLazyRuntimeNamedExport(() => import("./webhook-spool-MSe2Vqq3.mjs"), "zaloWebhookIngressRuntime");
177
175
  const loadZaloWebhookModule = createLazyRuntimeModule(async () => ({
178
176
  ...await loadZaloWebhookRuntime(),
179
177
  ...await loadZaloWebhookIngressRuntime()
@@ -209,10 +207,6 @@ function describeWebhookTarget(rawUrl) {
209
207
  return rawUrl;
210
208
  }
211
209
  }
212
- function normalizeWebhookUrl(url) {
213
- const trimmed = url?.trim();
214
- return trimmed ? trimmed : void 0;
215
- }
216
210
  function logVerbose(core, runtime, message) {
217
211
  if (core.logging.shouldLogVerbose()) runtime.log?.(`[zalo] ${message}`);
218
212
  }
@@ -259,8 +253,9 @@ async function processUpdate(params) {
259
253
  if (!message) return;
260
254
  switch (event_name) {
261
255
  case "message.text.received":
262
- await handleTextMessage({
256
+ if (message.text?.trim()) await processMessageWithPipeline({
263
257
  message,
258
+ text: message.text,
264
259
  ...sharedContext
265
260
  });
266
261
  break;
@@ -276,15 +271,6 @@ async function processUpdate(params) {
276
271
  case "message.unsupported.received": logVerbose(core, runtime, `[${account.accountId}] Received unsupported message type from ${message.from.id}`);
277
272
  }
278
273
  }
279
- async function handleTextMessage(params) {
280
- const { message } = params;
281
- const { text } = message;
282
- if (!text?.trim()) return;
283
- await processMessageWithPipeline({
284
- ...params,
285
- text
286
- });
287
- }
288
274
  async function handleImageMessage(params) {
289
275
  const { message, mediaMaxMb, account, core, runtime } = params;
290
276
  const { photo_url, caption } = message;
@@ -634,7 +620,7 @@ async function monitorZaloProvider(options) {
634
620
  const effectiveMediaMaxMb = typeof configuredMediaMaxMb === "number" && configuredMediaMaxMb > 0 ? configuredMediaMaxMb : DEFAULT_MEDIA_MAX_MB;
635
621
  const fetcher = fetcherOverride ?? resolveZaloProxyFetch(account.config.proxy);
636
622
  const mode = useWebhook ? "webhook" : "polling";
637
- const effectiveWebhookUrl = normalizeWebhookUrl(webhookUrl ?? account.config.webhookUrl);
623
+ const effectiveWebhookUrl = normalizeOptionalString(webhookUrl ?? account.config.webhookUrl);
638
624
  const effectiveWebhookPath = effectiveWebhookUrl || webhookPath?.trim() || account.config.webhookPath?.trim() ? resolveWebhookPath({
639
625
  webhookPath: webhookPath ?? account.config.webhookPath,
640
626
  webhookUrl: effectiveWebhookUrl,
@@ -647,7 +633,7 @@ async function monitorZaloProvider(options) {
647
633
  }) : void 0;
648
634
  let stopped = false;
649
635
  const stopHandlers = [];
650
- const asyncStopHandlers = [];
636
+ let stopIngress;
651
637
  let cleanupWebhook;
652
638
  const stop = () => {
653
639
  if (stopped) return;
@@ -702,7 +688,7 @@ async function monitorZaloProvider(options) {
702
688
  }
703
689
  });
704
690
  ingress.start();
705
- asyncStopHandlers.push(ingress.stop);
691
+ stopIngress = ingress.stop;
706
692
  const unregister = registerZaloWebhookTarget({
707
693
  account,
708
694
  config,
@@ -732,19 +718,15 @@ async function monitorZaloProvider(options) {
732
718
  secret_token: webhookSecret
733
719
  }, fetcher);
734
720
  statusSink?.(channelReadyPatch());
735
- let webhookCleanupPromise;
736
721
  cleanupWebhook = async () => {
737
- if (!webhookCleanupPromise) webhookCleanupPromise = (async () => {
738
- runtime.log?.(`[${account.accountId}] Zalo stopping; deleting webhook`);
739
- try {
740
- await deleteWebhook(token, fetcher, WEBHOOK_CLEANUP_TIMEOUT_MS);
741
- runtime.log?.(`[${account.accountId}] Zalo webhook deleted`);
742
- } catch (err) {
743
- const detail = err instanceof Error && err.name === "AbortError" ? `timed out after ${String(WEBHOOK_CLEANUP_TIMEOUT_MS)}ms` : formatZaloError(err);
744
- runtime.error?.(`[${account.accountId}] Zalo webhook delete failed: ${detail}`);
745
- }
746
- })();
747
- await webhookCleanupPromise;
722
+ runtime.log?.(`[${account.accountId}] Zalo stopping; deleting webhook`);
723
+ try {
724
+ await deleteWebhook(token, fetcher, WEBHOOK_CLEANUP_TIMEOUT_MS);
725
+ runtime.log?.(`[${account.accountId}] Zalo webhook deleted`);
726
+ } catch (err) {
727
+ const detail = err instanceof Error && err.name === "AbortError" ? `timed out after ${String(WEBHOOK_CLEANUP_TIMEOUT_MS)}ms` : formatZaloError(err);
728
+ runtime.error?.(`[${account.accountId}] Zalo webhook delete failed: ${detail}`);
729
+ }
748
730
  };
749
731
  runtime.log?.(`[${account.accountId}] Zalo webhook registered path=${path}`);
750
732
  await waitForAbortSignal(abortSignal);
@@ -752,7 +734,7 @@ async function monitorZaloProvider(options) {
752
734
  }
753
735
  runtime.log?.(`[${account.accountId}] Zalo polling mode: clearing webhook before startup`);
754
736
  try {
755
- const currentWebhookUrl = normalizeWebhookUrl((await getWebhookInfo(token, fetcher)).result?.url);
737
+ const currentWebhookUrl = normalizeOptionalString((await getWebhookInfo(token, fetcher)).result?.url);
756
738
  if (!currentWebhookUrl) runtime.log?.(`[${account.accountId}] Zalo polling mode ready (no webhook configured)`);
757
739
  else {
758
740
  runtime.log?.(`[${account.accountId}] Zalo polling mode disabling existing webhook ${describeWebhookTarget(currentWebhookUrl)}`);
@@ -792,7 +774,7 @@ async function monitorZaloProvider(options) {
792
774
  abortSignal.removeEventListener("abort", stopOnAbort);
793
775
  await cleanupWebhook?.();
794
776
  stop();
795
- for (const stopAsync of asyncStopHandlers) await stopAsync();
777
+ await stopIngress?.();
796
778
  runtime.log?.(`[${account.accountId}] Zalo provider stopped mode=${mode}`);
797
779
  }
798
780
  }
@@ -1,4 +1,4 @@
1
- import { ZaloWebhookPayloadError } from "./webhook-spool-CTCugbD_.mjs";
1
+ import { ZaloWebhookPayloadError } from "./webhook-spool-MSe2Vqq3.mjs";
2
2
  import { resolveClientIp } from "openclaw/plugin-sdk/core";
3
3
  import { WEBHOOK_ANOMALY_COUNTER_DEFAULTS, WEBHOOK_RATE_LIMIT_DEFAULTS, applyBasicWebhookRequestGuards, createFixedWindowRateLimiter, createWebhookAnomalyTracker, registerWebhookTarget, registerWebhookTargetWithPluginRoute, resolveWebhookTargetWithAuthOrRejectSync, withResolvedWebhookRequestPipeline } from "openclaw/plugin-sdk/webhook-ingress";
4
4
  import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
@@ -0,0 +1,33 @@
1
+ import { collectConditionalChannelFieldAssignments, createChannelSecretContract, hasOwnProperty, normalizeSecretStringValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
+ //#region extensions/zalo/src/secret-contract.ts
3
+ const channelSecrets = createChannelSecretContract({
4
+ channelKey: "zalo",
5
+ account: ["botToken", "webhookSecret"],
6
+ channel: ["botToken", "webhookSecret"],
7
+ collect(params) {
8
+ const { channel: zalo } = params;
9
+ collectConditionalChannelFieldAssignments({
10
+ ...params,
11
+ field: "botToken",
12
+ topLevelActiveWithoutAccounts: true,
13
+ topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "botToken") && !normalizeSecretStringValue(account.tokenFile),
14
+ accountActive: ({ enabled }) => enabled,
15
+ topInactiveReason: "no enabled Zalo surface inherits this top-level botToken.",
16
+ accountInactiveReason: "Zalo account is disabled."
17
+ });
18
+ const baseWebhookUrl = typeof zalo.webhookUrl === "string" ? zalo.webhookUrl.trim() : "";
19
+ const accountWebhookUrl = (account) => hasOwnProperty(account, "webhookUrl") ? typeof account.webhookUrl === "string" ? account.webhookUrl.trim() : "" : baseWebhookUrl;
20
+ collectConditionalChannelFieldAssignments({
21
+ ...params,
22
+ field: "webhookSecret",
23
+ topLevelActiveWithoutAccounts: baseWebhookUrl.length > 0,
24
+ topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "webhookSecret") && accountWebhookUrl(account).length > 0,
25
+ accountActive: ({ account, enabled }) => enabled && accountWebhookUrl(account).length > 0,
26
+ topInactiveReason: "no enabled Zalo webhook surface inherits this top-level webhookSecret (webhook mode is not active).",
27
+ accountInactiveReason: "Zalo account is disabled or webhook mode is not active for this account."
28
+ });
29
+ }
30
+ });
31
+ const { secretTargetRegistryEntries, collectRuntimeConfigAssignments } = channelSecrets;
32
+ //#endregion
33
+ export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
@@ -1,3 +1,3 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-Cpsqe5Cv.mjs";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-DF_0WQX4.mjs";
2
2
  import "../secret-contract-api.js";
3
3
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -32,8 +32,8 @@ var ZaloApiError = class extends Error {
32
32
  return this.errorCode === 408;
33
33
  }
34
34
  };
35
- function resolveZaloApiUrl(apiUrl) {
36
- const value = apiUrl === void 0 ? process.env[ZALO_API_URL_ENV]?.trim() ?? ZALO_API_BASE : apiUrl.trim();
35
+ function resolveZaloApiUrl() {
36
+ const value = process.env[ZALO_API_URL_ENV]?.trim() ?? ZALO_API_BASE;
37
37
  if (!value) throw new Error(`${ZALO_API_URL_ENV} must not be empty.`);
38
38
  let parsed;
39
39
  try {
@@ -45,11 +45,8 @@ function resolveZaloApiUrl(apiUrl) {
45
45
  if (parsed.search || parsed.hash) throw new Error(`${ZALO_API_URL_ENV} must not include a query string or fragment.`);
46
46
  return parsed.href.replace(/\/+$/u, "");
47
47
  }
48
- /**
49
- * Call the Zalo Bot API
50
- */
51
48
  async function callZaloApi(method, token, body, options) {
52
- const url = `${resolveZaloApiUrl(options?.apiUrl)}/bot${token}/${method}`;
49
+ const url = `${resolveZaloApiUrl()}/bot${token}/${method}`;
53
50
  const controller = new AbortController();
54
51
  const requestTimeoutMs = resolveTimerTimeoutMs(options?.timeoutMs, ZALO_DEFAULT_REQUEST_TIMEOUT_MS);
55
52
  const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
@@ -71,27 +68,18 @@ async function callZaloApi(method, token, body, options) {
71
68
  clearTimeout(timeoutId);
72
69
  }
73
70
  }
74
- /**
75
- * Validate bot token and get bot info
76
- */
77
71
  async function getMe(token, timeoutMs, fetcher) {
78
72
  return callZaloApi("getMe", token, void 0, {
79
73
  timeoutMs,
80
74
  fetch: fetcher
81
75
  });
82
76
  }
83
- /**
84
- * Send a text message
85
- */
86
77
  async function sendMessage(token, params, fetcher, assertDirectAdapterHandoff) {
87
78
  return callZaloApi("sendMessage", token, params, {
88
79
  fetch: fetcher,
89
80
  assertDirectAdapterHandoff
90
81
  });
91
82
  }
92
- /**
93
- * Send a photo message
94
- */
95
83
  async function sendPhoto(token, params, fetcher, assertDirectAdapterHandoff) {
96
84
  const photoUrl = params.photo.trim();
97
85
  let parsedPhotoUrl;
@@ -112,9 +100,6 @@ async function sendPhoto(token, params, fetcher, assertDirectAdapterHandoff) {
112
100
  assertDirectAdapterHandoff
113
101
  });
114
102
  }
115
- /**
116
- * Send a temporary chat action such as typing.
117
- */
118
103
  async function sendChatAction(token, params, fetcher, timeoutMs) {
119
104
  return callZaloApi("sendChatAction", token, params, {
120
105
  timeoutMs,
@@ -122,7 +107,6 @@ async function sendChatAction(token, params, fetcher, timeoutMs) {
122
107
  });
123
108
  }
124
109
  /**
125
- * Get updates using long polling (dev/testing only)
126
110
  * Note: Zalo returns a single update per call, not an array like Telegram
127
111
  */
128
112
  async function getUpdates(token, params, fetcher) {
@@ -133,24 +117,15 @@ async function getUpdates(token, params, fetcher) {
133
117
  fetch: fetcher
134
118
  });
135
119
  }
136
- /**
137
- * Set webhook URL for receiving updates
138
- */
139
120
  async function setWebhook(token, params, fetcher) {
140
121
  return callZaloApi("setWebhook", token, params, { fetch: fetcher });
141
122
  }
142
- /**
143
- * Delete webhook configuration
144
- */
145
123
  async function deleteWebhook(token, fetcher, timeoutMs) {
146
124
  return callZaloApi("deleteWebhook", token, void 0, {
147
125
  timeoutMs,
148
126
  fetch: fetcher
149
127
  });
150
128
  }
151
- /**
152
- * Get current webhook info
153
- */
154
129
  async function getWebhookInfo(token, fetcher) {
155
130
  return callZaloApi("getWebhookInfo", token, void 0, { fetch: fetcher });
156
131
  }
@@ -1,15 +1,11 @@
1
1
  import { t as getZaloRuntime } from "./runtime-Dfhzt7qb.mjs";
2
- import { n as ZaloApiError } from "./send-sCQINy2G.mjs";
2
+ import { n as ZaloApiError } from "./send-Cj1YI36h.mjs";
3
3
  import { DEFAULT_INGRESS_ADOPTION_STALL_MS, DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS, bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor } from "openclaw/plugin-sdk/channel-outbound";
4
4
  import { normalizeNullableString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { z } from "zod";
6
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7
7
  import { runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
8
- //#region extensions/zalo/src/webhook-spool.ts
9
- const ZALO_WEBHOOK_SPOOL_VERSION = 1;
10
- const ZALO_WEBHOOK_DRAIN_INTERVAL_MS = 500;
11
- const ZALO_WEBHOOK_MAX_CONCURRENT_DELIVERIES = 8;
12
- const ZaloWebhookPayloadError = createChannelIngressError("ZaloWebhookPayloadError");
8
+ //#region extensions/zalo/src/message-schema.ts
13
9
  const nonEmptyWebhookStringSchema = z.string().transform((value) => normalizeNullableString(value)).pipe(z.string());
14
10
  const optionalWebhookStringSchema = z.string().optional().catch(void 0);
15
11
  const webhookEnvelopeSchema = z.looseObject({
@@ -57,6 +53,12 @@ const webhookUpdateSchema = z.object({
57
53
  message: "text event requires message.text"
58
54
  });
59
55
  });
56
+ //#endregion
57
+ //#region extensions/zalo/src/webhook-spool.ts
58
+ const ZALO_WEBHOOK_SPOOL_VERSION = 1;
59
+ const ZALO_WEBHOOK_DRAIN_INTERVAL_MS = 500;
60
+ const ZALO_WEBHOOK_MAX_CONCURRENT_DELIVERIES = 8;
61
+ const ZaloWebhookPayloadError = createChannelIngressError("ZaloWebhookPayloadError");
60
62
  function parseRawRecord(rawEvent) {
61
63
  let parsed;
62
64
  try {
package/dist/api.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as zaloDmPolicy, r as zaloSetupAdapter, t as createZaloSetupWizardProxy } from "./.setup/setup-core-BE-EaCnS.mjs";
2
- import { t as zaloPlugin } from "./.setup/channel-COgJOEix.mjs";
2
+ import { t as zaloPlugin } from "./.setup/channel-f4tP7sv3.mjs";
3
3
  import { n as resolveZaloRuntimeGroupPolicy } from "./.setup/group-access-Blsyu-ot.mjs";
4
4
  import { zaloSetupWizard } from "./setup-api.js";
5
5
  export { createZaloSetupWizardProxy, resolveZaloRuntimeGroupPolicy, zaloDmPolicy, zaloPlugin, zaloSetupAdapter, zaloSetupWizard };
@@ -1,2 +1,2 @@
1
- import { t as zaloPlugin } from "./.setup/channel-COgJOEix.mjs";
1
+ import { t as zaloPlugin } from "./.setup/channel-f4tP7sv3.mjs";
2
2
  export { zaloPlugin };
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./.setup/secret-contract-Cpsqe5Cv.mjs";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./.setup/secret-contract-DF_0WQX4.mjs";
2
2
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -4,11 +4,11 @@ import { fileURLToPath } from "node:url";
4
4
  var setup_entry_default = defineBundledChannelSetupEntry({
5
5
  importMetaUrl: import.meta.url,
6
6
  plugin: {
7
- specifier: fileURLToPath(new URL(".setup/api-YaSbmx07.mjs", import.meta.url).href),
7
+ specifier: fileURLToPath(new URL(".setup/api-Do4fKxXr.mjs", import.meta.url).href),
8
8
  exportName: "zaloPlugin"
9
9
  },
10
10
  secrets: {
11
- specifier: fileURLToPath(new URL(".setup/secret-contract-api-DKDS_ZlS.mjs", import.meta.url).href),
11
+ specifier: fileURLToPath(new URL(".setup/secret-contract-api-CRklpdRx.mjs", import.meta.url).href),
12
12
  exportName: "channelSecrets"
13
13
  }
14
14
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/zalo",
3
- "version": "2026.9.8",
3
+ "version": "2026.10.1-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.9.8"
11
+ "openclaw": ">=2026.10.1-beta.2"
12
12
  },
13
13
  "peerDependenciesMeta": {
14
14
  "openclaw": {
@@ -80,13 +80,13 @@
80
80
  "clawhubSpec": "clawhub:@openclaw/zalo",
81
81
  "npmSpec": "@openclaw/zalo",
82
82
  "defaultChoice": "npm",
83
- "minHostVersion": ">=2026.4.10"
83
+ "minHostVersion": ">=2026.9.8"
84
84
  },
85
85
  "compat": {
86
- "pluginApi": ">=2026.9.8"
86
+ "pluginApi": ">=2026.10.1-beta.2"
87
87
  },
88
88
  "build": {
89
- "openclawVersion": "2026.9.8"
89
+ "openclawVersion": "2026.10.1-beta.2"
90
90
  },
91
91
  "release": {
92
92
  "publishToClawHub": true,
@@ -1,46 +0,0 @@
1
- import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty, normalizeSecretStringValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
- //#region extensions/zalo/src/secret-contract.ts
3
- const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
4
- channelKey: "zalo",
5
- account: ["botToken", "webhookSecret"],
6
- channel: ["botToken", "webhookSecret"]
7
- });
8
- function collectRuntimeConfigAssignments(params) {
9
- const resolved = getChannelSurface(params.config, "zalo");
10
- if (!resolved) return;
11
- const { channel: zalo, surface } = resolved;
12
- collectConditionalChannelFieldAssignments({
13
- channelKey: "zalo",
14
- field: "botToken",
15
- channel: zalo,
16
- surface,
17
- defaults: params.defaults,
18
- context: params.context,
19
- topLevelActiveWithoutAccounts: true,
20
- topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "botToken") && !normalizeSecretStringValue(account.tokenFile),
21
- accountActive: ({ enabled }) => enabled,
22
- topInactiveReason: "no enabled Zalo surface inherits this top-level botToken.",
23
- accountInactiveReason: "Zalo account is disabled."
24
- });
25
- const baseWebhookUrl = typeof zalo.webhookUrl === "string" ? zalo.webhookUrl.trim() : "";
26
- const accountWebhookUrl = (account) => hasOwnProperty(account, "webhookUrl") ? typeof account.webhookUrl === "string" ? account.webhookUrl.trim() : "" : baseWebhookUrl;
27
- collectConditionalChannelFieldAssignments({
28
- channelKey: "zalo",
29
- field: "webhookSecret",
30
- channel: zalo,
31
- surface,
32
- defaults: params.defaults,
33
- context: params.context,
34
- topLevelActiveWithoutAccounts: baseWebhookUrl.length > 0,
35
- topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "webhookSecret") && accountWebhookUrl(account).length > 0,
36
- accountActive: ({ account, enabled }) => enabled && accountWebhookUrl(account).length > 0,
37
- topInactiveReason: "no enabled Zalo webhook surface inherits this top-level webhookSecret (webhook mode is not active).",
38
- accountInactiveReason: "Zalo account is disabled or webhook mode is not active for this account."
39
- });
40
- }
41
- const channelSecrets = {
42
- secretTargetRegistryEntries,
43
- collectRuntimeConfigAssignments
44
- };
45
- //#endregion
46
- export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };