@openclaw/zalo 2026.6.5-beta.1 → 2026.6.5-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/api.js +1 -1
- package/dist/{channel-DSMo5e3B.js → channel-fQwAowmS.js} +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-uSuM_HDe.js → channel.runtime-Dfy33H5M.js} +1 -1
- package/dist/{monitor-BEIaqyy1.js → monitor-BcYKNoj4.js} +48 -94
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
- package/dist/{monitor.webhook-BSYRYNHE.js → monitor.webhook-B23mUx-y.js} +1 -1
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-fQwAowmS.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 };
|
|
@@ -173,7 +173,7 @@ function normalizeZaloMessagingTarget(raw) {
|
|
|
173
173
|
if (!trimmed) return;
|
|
174
174
|
return trimmed.replace(/^(zalo|zl):/i, "").trim();
|
|
175
175
|
}
|
|
176
|
-
const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
176
|
+
const loadZaloChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-Dfy33H5M.js"));
|
|
177
177
|
const zaloSetupWizard = createZaloSetupWizardProxy(async () => (await import("./setup-surface-8eRimod9.js")).zaloSetupWizard);
|
|
178
178
|
const zaloTextChunkLimit = 2e3;
|
|
179
179
|
const zaloRawSendResultAdapter = createRawChannelSendResultAdapter({
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as zaloPlugin } from "./channel-
|
|
1
|
+
import { t as zaloPlugin } from "./channel-fQwAowmS.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-BcYKNoj4.js");
|
|
90
90
|
return monitorZaloProvider({
|
|
91
91
|
token,
|
|
92
92
|
account,
|
|
@@ -11,12 +11,7 @@ import { registerPluginHttpRoute, resolveWebhookPath } from "openclaw/plugin-sdk
|
|
|
11
11
|
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
12
12
|
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
13
13
|
import { waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
|
|
14
|
-
import {
|
|
15
|
-
import { readFile, readdir, stat, unlink } from "node:fs/promises";
|
|
16
|
-
import { join } from "node:path";
|
|
17
|
-
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
18
|
-
import { privateFileStore } from "openclaw/plugin-sdk/security-runtime";
|
|
19
|
-
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
|
|
14
|
+
import { createHostedOutboundMediaStore } from "openclaw/plugin-sdk/outbound-media";
|
|
20
15
|
//#region extensions/zalo/src/monitor-durable.ts
|
|
21
16
|
function prepareZaloDurableReplyPayload(params) {
|
|
22
17
|
if (!params.payload.text) return params.payload;
|
|
@@ -36,63 +31,32 @@ function resolveZaloDurableReplyOptions(params) {
|
|
|
36
31
|
const ZALO_OUTBOUND_MEDIA_TTL_MS = 2 * 6e4;
|
|
37
32
|
const ZALO_OUTBOUND_MEDIA_SEGMENT = "media";
|
|
38
33
|
const ZALO_OUTBOUND_MEDIA_PREFIX = `/${ZALO_OUTBOUND_MEDIA_SEGMENT}/`;
|
|
39
|
-
const ZALO_OUTBOUND_MEDIA_DIR_NAME = "openclaw-zalo-outbound-media";
|
|
40
|
-
function resolveHostedZaloMediaDirName() {
|
|
41
|
-
const workerId = process.env.VITEST_WORKER_ID ?? process.env.VITEST_POOL_ID;
|
|
42
|
-
if (!workerId) return ZALO_OUTBOUND_MEDIA_DIR_NAME;
|
|
43
|
-
return `${ZALO_OUTBOUND_MEDIA_DIR_NAME}-${workerId.replaceAll(/[^a-zA-Z0-9_.-]/gu, "_")}`;
|
|
44
|
-
}
|
|
45
|
-
const ZALO_OUTBOUND_MEDIA_DIR = join(resolvePreferredOpenClawTmpDir(), resolveHostedZaloMediaDirName());
|
|
46
34
|
const ZALO_OUTBOUND_MEDIA_ID_RE = /^[a-f0-9]{24}$/;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (now === void 0) return;
|
|
69
|
-
let fileNames;
|
|
70
|
-
try {
|
|
71
|
-
fileNames = await readdir(ZALO_OUTBOUND_MEDIA_DIR);
|
|
72
|
-
} catch {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
await Promise.all(fileNames.filter((fileName) => fileName.endsWith(".json")).map(async (fileName) => {
|
|
76
|
-
const id = fileName.slice(0, -5);
|
|
77
|
-
try {
|
|
78
|
-
const metadataRaw = await readFile(resolveHostedZaloMediaMetadataPath(id), "utf8");
|
|
79
|
-
const expiresAt = asDateTimestampMs(JSON.parse(metadataRaw).expiresAt);
|
|
80
|
-
if (expiresAt === void 0 || expiresAt <= now) await deleteHostedZaloMediaEntry(id);
|
|
81
|
-
} catch {
|
|
82
|
-
await deleteHostedZaloMediaEntry(id);
|
|
83
|
-
}
|
|
84
|
-
}));
|
|
35
|
+
const ZALO_OUTBOUND_MEDIA_NAMESPACE = "hosted-outbound-media";
|
|
36
|
+
const ZALO_OUTBOUND_MEDIA_CHUNKS_NAMESPACE = "hosted-outbound-media-chunks";
|
|
37
|
+
const ZALO_OUTBOUND_MEDIA_MAX_ENTRIES = 64;
|
|
38
|
+
const ZALO_OUTBOUND_MEDIA_MAX_CHUNK_ROWS = ZALO_OUTBOUND_MEDIA_MAX_ENTRIES * 256;
|
|
39
|
+
let hostedZaloMediaStore;
|
|
40
|
+
function createHostedZaloMediaStore() {
|
|
41
|
+
const runtime = getZaloRuntime();
|
|
42
|
+
return createHostedOutboundMediaStore({
|
|
43
|
+
metadataStore: runtime.state.openKeyedStore({
|
|
44
|
+
namespace: ZALO_OUTBOUND_MEDIA_NAMESPACE,
|
|
45
|
+
maxEntries: 80
|
|
46
|
+
}),
|
|
47
|
+
chunkStore: runtime.state.openKeyedStore({
|
|
48
|
+
namespace: ZALO_OUTBOUND_MEDIA_CHUNKS_NAMESPACE,
|
|
49
|
+
maxEntries: ZALO_OUTBOUND_MEDIA_MAX_CHUNK_ROWS
|
|
50
|
+
}),
|
|
51
|
+
ttlMs: ZALO_OUTBOUND_MEDIA_TTL_MS,
|
|
52
|
+
maxEntries: ZALO_OUTBOUND_MEDIA_MAX_ENTRIES,
|
|
53
|
+
maxChunkRows: ZALO_OUTBOUND_MEDIA_MAX_CHUNK_ROWS,
|
|
54
|
+
resolveExpiresAtMs: (ttlMs) => resolveExpiresAtMsFromDurationMs(ttlMs)
|
|
55
|
+
});
|
|
85
56
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
metadata: JSON.parse(metadataRaw),
|
|
91
|
-
buffer
|
|
92
|
-
};
|
|
93
|
-
} catch {
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
57
|
+
function getHostedZaloMediaStore() {
|
|
58
|
+
hostedZaloMediaStore ??= createHostedZaloMediaStore();
|
|
59
|
+
return hostedZaloMediaStore;
|
|
96
60
|
}
|
|
97
61
|
function resolveHostedZaloMediaRoutePrefix(params) {
|
|
98
62
|
const webhookRoutePath = resolveWebhookPath({
|
|
@@ -107,39 +71,24 @@ function resolveHostedZaloMediaRoutePath(params) {
|
|
|
107
71
|
return `${resolveHostedZaloMediaRoutePrefix(params)}/`;
|
|
108
72
|
}
|
|
109
73
|
async function prepareHostedZaloMediaUrl(params) {
|
|
110
|
-
await ensureHostedZaloMediaDir();
|
|
111
|
-
await cleanupExpiredHostedZaloMedia();
|
|
112
74
|
const now = asDateTimestampMs(Date.now());
|
|
113
|
-
|
|
114
|
-
if (expiresAt === void 0) throw new Error("Zalo outbound media expiry could not be resolved");
|
|
115
|
-
const media = await loadOutboundMediaFromUrl(params.mediaUrl, {
|
|
116
|
-
maxBytes: params.maxBytes,
|
|
117
|
-
...params.proxyUrl ? { proxyUrl: params.proxyUrl } : {}
|
|
118
|
-
});
|
|
75
|
+
if ((now === void 0 ? void 0 : resolveExpiresAtMsFromDurationMs(ZALO_OUTBOUND_MEDIA_TTL_MS, { nowMs: now })) === void 0) throw new Error("Zalo outbound media expiry could not be resolved");
|
|
119
76
|
const routePath = resolveHostedZaloMediaRoutePath({
|
|
120
77
|
webhookUrl: params.webhookUrl,
|
|
121
78
|
webhookPath: params.webhookPath
|
|
122
79
|
});
|
|
123
|
-
const id = createHostedZaloMediaId();
|
|
124
|
-
const token = createHostedZaloMediaToken();
|
|
125
80
|
const publicBaseUrl = new URL(params.webhookUrl).origin;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
expiresAt
|
|
134
|
-
});
|
|
135
|
-
} catch (error) {
|
|
136
|
-
await deleteHostedZaloMediaEntry(id);
|
|
137
|
-
throw error;
|
|
138
|
-
}
|
|
139
|
-
return `${publicBaseUrl}${routePath}${id}?token=${token}`;
|
|
81
|
+
return await getHostedZaloMediaStore().prepareUrl({
|
|
82
|
+
mediaUrl: params.mediaUrl,
|
|
83
|
+
routePath,
|
|
84
|
+
publicBaseUrl,
|
|
85
|
+
maxBytes: params.maxBytes,
|
|
86
|
+
...params.proxyUrl ? { proxyUrl: params.proxyUrl } : {}
|
|
87
|
+
});
|
|
140
88
|
}
|
|
141
89
|
async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
142
|
-
|
|
90
|
+
const store = getHostedZaloMediaStore();
|
|
91
|
+
await store.cleanupExpired();
|
|
143
92
|
const method = req.method ?? "GET";
|
|
144
93
|
if (method !== "GET" && method !== "HEAD") return false;
|
|
145
94
|
let url;
|
|
@@ -158,16 +107,22 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
|
158
107
|
res.end("Not Found");
|
|
159
108
|
return true;
|
|
160
109
|
}
|
|
161
|
-
const
|
|
110
|
+
const now = asDateTimestampMs(Date.now());
|
|
111
|
+
if (now === void 0) {
|
|
112
|
+
await store.delete(id);
|
|
113
|
+
res.statusCode = 410;
|
|
114
|
+
res.end("Expired");
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
const entry = await store.read(id, now);
|
|
162
118
|
if (!entry || entry.metadata.routePath !== routePath) {
|
|
163
119
|
res.statusCode = 404;
|
|
164
120
|
res.end("Not Found");
|
|
165
121
|
return true;
|
|
166
122
|
}
|
|
167
|
-
const now = asDateTimestampMs(Date.now());
|
|
168
123
|
const expiresAt = asDateTimestampMs(entry.metadata.expiresAt);
|
|
169
|
-
if (
|
|
170
|
-
await
|
|
124
|
+
if (expiresAt === void 0 || expiresAt <= now) {
|
|
125
|
+
await store.delete(id);
|
|
171
126
|
res.statusCode = 410;
|
|
172
127
|
res.end("Expired");
|
|
173
128
|
return true;
|
|
@@ -180,8 +135,7 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
|
180
135
|
if (entry.metadata.contentType) res.setHeader("Content-Type", entry.metadata.contentType);
|
|
181
136
|
res.setHeader("Cache-Control", "no-store");
|
|
182
137
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
183
|
-
|
|
184
|
-
if (bufferStats) res.setHeader("Content-Length", String(bufferStats.size));
|
|
138
|
+
res.setHeader("Content-Length", String(entry.metadata.byteLength));
|
|
185
139
|
if (method === "HEAD") {
|
|
186
140
|
res.statusCode = 200;
|
|
187
141
|
res.end();
|
|
@@ -189,7 +143,7 @@ async function tryHandleHostedZaloMediaRequest(req, res) {
|
|
|
189
143
|
}
|
|
190
144
|
res.statusCode = 200;
|
|
191
145
|
res.end(entry.buffer);
|
|
192
|
-
await
|
|
146
|
+
await store.delete(id);
|
|
193
147
|
return true;
|
|
194
148
|
}
|
|
195
149
|
//#endregion
|
|
@@ -201,7 +155,7 @@ const ZALO_TYPING_TIMEOUT_MS = 5e3;
|
|
|
201
155
|
let zaloWebhookModulePromise;
|
|
202
156
|
const hostedMediaRouteRefs = /* @__PURE__ */ new Map();
|
|
203
157
|
function loadZaloWebhookModule() {
|
|
204
|
-
zaloWebhookModulePromise ??= import("./monitor.webhook-
|
|
158
|
+
zaloWebhookModulePromise ??= import("./monitor.webhook-B23mUx-y.js");
|
|
205
159
|
return zaloWebhookModulePromise;
|
|
206
160
|
}
|
|
207
161
|
function registerSharedHostedMediaRoute(params) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/zalo",
|
|
3
|
-
"version": "2026.6.5-beta.
|
|
3
|
+
"version": "2026.6.5-beta.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/zalo",
|
|
9
|
-
"version": "2026.6.5-beta.
|
|
9
|
+
"version": "2026.6.5-beta.3",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"zod": "4.4.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"openclaw": ">=2026.6.5-beta.
|
|
14
|
+
"openclaw": ">=2026.6.5-beta.3"
|
|
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.6.5-beta.
|
|
3
|
+
"version": "2026.6.5-beta.3",
|
|
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.6.5-beta.
|
|
11
|
+
"openclaw": ">=2026.6.5-beta.3"
|
|
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.6.5-beta.
|
|
42
|
+
"pluginApi": ">=2026.6.5-beta.3"
|
|
43
43
|
},
|
|
44
44
|
"build": {
|
|
45
|
-
"openclawVersion": "2026.6.5-beta.
|
|
45
|
+
"openclawVersion": "2026.6.5-beta.3"
|
|
46
46
|
},
|
|
47
47
|
"release": {
|
|
48
48
|
"publishToClawHub": true,
|
|
@@ -1,6 +1,6 @@
|
|
|
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-CDwUY_-_.js";
|
|
2
|
-
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
3
2
|
import { createClaimableDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
3
|
+
import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
|
|
4
4
|
//#region extensions/zalo/src/monitor.webhook.ts
|
|
5
5
|
const ZALO_WEBHOOK_REPLAY_WINDOW_MS = 5 * 6e4;
|
|
6
6
|
const webhookTargets = /* @__PURE__ */ new Map();
|