@openclaw/zalo 2026.7.2-beta.7 → 2026.7.33

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,121 +0,0 @@
1
- import { t as getZaloRuntime } from "./runtime-api-qxdOyk3M.js";
2
- import { r as ZaloApiError } from "./send-BUvbbedq.js";
3
- import { DEFAULT_INGRESS_ADOPTION_STALL_MS, DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS, bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor } from "openclaw/plugin-sdk/channel-outbound";
4
- import { normalizeNullableString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
- import { isRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
6
- import { runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
7
- //#region extensions/zalo/src/webhook-spool.ts
8
- const ZALO_WEBHOOK_SPOOL_VERSION = 1;
9
- const ZALO_WEBHOOK_DRAIN_INTERVAL_MS = 500;
10
- const ZALO_WEBHOOK_MAX_CONCURRENT_DELIVERIES = 8;
11
- const ZaloWebhookPayloadError = createChannelIngressError("ZaloWebhookPayloadError");
12
- function parseRawRecord(rawEvent) {
13
- let parsed;
14
- try {
15
- parsed = JSON.parse(rawEvent);
16
- } catch (error) {
17
- throw new ZaloWebhookPayloadError("Zalo webhook body contains invalid JSON.", { cause: error });
18
- }
19
- if (!isRecord(parsed)) throw new ZaloWebhookPayloadError("Zalo webhook body must be a JSON object.");
20
- return parsed;
21
- }
22
- function resolveUpdateRecord(envelope) {
23
- if (envelope.ok === true && isRecord(envelope.result)) return envelope.result;
24
- return envelope;
25
- }
26
- function inspectZaloWebhookEvent(rawEvent) {
27
- const update = resolveUpdateRecord(parseRawRecord(rawEvent));
28
- const message = isRecord(update.message) ? update.message : null;
29
- const eventId = normalizeNullableString(message?.message_id);
30
- if (!eventId) throw new ZaloWebhookPayloadError("Zalo webhook message is missing message.message_id.");
31
- const chatId = normalizeNullableString((isRecord(message?.chat) ? message.chat : null)?.id);
32
- if (!chatId) throw new ZaloWebhookPayloadError("Zalo webhook message is missing message.chat.id.");
33
- return {
34
- eventId,
35
- laneKey: `chat:${chatId}`,
36
- update
37
- };
38
- }
39
- function parseClaimedUpdate(payload, claimedId) {
40
- if (payload.version !== ZALO_WEBHOOK_SPOOL_VERSION || typeof payload.rawEvent !== "string") throw new ZaloWebhookPayloadError("Zalo webhook spool payload is invalid.");
41
- const facts = inspectZaloWebhookEvent(payload.rawEvent);
42
- if (facts.eventId !== claimedId) throw new ZaloWebhookPayloadError("Zalo webhook message id changed after durable admission.");
43
- const eventName = normalizeNullableString(facts.update.event_name);
44
- if (eventName !== "message.text.received" && eventName !== "message.image.received" && eventName !== "message.sticker.received" && eventName !== "message.unsupported.received") throw new ZaloWebhookPayloadError("Zalo webhook event_name is unsupported.");
45
- const message = facts.update.message;
46
- const from = isRecord(message.from) ? message.from : null;
47
- const chat = isRecord(message.chat) ? message.chat : null;
48
- if (!normalizeNullableString(from?.id)) throw new ZaloWebhookPayloadError("Zalo webhook message is missing message.from.id.");
49
- if (chat?.chat_type !== "PRIVATE" && chat?.chat_type !== "GROUP") throw new ZaloWebhookPayloadError("Zalo webhook message has an invalid chat type.");
50
- if (typeof message.date !== "number" || !Number.isFinite(message.date)) throw new ZaloWebhookPayloadError("Zalo webhook message has an invalid date.");
51
- if (eventName === "message.text.received" && typeof message.text !== "string") throw new ZaloWebhookPayloadError("Zalo text event is missing message.text.");
52
- return facts.update;
53
- }
54
- function errorText(error) {
55
- return error instanceof Error ? error.message : String(error);
56
- }
57
- function isZaloAuthenticationFailure(error) {
58
- let current = error;
59
- const seen = /* @__PURE__ */ new Set();
60
- while (current && typeof current === "object" && !seen.has(current)) {
61
- seen.add(current);
62
- const candidate = current;
63
- if (current instanceof ZaloApiError && (current.errorCode === 401 || current.errorCode === 403) || candidate.status === 401 || candidate.status === 403 || candidate.statusCode === 401 || candidate.statusCode === 403) return true;
64
- current = candidate.cause;
65
- }
66
- return false;
67
- }
68
- function createZaloWebhookIngress(options) {
69
- const monitor = createChannelIngressMonitor({
70
- queue: options.queue ?? getZaloRuntime().state.openChannelIngressQueue({ accountId: options.accountId }),
71
- inspect: (rawEvent) => inspectZaloWebhookEvent(rawEvent),
72
- payload: {
73
- storage: "raw-event",
74
- version: ZALO_WEBHOOK_SPOOL_VERSION,
75
- serialize: (rawEvent) => rawEvent,
76
- deserialize: (rawEvent) => rawEvent,
77
- createClaimError: (kind) => new ZaloWebhookPayloadError(kind === "invalid-version" ? "Zalo webhook spool payload is invalid." : "Zalo webhook identity changed after durable admission.")
78
- },
79
- deliver: async (_rawEvent, lifecycle, claim) => {
80
- const update = parseClaimedUpdate(claim.payload, claim.id);
81
- await options.deliver(update, bindIngressLifecycleToReplyOptions(lifecycle).turnAdoptionLifecycle);
82
- },
83
- pollIntervalMs: ZALO_WEBHOOK_DRAIN_INTERVAL_MS,
84
- retention: { failedMaxEntries: 5e3 },
85
- waitForDeliveryIdleBeforeRepump: false,
86
- runPumpTask: runDetachedWebhookWork,
87
- deferredClaims: "wait-on-stop",
88
- drain: {
89
- adoptionStallTimeoutMs: DEFAULT_INGRESS_ADOPTION_STALL_MS,
90
- startLimit: ZALO_WEBHOOK_MAX_CONCURRENT_DELIVERIES,
91
- retryPolicy: {
92
- maxAttempts: DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS,
93
- deadLetterMinAgeMs: 0
94
- },
95
- resolveNonRetryableFailure: (error) => {
96
- if (error instanceof ZaloWebhookPayloadError) return {
97
- reason: "invalid-event",
98
- message: error.message
99
- };
100
- if (isZaloAuthenticationFailure(error)) return {
101
- reason: "authentication-failed",
102
- message: errorText(error)
103
- };
104
- return null;
105
- },
106
- onLog: (message) => options.runtime.error?.(`zalo ingress: ${message}`)
107
- },
108
- createStoppedError: () => /* @__PURE__ */ new Error("Zalo ingress stopped."),
109
- onError: (error) => options.runtime.error?.(`zalo ingress drain failed: ${errorText(error)}`)
110
- });
111
- return {
112
- accept: async (rawEvent) => {
113
- await monitor.admit(rawEvent);
114
- },
115
- start: monitor.start,
116
- stop: monitor.stop
117
- };
118
- }
119
- const zaloWebhookIngressRuntime = { createZaloWebhookIngress };
120
- //#endregion
121
- export { ZaloWebhookPayloadError, zaloWebhookIngressRuntime };