@openclaw/zalo 2026.5.2 → 2026.5.3-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.
Files changed (87) hide show
  1. package/dist/accounts-9NLDDlZ8.js +118 -0
  2. package/dist/actions.runtime-kJ65ZxW7.js +5 -0
  3. package/dist/api.js +5 -0
  4. package/dist/channel-VPbtV3Oq.js +343 -0
  5. package/dist/channel-plugin-api.js +2 -0
  6. package/dist/channel.runtime-BnTAWQx5.js +106 -0
  7. package/dist/contract-api.js +3 -0
  8. package/dist/group-access-DZR43lOR.js +30 -0
  9. package/dist/index.js +22 -0
  10. package/dist/monitor-DMysJBWa.js +823 -0
  11. package/dist/monitor.webhook-DqnuvgjV.js +175 -0
  12. package/dist/proxy-CY8VuC6H.js +135 -0
  13. package/dist/runtime-BRFxnYQx.js +8 -0
  14. package/dist/runtime-api-MOTmRW4F.js +19 -0
  15. package/dist/runtime-api.js +3 -0
  16. package/dist/secret-contract-Dw93tGo2.js +87 -0
  17. package/dist/secret-contract-api.js +2 -0
  18. package/dist/send-Gv3l5EGI.js +101 -0
  19. package/dist/setup-api.js +30 -0
  20. package/dist/setup-core-DigRD3j1.js +166 -0
  21. package/dist/setup-entry.js +15 -0
  22. package/dist/setup-surface-2Up3yWov.js +216 -0
  23. package/dist/test-api.js +2 -0
  24. package/package.json +15 -6
  25. package/api.ts +0 -9
  26. package/channel-plugin-api.ts +0 -1
  27. package/contract-api.ts +0 -5
  28. package/index.test.ts +0 -15
  29. package/index.ts +0 -20
  30. package/runtime-api.test.ts +0 -17
  31. package/runtime-api.ts +0 -75
  32. package/secret-contract-api.ts +0 -5
  33. package/setup-api.ts +0 -34
  34. package/setup-entry.ts +0 -13
  35. package/src/accounts.test.ts +0 -70
  36. package/src/accounts.ts +0 -60
  37. package/src/actions.runtime.ts +0 -5
  38. package/src/actions.test.ts +0 -32
  39. package/src/actions.ts +0 -62
  40. package/src/api.test.ts +0 -149
  41. package/src/api.ts +0 -265
  42. package/src/approval-auth.test.ts +0 -17
  43. package/src/approval-auth.ts +0 -25
  44. package/src/channel.directory.test.ts +0 -59
  45. package/src/channel.runtime.ts +0 -93
  46. package/src/channel.startup.test.ts +0 -101
  47. package/src/channel.ts +0 -275
  48. package/src/config-schema.test.ts +0 -30
  49. package/src/config-schema.ts +0 -29
  50. package/src/group-access.ts +0 -49
  51. package/src/monitor.group-policy.test.ts +0 -94
  52. package/src/monitor.image.polling.test.ts +0 -110
  53. package/src/monitor.lifecycle.test.ts +0 -198
  54. package/src/monitor.pairing.lifecycle.test.ts +0 -141
  55. package/src/monitor.polling.media-reply.test.ts +0 -425
  56. package/src/monitor.reply-once.lifecycle.test.ts +0 -171
  57. package/src/monitor.ts +0 -1028
  58. package/src/monitor.types.ts +0 -4
  59. package/src/monitor.webhook.test.ts +0 -806
  60. package/src/monitor.webhook.ts +0 -278
  61. package/src/outbound-media.test.ts +0 -182
  62. package/src/outbound-media.ts +0 -241
  63. package/src/outbound-payload.contract.test.ts +0 -45
  64. package/src/probe.ts +0 -45
  65. package/src/proxy.ts +0 -24
  66. package/src/runtime-api.ts +0 -75
  67. package/src/runtime-support.ts +0 -91
  68. package/src/runtime.ts +0 -9
  69. package/src/secret-contract.ts +0 -109
  70. package/src/secret-input.ts +0 -5
  71. package/src/send.test.ts +0 -120
  72. package/src/send.ts +0 -153
  73. package/src/session-route.ts +0 -32
  74. package/src/setup-allow-from.ts +0 -94
  75. package/src/setup-core.ts +0 -149
  76. package/src/setup-status.test.ts +0 -33
  77. package/src/setup-surface.test.ts +0 -175
  78. package/src/setup-surface.ts +0 -291
  79. package/src/status-issues.test.ts +0 -17
  80. package/src/status-issues.ts +0 -37
  81. package/src/test-support/lifecycle-test-support.ts +0 -413
  82. package/src/test-support/monitor-mocks-test-support.ts +0 -209
  83. package/src/token.test.ts +0 -92
  84. package/src/token.ts +0 -79
  85. package/src/types.ts +0 -50
  86. package/test-api.ts +0 -1
  87. package/tsconfig.json +0 -16
@@ -1,32 +0,0 @@
1
- import {
2
- buildChannelOutboundSessionRoute,
3
- stripChannelTargetPrefix,
4
- stripTargetKindPrefix,
5
- type ChannelOutboundSessionRouteParams,
6
- } from "openclaw/plugin-sdk/core";
7
- import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
8
-
9
- export function resolveZaloOutboundSessionRoute(params: ChannelOutboundSessionRouteParams) {
10
- const trimmed = stripChannelTargetPrefix(params.target, "zalo", "zl");
11
- if (!trimmed) {
12
- return null;
13
- }
14
- const isGroup = normalizeLowercaseStringOrEmpty(trimmed).startsWith("group:");
15
- const peerId = stripTargetKindPrefix(trimmed);
16
- if (!peerId) {
17
- return null;
18
- }
19
- return buildChannelOutboundSessionRoute({
20
- cfg: params.cfg,
21
- agentId: params.agentId,
22
- channel: "zalo",
23
- accountId: params.accountId,
24
- peer: {
25
- kind: isGroup ? "group" : "direct",
26
- id: peerId,
27
- },
28
- chatType: isGroup ? "group" : "direct",
29
- from: isGroup ? `zalo:group:${peerId}` : `zalo:${peerId}`,
30
- to: `zalo:${peerId}`,
31
- });
32
- }
@@ -1,94 +0,0 @@
1
- import {
2
- DEFAULT_ACCOUNT_ID,
3
- formatDocsLink,
4
- mergeAllowFromEntries,
5
- type ChannelSetupDmPolicy,
6
- type ChannelSetupWizard,
7
- type OpenClawConfig,
8
- } from "openclaw/plugin-sdk/setup";
9
- import { resolveDefaultZaloAccountId, resolveZaloAccount } from "./accounts.js";
10
-
11
- type ZaloAccountSetupConfig = {
12
- enabled?: boolean;
13
- };
14
-
15
- export async function noteZaloTokenHelp(
16
- prompter: Parameters<NonNullable<ChannelSetupWizard["finalize"]>>[0]["prompter"],
17
- ): Promise<void> {
18
- await prompter.note(
19
- [
20
- "1) Open Zalo Bot Platform: https://bot.zaloplatforms.com",
21
- "2) Create a bot and get the token",
22
- "3) Token looks like 12345689:abc-xyz",
23
- "Tip: you can also set ZALO_BOT_TOKEN in your env.",
24
- `Docs: ${formatDocsLink("/channels/zalo", "zalo")}`,
25
- ].join("\n"),
26
- "Zalo bot token",
27
- );
28
- }
29
-
30
- export async function promptZaloAllowFrom(params: {
31
- cfg: OpenClawConfig;
32
- prompter: Parameters<NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]>>[0]["prompter"];
33
- accountId?: string;
34
- }): Promise<OpenClawConfig> {
35
- const { cfg, prompter } = params;
36
- const accountId = params.accountId ?? resolveDefaultZaloAccountId(cfg);
37
- const resolved = resolveZaloAccount({ cfg, accountId });
38
- const existingAllowFrom = resolved.config.allowFrom ?? [];
39
- const entry = await prompter.text({
40
- message: "Zalo allowFrom (user id)",
41
- placeholder: "123456789",
42
- initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
43
- validate: (value) => {
44
- const raw = (value ?? "").trim();
45
- if (!raw) {
46
- return "Required";
47
- }
48
- if (!/^\d+$/.test(raw)) {
49
- return "Use a numeric Zalo user id";
50
- }
51
- return undefined;
52
- },
53
- });
54
- const normalized = entry.trim();
55
- const unique = mergeAllowFromEntries(existingAllowFrom, [normalized]);
56
-
57
- if (accountId === DEFAULT_ACCOUNT_ID) {
58
- return {
59
- ...cfg,
60
- channels: {
61
- ...cfg.channels,
62
- zalo: {
63
- ...cfg.channels?.zalo,
64
- enabled: true,
65
- dmPolicy: "allowlist",
66
- allowFrom: unique,
67
- },
68
- },
69
- } as OpenClawConfig;
70
- }
71
-
72
- const currentAccount = cfg.channels?.zalo?.accounts?.[accountId] as
73
- | ZaloAccountSetupConfig
74
- | undefined;
75
- return {
76
- ...cfg,
77
- channels: {
78
- ...cfg.channels,
79
- zalo: {
80
- ...cfg.channels?.zalo,
81
- enabled: true,
82
- accounts: {
83
- ...cfg.channels?.zalo?.accounts,
84
- [accountId]: {
85
- ...currentAccount,
86
- enabled: currentAccount?.enabled ?? true,
87
- dmPolicy: "allowlist",
88
- allowFrom: unique,
89
- },
90
- },
91
- },
92
- },
93
- } as OpenClawConfig;
94
- }
package/src/setup-core.ts DELETED
@@ -1,149 +0,0 @@
1
- import {
2
- addWildcardAllowFrom,
3
- createDelegatedSetupWizardProxy,
4
- createPatchedAccountSetupAdapter,
5
- createSetupInputPresenceValidator,
6
- DEFAULT_ACCOUNT_ID,
7
- normalizeAccountId,
8
- type ChannelSetupDmPolicy,
9
- type ChannelSetupWizard,
10
- } from "openclaw/plugin-sdk/setup";
11
- import { resolveDefaultZaloAccountId, resolveZaloAccount } from "./accounts.js";
12
- import { promptZaloAllowFrom } from "./setup-allow-from.js";
13
-
14
- const channel = "zalo" as const;
15
-
16
- type ZaloAccountSetupConfig = {
17
- enabled?: boolean;
18
- dmPolicy?: string;
19
- allowFrom?: Array<string | number> | ReadonlyArray<string | number>;
20
- };
21
-
22
- export const zaloSetupAdapter = createPatchedAccountSetupAdapter({
23
- channelKey: channel,
24
- validateInput: createSetupInputPresenceValidator({
25
- defaultAccountOnlyEnvError: "ZALO_BOT_TOKEN can only be used for the default account.",
26
- whenNotUseEnv: [
27
- {
28
- someOf: ["token", "tokenFile"],
29
- message: "Zalo requires token or --token-file (or --use-env).",
30
- },
31
- ],
32
- }),
33
- buildPatch: (input) =>
34
- input.useEnv
35
- ? {}
36
- : input.tokenFile
37
- ? { tokenFile: input.tokenFile }
38
- : input.token
39
- ? { botToken: input.token }
40
- : {},
41
- });
42
-
43
- export const zaloDmPolicy: ChannelSetupDmPolicy = {
44
- label: "Zalo",
45
- channel,
46
- policyKey: "channels.zalo.dmPolicy",
47
- allowFromKey: "channels.zalo.allowFrom",
48
- resolveConfigKeys: (cfg, accountId) =>
49
- (accountId ?? resolveDefaultZaloAccountId(cfg)) !== DEFAULT_ACCOUNT_ID
50
- ? {
51
- policyKey: `channels.zalo.accounts.${accountId ?? resolveDefaultZaloAccountId(cfg)}.dmPolicy`,
52
- allowFromKey: `channels.zalo.accounts.${accountId ?? resolveDefaultZaloAccountId(cfg)}.allowFrom`,
53
- }
54
- : {
55
- policyKey: "channels.zalo.dmPolicy",
56
- allowFromKey: "channels.zalo.allowFrom",
57
- },
58
- getCurrent: (cfg, accountId) =>
59
- resolveZaloAccount({
60
- cfg: cfg,
61
- accountId: accountId ?? resolveDefaultZaloAccountId(cfg),
62
- }).config.dmPolicy ?? "pairing",
63
- setPolicy: (cfg, policy, accountId) => {
64
- const resolvedAccountId =
65
- accountId && normalizeAccountId(accountId)
66
- ? (normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID)
67
- : resolveDefaultZaloAccountId(cfg);
68
- const resolved = resolveZaloAccount({
69
- cfg: cfg,
70
- accountId: resolvedAccountId,
71
- });
72
- if (resolvedAccountId === DEFAULT_ACCOUNT_ID) {
73
- return {
74
- ...cfg,
75
- channels: {
76
- ...cfg.channels,
77
- zalo: {
78
- ...cfg.channels?.zalo,
79
- enabled: true,
80
- dmPolicy: policy,
81
- ...(policy === "open"
82
- ? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) }
83
- : {}),
84
- },
85
- },
86
- };
87
- }
88
- const currentAccount = cfg.channels?.zalo?.accounts?.[resolvedAccountId] as
89
- | ZaloAccountSetupConfig
90
- | undefined;
91
- return {
92
- ...cfg,
93
- channels: {
94
- ...cfg.channels,
95
- zalo: {
96
- ...cfg.channels?.zalo,
97
- enabled: true,
98
- accounts: {
99
- ...cfg.channels?.zalo?.accounts,
100
- [resolvedAccountId]: {
101
- ...currentAccount,
102
- enabled: currentAccount?.enabled ?? true,
103
- dmPolicy: policy,
104
- ...(policy === "open"
105
- ? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) }
106
- : {}),
107
- },
108
- },
109
- },
110
- },
111
- };
112
- },
113
- promptAllowFrom: async ({ cfg, prompter, accountId }) =>
114
- promptZaloAllowFrom({
115
- cfg,
116
- prompter,
117
- accountId: accountId ?? resolveDefaultZaloAccountId(cfg),
118
- }),
119
- };
120
-
121
- export function createZaloSetupWizardProxy(
122
- loadWizard: () => Promise<ChannelSetupWizard>,
123
- ): ChannelSetupWizard {
124
- return createDelegatedSetupWizardProxy({
125
- channel,
126
- loadWizard,
127
- status: {
128
- configuredLabel: "configured",
129
- unconfiguredLabel: "needs token",
130
- configuredHint: "recommended · configured",
131
- unconfiguredHint: "recommended · newcomer-friendly",
132
- configuredScore: 1,
133
- unconfiguredScore: 10,
134
- },
135
- credentials: [],
136
- delegateFinalize: true,
137
- dmPolicy: zaloDmPolicy,
138
- disable: (cfg) => ({
139
- ...cfg,
140
- channels: {
141
- ...cfg.channels,
142
- zalo: {
143
- ...cfg.channels?.zalo,
144
- enabled: false,
145
- },
146
- },
147
- }),
148
- });
149
- }
@@ -1,33 +0,0 @@
1
- import { createPluginSetupWizardStatus } from "openclaw/plugin-sdk/plugin-test-runtime";
2
- import { describe, expect, it } from "vitest";
3
- import type { OpenClawConfig } from "../runtime-api.js";
4
- import { zaloSetupWizard } from "./setup-surface.js";
5
-
6
- const zaloGetStatus = createPluginSetupWizardStatus({
7
- id: "zalo",
8
- meta: {
9
- label: "Zalo",
10
- },
11
- setupWizard: zaloSetupWizard,
12
- } as never);
13
-
14
- describe("zalo setup wizard status", () => {
15
- it("treats SecretRef botToken as configured", async () => {
16
- const status = await zaloGetStatus({
17
- cfg: {
18
- channels: {
19
- zalo: {
20
- botToken: {
21
- source: "env",
22
- provider: "default",
23
- id: "ZALO_BOT_TOKEN",
24
- },
25
- },
26
- },
27
- } as OpenClawConfig,
28
- accountOverrides: {},
29
- });
30
-
31
- expect(status.configured).toBe(true);
32
- });
33
- });
@@ -1,175 +0,0 @@
1
- import { adaptScopedAccountAccessor } from "openclaw/plugin-sdk/channel-config-helpers";
2
- import {
3
- createPluginSetupWizardConfigure,
4
- createTestWizardPrompter,
5
- runSetupWizardConfigure,
6
- } from "openclaw/plugin-sdk/plugin-test-runtime";
7
- import type { WizardPrompter } from "openclaw/plugin-sdk/plugin-test-runtime";
8
- import { describe, expect, it, vi } from "vitest";
9
- import type { OpenClawConfig } from "../runtime-api.js";
10
- import { listZaloAccountIds, resolveDefaultZaloAccountId, resolveZaloAccount } from "./accounts.js";
11
- import { zaloDmPolicy } from "./setup-core.js";
12
- import { zaloSetupAdapter, zaloSetupWizard } from "./setup-surface.js";
13
-
14
- const zaloSetupPlugin = {
15
- id: "zalo",
16
- meta: {
17
- id: "zalo",
18
- label: "Zalo",
19
- selectionLabel: "Zalo (Bot API)",
20
- docsPath: "/channels/zalo",
21
- blurb: "Vietnam-focused messaging platform with Bot API.",
22
- },
23
- capabilities: {
24
- chatTypes: ["direct", "group"] as Array<"direct" | "group">,
25
- },
26
- config: {
27
- listAccountIds: (cfg: unknown) => listZaloAccountIds(cfg as never),
28
- defaultAccountId: (cfg: unknown) => resolveDefaultZaloAccountId(cfg as never),
29
- resolveAccount: adaptScopedAccountAccessor(resolveZaloAccount),
30
- },
31
- setup: zaloSetupAdapter,
32
- setupWizard: zaloSetupWizard,
33
- } as const;
34
-
35
- const zaloConfigure = createPluginSetupWizardConfigure(zaloSetupPlugin);
36
-
37
- describe("zalo setup wizard", () => {
38
- it("configures a polling token flow", async () => {
39
- const prompter = createTestWizardPrompter({
40
- select: vi.fn(async () => "plaintext") as WizardPrompter["select"],
41
- text: vi.fn(async ({ message }: { message: string }) => {
42
- if (message === "Enter Zalo bot token") {
43
- return "12345689:abc-xyz";
44
- }
45
- throw new Error(`Unexpected prompt: ${message}`);
46
- }) as WizardPrompter["text"],
47
- confirm: vi.fn(async ({ message }: { message: string }) => {
48
- if (message === "Use webhook mode for Zalo?") {
49
- return false;
50
- }
51
- return false;
52
- }),
53
- });
54
-
55
- const result = await runSetupWizardConfigure({
56
- configure: zaloConfigure,
57
- cfg: {} as OpenClawConfig,
58
- prompter,
59
- options: { secretInputMode: "plaintext" as const },
60
- });
61
-
62
- expect(result.accountId).toBe("default");
63
- expect(result.cfg.channels?.zalo?.enabled).toBe(true);
64
- expect(result.cfg.channels?.zalo?.botToken).toBe("12345689:abc-xyz");
65
- expect(result.cfg.channels?.zalo?.webhookUrl).toBeUndefined();
66
- });
67
-
68
- it("reads the named-account DM policy instead of the channel root", () => {
69
- expect(
70
- zaloDmPolicy.getCurrent(
71
- {
72
- channels: {
73
- zalo: {
74
- dmPolicy: "disabled",
75
- accounts: {
76
- work: {
77
- botToken: "12345689:abc-xyz",
78
- dmPolicy: "allowlist",
79
- },
80
- },
81
- },
82
- },
83
- } as OpenClawConfig,
84
- "work",
85
- ),
86
- ).toBe("allowlist");
87
- });
88
-
89
- it("reports account-scoped config keys for named accounts", () => {
90
- expect(zaloDmPolicy.resolveConfigKeys?.({} as OpenClawConfig, "work")).toEqual({
91
- policyKey: "channels.zalo.accounts.work.dmPolicy",
92
- allowFromKey: "channels.zalo.accounts.work.allowFrom",
93
- });
94
- });
95
-
96
- it("uses configured defaultAccount for omitted DM policy account context", () => {
97
- const cfg = {
98
- channels: {
99
- zalo: {
100
- defaultAccount: "work",
101
- dmPolicy: "disabled",
102
- allowFrom: ["123456789"],
103
- accounts: {
104
- work: {
105
- botToken: "12345689:abc-xyz",
106
- dmPolicy: "allowlist",
107
- },
108
- },
109
- },
110
- },
111
- } as OpenClawConfig;
112
-
113
- expect(zaloDmPolicy.getCurrent(cfg)).toBe("allowlist");
114
- expect(zaloDmPolicy.resolveConfigKeys?.(cfg)).toEqual({
115
- policyKey: "channels.zalo.accounts.work.dmPolicy",
116
- allowFromKey: "channels.zalo.accounts.work.allowFrom",
117
- });
118
-
119
- const next = zaloDmPolicy.setPolicy(cfg, "open");
120
- expect(next.channels?.zalo?.dmPolicy).toBe("disabled");
121
- const workAccount = next.channels?.zalo?.accounts?.work as
122
- | { dmPolicy?: string; allowFrom?: Array<string | number> }
123
- | undefined;
124
- expect(workAccount?.dmPolicy).toBe("open");
125
- });
126
-
127
- it('writes open policy state to the named account and preserves inherited allowFrom with "*"', () => {
128
- const next = zaloDmPolicy.setPolicy(
129
- {
130
- channels: {
131
- zalo: {
132
- allowFrom: ["123456789"],
133
- accounts: {
134
- work: {
135
- botToken: "12345689:abc-xyz",
136
- },
137
- },
138
- },
139
- },
140
- } as OpenClawConfig,
141
- "open",
142
- "work",
143
- );
144
-
145
- expect(next.channels?.zalo?.dmPolicy).toBeUndefined();
146
- const workAccount = next.channels?.zalo?.accounts?.work as
147
- | { dmPolicy?: string; allowFrom?: Array<string | number> }
148
- | undefined;
149
- expect(workAccount?.dmPolicy).toBe("open");
150
- expect(workAccount?.allowFrom).toEqual(["123456789", "*"]);
151
- });
152
-
153
- it("uses configured defaultAccount for omitted setup configured state", async () => {
154
- const configured = await zaloSetupWizard.status.resolveConfigured({
155
- cfg: {
156
- channels: {
157
- zalo: {
158
- defaultAccount: "work",
159
- botToken: "root-token",
160
- accounts: {
161
- alerts: {
162
- botToken: "alerts-token",
163
- },
164
- work: {
165
- botToken: "",
166
- },
167
- },
168
- },
169
- },
170
- } as OpenClawConfig,
171
- });
172
-
173
- expect(configured).toBe(false);
174
- });
175
- });