@kodelyth/zalo 2026.5.39 → 2026.5.42

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 (97) hide show
  1. package/README.md +50 -0
  2. package/api.ts +8 -0
  3. package/channel-plugin-api.ts +1 -0
  4. package/contract-api.ts +5 -0
  5. package/dist/actions.runtime-C61oPfyd.js +5 -0
  6. package/dist/api.js +5 -0
  7. package/dist/channel-D8ylaEdN.js +367 -0
  8. package/dist/channel-plugin-api.js +2 -0
  9. package/dist/channel.runtime-sf-rx5n-.js +105 -0
  10. package/dist/contract-api.js +3 -0
  11. package/dist/group-access-DTQVR6Nd.js +15 -0
  12. package/dist/index.js +22 -0
  13. package/dist/monitor-CQ1bjGih.js +825 -0
  14. package/dist/monitor.webhook-CDxUxa9l.js +175 -0
  15. package/dist/runtime-api-CxXTp1Q2.js +23 -0
  16. package/dist/runtime-api.js +2 -0
  17. package/dist/secret-contract-CRFukr2n.js +87 -0
  18. package/dist/secret-contract-api.js +2 -0
  19. package/dist/send-CGAqdfSA.js +270 -0
  20. package/dist/setup-api.js +30 -0
  21. package/dist/setup-core-Dr75wK6l.js +287 -0
  22. package/dist/setup-entry.js +15 -0
  23. package/dist/setup-surface-C8zxrnzG.js +216 -0
  24. package/dist/test-api.js +2 -0
  25. package/index.test.ts +15 -0
  26. package/index.ts +20 -0
  27. package/klaw.plugin.json +2 -509
  28. package/package.json +4 -4
  29. package/runtime-api.test.ts +10 -0
  30. package/runtime-api.ts +71 -0
  31. package/secret-contract-api.ts +5 -0
  32. package/setup-api.ts +34 -0
  33. package/setup-entry.ts +13 -0
  34. package/src/accounts.test.ts +95 -0
  35. package/src/accounts.ts +65 -0
  36. package/src/actions.runtime.ts +5 -0
  37. package/src/actions.test.ts +32 -0
  38. package/src/actions.ts +62 -0
  39. package/src/api.test.ts +166 -0
  40. package/src/api.ts +265 -0
  41. package/src/approval-auth.test.ts +17 -0
  42. package/src/approval-auth.ts +25 -0
  43. package/src/channel.directory.test.ts +56 -0
  44. package/src/channel.runtime.ts +89 -0
  45. package/src/channel.startup.test.ts +121 -0
  46. package/src/channel.ts +309 -0
  47. package/src/config-schema.test.ts +30 -0
  48. package/src/config-schema.ts +29 -0
  49. package/src/group-access.ts +23 -0
  50. package/src/monitor-durable.test.ts +49 -0
  51. package/src/monitor-durable.ts +38 -0
  52. package/src/monitor.group-policy.test.ts +213 -0
  53. package/src/monitor.image.polling.test.ts +113 -0
  54. package/src/monitor.lifecycle.test.ts +194 -0
  55. package/src/monitor.pairing.lifecycle.test.ts +139 -0
  56. package/src/monitor.polling.media-reply.test.ts +433 -0
  57. package/src/monitor.reply-once.lifecycle.test.ts +178 -0
  58. package/src/monitor.ts +1009 -0
  59. package/src/monitor.types.ts +4 -0
  60. package/src/monitor.webhook.test.ts +808 -0
  61. package/src/monitor.webhook.ts +278 -0
  62. package/src/outbound-media.test.ts +186 -0
  63. package/src/outbound-media.ts +236 -0
  64. package/src/outbound-payload.contract.test.ts +143 -0
  65. package/src/probe.ts +45 -0
  66. package/src/proxy.ts +18 -0
  67. package/src/runtime-api.ts +71 -0
  68. package/src/runtime-support.ts +82 -0
  69. package/src/runtime.ts +9 -0
  70. package/src/secret-contract.ts +109 -0
  71. package/src/secret-input.ts +5 -0
  72. package/src/send.test.ts +150 -0
  73. package/src/send.ts +207 -0
  74. package/src/session-route.ts +32 -0
  75. package/src/setup-allow-from.ts +97 -0
  76. package/src/setup-core.ts +152 -0
  77. package/src/setup-status.test.ts +33 -0
  78. package/src/setup-surface.test.ts +193 -0
  79. package/src/setup-surface.ts +294 -0
  80. package/src/status-issues.test.ts +17 -0
  81. package/src/status-issues.ts +34 -0
  82. package/src/test-support/lifecycle-test-support.ts +456 -0
  83. package/src/test-support/monitor-mocks-test-support.ts +209 -0
  84. package/src/token.test.ts +92 -0
  85. package/src/token.ts +79 -0
  86. package/src/types.ts +50 -0
  87. package/test-api.ts +1 -0
  88. package/tsconfig.json +16 -0
  89. package/api.js +0 -7
  90. package/channel-plugin-api.js +0 -7
  91. package/contract-api.js +0 -7
  92. package/index.js +0 -7
  93. package/runtime-api.js +0 -7
  94. package/secret-contract-api.js +0 -7
  95. package/setup-api.js +0 -7
  96. package/setup-entry.js +0 -7
  97. package/test-api.js +0 -7
@@ -0,0 +1,287 @@
1
+ import { createAccountListHelpers, resolveMergedAccountConfig } from "klaw/plugin-sdk/account-helpers";
2
+ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "klaw/plugin-sdk/account-id";
3
+ import { normalizeOptionalString } from "klaw/plugin-sdk/string-coerce-runtime";
4
+ import { tryReadSecretFileSync } from "klaw/plugin-sdk/core";
5
+ import { resolveAccountEntry } from "klaw/plugin-sdk/routing";
6
+ import { buildSecretInputSchema, normalizeResolvedSecretInputString, normalizeSecretInputString } from "klaw/plugin-sdk/secret-input";
7
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, addWildcardAllowFrom, createDelegatedSetupWizardProxy, createPatchedAccountSetupAdapter, createSetupInputPresenceValidator, createSetupTranslator, formatDocsLink, mergeAllowFromEntries, normalizeAccountId as normalizeAccountId$1 } from "klaw/plugin-sdk/setup";
8
+ //#region \0rolldown/runtime.js
9
+ var __defProp = Object.defineProperty;
10
+ var __exportAll = (all, no_symbols) => {
11
+ let target = {};
12
+ for (var name in all) __defProp(target, name, {
13
+ get: all[name],
14
+ enumerable: true
15
+ });
16
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
17
+ return target;
18
+ };
19
+ //#endregion
20
+ //#region extensions/zalo/src/token.ts
21
+ function readTokenFromFile(tokenFile) {
22
+ return tryReadSecretFileSync(tokenFile, "Zalo token file", { rejectSymlink: true }) ?? "";
23
+ }
24
+ function resolveZaloToken(config, accountId, options) {
25
+ const resolvedAccountId = normalizeAccountId(accountId ?? config?.defaultAccount);
26
+ const isDefaultAccount = resolvedAccountId === DEFAULT_ACCOUNT_ID;
27
+ const baseConfig = config;
28
+ const accountConfig = resolveAccountEntry(baseConfig?.accounts, normalizeAccountId(resolvedAccountId));
29
+ const accountHasBotToken = Boolean(accountConfig && Object.prototype.hasOwnProperty.call(accountConfig, "botToken"));
30
+ if (accountConfig && accountHasBotToken) {
31
+ const token = options?.allowUnresolvedSecretRef ? normalizeSecretInputString(accountConfig.botToken) : normalizeResolvedSecretInputString({
32
+ value: accountConfig.botToken,
33
+ path: `channels.zalo.accounts.${resolvedAccountId}.botToken`
34
+ });
35
+ if (token) return {
36
+ token,
37
+ source: "config"
38
+ };
39
+ const fileToken = readTokenFromFile(accountConfig.tokenFile);
40
+ if (fileToken) return {
41
+ token: fileToken,
42
+ source: "configFile"
43
+ };
44
+ }
45
+ if (!accountHasBotToken) {
46
+ const fileToken = readTokenFromFile(accountConfig?.tokenFile);
47
+ if (fileToken) return {
48
+ token: fileToken,
49
+ source: "configFile"
50
+ };
51
+ }
52
+ if (!accountHasBotToken) {
53
+ const token = options?.allowUnresolvedSecretRef ? normalizeSecretInputString(baseConfig?.botToken) : normalizeResolvedSecretInputString({
54
+ value: baseConfig?.botToken,
55
+ path: "channels.zalo.botToken"
56
+ });
57
+ if (token) return {
58
+ token,
59
+ source: "config"
60
+ };
61
+ const fileToken = readTokenFromFile(baseConfig?.tokenFile);
62
+ if (fileToken) return {
63
+ token: fileToken,
64
+ source: "configFile"
65
+ };
66
+ }
67
+ if (isDefaultAccount) {
68
+ const envToken = process.env.ZALO_BOT_TOKEN?.trim();
69
+ if (envToken) return {
70
+ token: envToken,
71
+ source: "env"
72
+ };
73
+ }
74
+ return {
75
+ token: "",
76
+ source: "none"
77
+ };
78
+ }
79
+ //#endregion
80
+ //#region extensions/zalo/src/accounts.ts
81
+ var accounts_exports = /* @__PURE__ */ __exportAll({
82
+ listEnabledZaloAccounts: () => listEnabledZaloAccounts,
83
+ listZaloAccountIds: () => listZaloAccountIds,
84
+ resolveDefaultZaloAccountId: () => resolveDefaultZaloAccountId,
85
+ resolveZaloAccount: () => resolveZaloAccount
86
+ });
87
+ const { listAccountIds: listZaloAccountIds, resolveDefaultAccountId: resolveDefaultZaloAccountId } = createAccountListHelpers("zalo", { implicitDefaultAccount: {
88
+ channelKeys: ["botToken", "tokenFile"],
89
+ envVars: ["ZALO_BOT_TOKEN"]
90
+ } });
91
+ function mergeZaloAccountConfig(cfg, accountId) {
92
+ return resolveMergedAccountConfig({
93
+ channelConfig: cfg.channels?.zalo,
94
+ accounts: (cfg.channels?.zalo)?.accounts,
95
+ accountId,
96
+ omitKeys: ["defaultAccount"]
97
+ });
98
+ }
99
+ function resolveZaloAccount(params) {
100
+ const accountId = normalizeAccountId(params.accountId ?? (params.cfg.channels?.zalo)?.defaultAccount);
101
+ const baseEnabled = (params.cfg.channels?.zalo)?.enabled !== false;
102
+ const merged = mergeZaloAccountConfig(params.cfg, accountId);
103
+ const accountEnabled = merged.enabled !== false;
104
+ const enabled = baseEnabled && accountEnabled;
105
+ const tokenResolution = resolveZaloToken(params.cfg.channels?.zalo, accountId, { allowUnresolvedSecretRef: params.allowUnresolvedSecretRef });
106
+ return {
107
+ accountId,
108
+ name: normalizeOptionalString(merged.name),
109
+ enabled,
110
+ token: tokenResolution.token,
111
+ tokenSource: tokenResolution.source,
112
+ config: merged
113
+ };
114
+ }
115
+ function listEnabledZaloAccounts(cfg) {
116
+ return listZaloAccountIds(cfg).map((accountId) => resolveZaloAccount({
117
+ cfg,
118
+ accountId
119
+ })).filter((account) => account.enabled);
120
+ }
121
+ //#endregion
122
+ //#region extensions/zalo/src/setup-allow-from.ts
123
+ const t$1 = createSetupTranslator();
124
+ async function noteZaloTokenHelp(prompter) {
125
+ await prompter.note([
126
+ t$1("wizard.zalo.helpOpenPlatform"),
127
+ t$1("wizard.zalo.helpCreateBot"),
128
+ t$1("wizard.zalo.helpTokenFormat"),
129
+ t$1("wizard.zalo.helpEnvTip"),
130
+ `Docs: ${formatDocsLink("/channels/zalo", "zalo")}`
131
+ ].join("\n"), t$1("wizard.zalo.botTokenTitle"));
132
+ }
133
+ async function promptZaloAllowFrom(params) {
134
+ const { cfg, prompter } = params;
135
+ const accountId = params.accountId ?? resolveDefaultZaloAccountId(cfg);
136
+ const existingAllowFrom = resolveZaloAccount({
137
+ cfg,
138
+ accountId
139
+ }).config.allowFrom ?? [];
140
+ const unique = mergeAllowFromEntries(existingAllowFrom, [(await prompter.text({
141
+ message: t$1("wizard.zalo.allowFromPrompt"),
142
+ placeholder: "123456789",
143
+ initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : void 0,
144
+ validate: (value) => {
145
+ const raw = (value ?? "").trim();
146
+ if (!raw) return t$1("common.required");
147
+ if (!/^\d+$/.test(raw)) return t$1("wizard.zalo.allowFromNumeric");
148
+ }
149
+ })).trim()]);
150
+ if (accountId === DEFAULT_ACCOUNT_ID$1) return {
151
+ ...cfg,
152
+ channels: {
153
+ ...cfg.channels,
154
+ zalo: {
155
+ ...cfg.channels?.zalo,
156
+ enabled: true,
157
+ dmPolicy: "allowlist",
158
+ allowFrom: unique
159
+ }
160
+ }
161
+ };
162
+ const currentAccount = cfg.channels?.zalo?.accounts?.[accountId];
163
+ return {
164
+ ...cfg,
165
+ channels: {
166
+ ...cfg.channels,
167
+ zalo: {
168
+ ...cfg.channels?.zalo,
169
+ enabled: true,
170
+ accounts: {
171
+ ...cfg.channels?.zalo?.accounts,
172
+ [accountId]: {
173
+ ...currentAccount,
174
+ enabled: currentAccount?.enabled ?? true,
175
+ dmPolicy: "allowlist",
176
+ allowFrom: unique
177
+ }
178
+ }
179
+ }
180
+ }
181
+ };
182
+ }
183
+ //#endregion
184
+ //#region extensions/zalo/src/setup-core.ts
185
+ const t = createSetupTranslator();
186
+ const channel = "zalo";
187
+ const zaloSetupAdapter = createPatchedAccountSetupAdapter({
188
+ channelKey: channel,
189
+ validateInput: createSetupInputPresenceValidator({
190
+ defaultAccountOnlyEnvError: "ZALO_BOT_TOKEN can only be used for the default account.",
191
+ whenNotUseEnv: [{
192
+ someOf: ["token", "tokenFile"],
193
+ message: "Zalo requires token or --token-file (or --use-env)."
194
+ }]
195
+ }),
196
+ buildPatch: (input) => input.useEnv ? {} : input.tokenFile ? { tokenFile: input.tokenFile } : input.token ? { botToken: input.token } : {}
197
+ });
198
+ const zaloDmPolicy = {
199
+ label: "Zalo",
200
+ channel,
201
+ policyKey: "channels.zalo.dmPolicy",
202
+ allowFromKey: "channels.zalo.allowFrom",
203
+ resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultZaloAccountId(cfg)) !== DEFAULT_ACCOUNT_ID$1 ? {
204
+ policyKey: `channels.zalo.accounts.${accountId ?? resolveDefaultZaloAccountId(cfg)}.dmPolicy`,
205
+ allowFromKey: `channels.zalo.accounts.${accountId ?? resolveDefaultZaloAccountId(cfg)}.allowFrom`
206
+ } : {
207
+ policyKey: "channels.zalo.dmPolicy",
208
+ allowFromKey: "channels.zalo.allowFrom"
209
+ },
210
+ getCurrent: (cfg, accountId) => resolveZaloAccount({
211
+ cfg,
212
+ accountId: accountId ?? resolveDefaultZaloAccountId(cfg)
213
+ }).config.dmPolicy ?? "pairing",
214
+ setPolicy: (cfg, policy, accountId) => {
215
+ const resolvedAccountId = accountId && normalizeAccountId$1(accountId) ? normalizeAccountId$1(accountId) ?? DEFAULT_ACCOUNT_ID$1 : resolveDefaultZaloAccountId(cfg);
216
+ const resolved = resolveZaloAccount({
217
+ cfg,
218
+ accountId: resolvedAccountId
219
+ });
220
+ if (resolvedAccountId === DEFAULT_ACCOUNT_ID$1) return {
221
+ ...cfg,
222
+ channels: {
223
+ ...cfg.channels,
224
+ zalo: {
225
+ ...cfg.channels?.zalo,
226
+ enabled: true,
227
+ dmPolicy: policy,
228
+ ...policy === "open" ? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) } : {}
229
+ }
230
+ }
231
+ };
232
+ const currentAccount = cfg.channels?.zalo?.accounts?.[resolvedAccountId];
233
+ return {
234
+ ...cfg,
235
+ channels: {
236
+ ...cfg.channels,
237
+ zalo: {
238
+ ...cfg.channels?.zalo,
239
+ enabled: true,
240
+ accounts: {
241
+ ...cfg.channels?.zalo?.accounts,
242
+ [resolvedAccountId]: {
243
+ ...currentAccount,
244
+ enabled: currentAccount?.enabled ?? true,
245
+ dmPolicy: policy,
246
+ ...policy === "open" ? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) } : {}
247
+ }
248
+ }
249
+ }
250
+ }
251
+ };
252
+ },
253
+ promptAllowFrom: async ({ cfg, prompter, accountId }) => promptZaloAllowFrom({
254
+ cfg,
255
+ prompter,
256
+ accountId: accountId ?? resolveDefaultZaloAccountId(cfg)
257
+ })
258
+ };
259
+ function createZaloSetupWizardProxy(loadWizard) {
260
+ return createDelegatedSetupWizardProxy({
261
+ channel,
262
+ loadWizard,
263
+ status: {
264
+ configuredLabel: t("wizard.channels.statusConfigured"),
265
+ unconfiguredLabel: t("wizard.channels.statusNeedsToken"),
266
+ configuredHint: t("wizard.channels.statusRecommendedConfigured"),
267
+ unconfiguredHint: t("wizard.channels.statusRecommendedNewcomerFriendly"),
268
+ configuredScore: 1,
269
+ unconfiguredScore: 10
270
+ },
271
+ credentials: [],
272
+ delegateFinalize: true,
273
+ dmPolicy: zaloDmPolicy,
274
+ disable: (cfg) => ({
275
+ ...cfg,
276
+ channels: {
277
+ ...cfg.channels,
278
+ zalo: {
279
+ ...cfg.channels?.zalo,
280
+ enabled: false
281
+ }
282
+ }
283
+ })
284
+ });
285
+ }
286
+ //#endregion
287
+ export { promptZaloAllowFrom as a, listZaloAccountIds as c, resolveZaloToken as d, buildSecretInputSchema as f, noteZaloTokenHelp as i, resolveDefaultZaloAccountId as l, zaloDmPolicy as n, accounts_exports as o, normalizeSecretInputString as p, zaloSetupAdapter as r, listEnabledZaloAccounts as s, createZaloSetupWizardProxy as t, resolveZaloAccount as u };
@@ -0,0 +1,15 @@
1
+ import { defineBundledChannelSetupEntry } from "klaw/plugin-sdk/channel-entry-contract";
2
+ //#region extensions/zalo/setup-entry.ts
3
+ var setup_entry_default = defineBundledChannelSetupEntry({
4
+ importMetaUrl: import.meta.url,
5
+ plugin: {
6
+ specifier: "./api.js",
7
+ exportName: "zaloPlugin"
8
+ },
9
+ secrets: {
10
+ specifier: "./secret-contract-api.js",
11
+ exportName: "channelSecrets"
12
+ }
13
+ });
14
+ //#endregion
15
+ export { setup_entry_default as default };
@@ -0,0 +1,216 @@
1
+ import { a as promptZaloAllowFrom, i as noteZaloTokenHelp, n as zaloDmPolicy, u as resolveZaloAccount } from "./setup-core-Dr75wK6l.js";
2
+ import { DEFAULT_ACCOUNT_ID, buildSingleChannelSecretPromptState, createSetupTranslator, createStandardChannelSetupStatus, hasConfiguredSecretInput, promptSingleChannelSecretInput, runSingleChannelSecretStep } from "klaw/plugin-sdk/setup";
3
+ //#region extensions/zalo/src/setup-surface.ts
4
+ const t = createSetupTranslator();
5
+ const channel = "zalo";
6
+ function setZaloUpdateMode(cfg, accountId, mode, webhookUrl, webhookSecret, webhookPath) {
7
+ const isDefault = accountId === DEFAULT_ACCOUNT_ID;
8
+ if (mode === "polling") {
9
+ if (isDefault) {
10
+ const { webhookUrl: _url, webhookSecret: _secret, webhookPath: _path, ...rest } = cfg.channels?.zalo ?? {};
11
+ return {
12
+ ...cfg,
13
+ channels: {
14
+ ...cfg.channels,
15
+ zalo: rest
16
+ }
17
+ };
18
+ }
19
+ const accounts = { ...cfg.channels?.zalo?.accounts };
20
+ const { webhookUrl: _url, webhookSecret: _secret, webhookPath: _path, ...rest } = accounts[accountId] ?? {};
21
+ accounts[accountId] = rest;
22
+ return {
23
+ ...cfg,
24
+ channels: {
25
+ ...cfg.channels,
26
+ zalo: {
27
+ ...cfg.channels?.zalo,
28
+ accounts
29
+ }
30
+ }
31
+ };
32
+ }
33
+ if (isDefault) return {
34
+ ...cfg,
35
+ channels: {
36
+ ...cfg.channels,
37
+ zalo: {
38
+ ...cfg.channels?.zalo,
39
+ webhookUrl,
40
+ webhookSecret,
41
+ webhookPath
42
+ }
43
+ }
44
+ };
45
+ const accounts = { ...cfg.channels?.zalo?.accounts };
46
+ accounts[accountId] = {
47
+ ...accounts[accountId],
48
+ webhookUrl,
49
+ webhookSecret,
50
+ webhookPath
51
+ };
52
+ return {
53
+ ...cfg,
54
+ channels: {
55
+ ...cfg.channels,
56
+ zalo: {
57
+ ...cfg.channels?.zalo,
58
+ accounts
59
+ }
60
+ }
61
+ };
62
+ }
63
+ const zaloSetupWizard = {
64
+ channel,
65
+ status: createStandardChannelSetupStatus({
66
+ channelLabel: "Zalo",
67
+ configuredLabel: t("wizard.channels.statusConfigured"),
68
+ unconfiguredLabel: t("wizard.channels.statusNeedsToken"),
69
+ configuredHint: t("wizard.channels.statusRecommendedConfigured"),
70
+ unconfiguredHint: t("wizard.channels.statusRecommendedNewcomerFriendly"),
71
+ configuredScore: 1,
72
+ unconfiguredScore: 10,
73
+ includeStatusLine: true,
74
+ resolveConfigured: ({ cfg, accountId }) => {
75
+ const account = resolveZaloAccount({
76
+ cfg,
77
+ accountId,
78
+ allowUnresolvedSecretRef: true
79
+ });
80
+ return Boolean(account.token) || hasConfiguredSecretInput(account.config.botToken) || Boolean(account.config.tokenFile?.trim());
81
+ }
82
+ }),
83
+ credentials: [],
84
+ finalize: async ({ cfg, accountId, forceAllowFrom, options, prompter }) => {
85
+ let next = cfg;
86
+ const resolvedAccount = resolveZaloAccount({
87
+ cfg: next,
88
+ accountId,
89
+ allowUnresolvedSecretRef: true
90
+ });
91
+ const accountConfigured = Boolean(resolvedAccount.token);
92
+ const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
93
+ const hasConfigToken = Boolean(hasConfiguredSecretInput(resolvedAccount.config.botToken) || resolvedAccount.config.tokenFile);
94
+ next = (await runSingleChannelSecretStep({
95
+ cfg: next,
96
+ prompter,
97
+ providerHint: "zalo",
98
+ credentialLabel: t("wizard.zalo.botToken"),
99
+ secretInputMode: options?.secretInputMode,
100
+ accountConfigured,
101
+ hasConfigToken,
102
+ allowEnv,
103
+ envValue: process.env.ZALO_BOT_TOKEN,
104
+ envPrompt: t("wizard.zalo.tokenEnvPrompt"),
105
+ keepPrompt: t("wizard.zalo.tokenKeep"),
106
+ inputPrompt: t("wizard.zalo.tokenInput"),
107
+ preferredEnvVar: "ZALO_BOT_TOKEN",
108
+ onMissingConfigured: async () => await noteZaloTokenHelp(prompter),
109
+ applyUseEnv: async (currentCfg) => accountId === DEFAULT_ACCOUNT_ID ? {
110
+ ...currentCfg,
111
+ channels: {
112
+ ...currentCfg.channels,
113
+ zalo: {
114
+ ...currentCfg.channels?.zalo,
115
+ enabled: true
116
+ }
117
+ }
118
+ } : currentCfg,
119
+ applySet: async (currentCfg, value) => accountId === DEFAULT_ACCOUNT_ID ? {
120
+ ...currentCfg,
121
+ channels: {
122
+ ...currentCfg.channels,
123
+ zalo: {
124
+ ...currentCfg.channels?.zalo,
125
+ enabled: true,
126
+ botToken: value
127
+ }
128
+ }
129
+ } : {
130
+ ...currentCfg,
131
+ channels: {
132
+ ...currentCfg.channels,
133
+ zalo: {
134
+ ...currentCfg.channels?.zalo,
135
+ enabled: true,
136
+ accounts: {
137
+ ...currentCfg.channels?.zalo?.accounts,
138
+ [accountId]: {
139
+ ...currentCfg.channels?.zalo?.accounts?.[accountId],
140
+ enabled: true,
141
+ botToken: value
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ })).cfg;
148
+ if (await prompter.confirm({
149
+ message: t("wizard.zalo.webhookModePrompt"),
150
+ initialValue: Boolean(resolvedAccount.config.webhookUrl)
151
+ })) {
152
+ const webhookUrl = (await prompter.text({
153
+ message: t("wizard.zalo.webhookUrlPrompt"),
154
+ initialValue: resolvedAccount.config.webhookUrl,
155
+ validate: (value) => value?.trim()?.startsWith("https://") ? void 0 : "HTTPS URL required"
156
+ })).trim();
157
+ const defaultPath = (() => {
158
+ try {
159
+ return new URL(webhookUrl).pathname || "/zalo-webhook";
160
+ } catch {
161
+ return "/zalo-webhook";
162
+ }
163
+ })();
164
+ let webhookSecretResult = await promptSingleChannelSecretInput({
165
+ cfg: next,
166
+ prompter,
167
+ providerHint: "zalo-webhook",
168
+ credentialLabel: t("wizard.zalo.webhookSecret"),
169
+ secretInputMode: options?.secretInputMode,
170
+ ...buildSingleChannelSecretPromptState({
171
+ accountConfigured: hasConfiguredSecretInput(resolvedAccount.config.webhookSecret),
172
+ hasConfigToken: hasConfiguredSecretInput(resolvedAccount.config.webhookSecret),
173
+ allowEnv: false
174
+ }),
175
+ envPrompt: "",
176
+ keepPrompt: t("wizard.zalo.webhookSecretKeep"),
177
+ inputPrompt: t("wizard.zalo.webhookSecretInput"),
178
+ preferredEnvVar: "ZALO_WEBHOOK_SECRET"
179
+ });
180
+ while (webhookSecretResult.action === "set" && typeof webhookSecretResult.value === "string" && (webhookSecretResult.value.length < 8 || webhookSecretResult.value.length > 256)) {
181
+ await prompter.note(t("wizard.zalo.webhookSecretLength"), t("wizard.zalo.webhookTitle"));
182
+ webhookSecretResult = await promptSingleChannelSecretInput({
183
+ cfg: next,
184
+ prompter,
185
+ providerHint: "zalo-webhook",
186
+ credentialLabel: t("wizard.zalo.webhookSecret"),
187
+ secretInputMode: options?.secretInputMode,
188
+ ...buildSingleChannelSecretPromptState({
189
+ accountConfigured: false,
190
+ hasConfigToken: false,
191
+ allowEnv: false
192
+ }),
193
+ envPrompt: "",
194
+ keepPrompt: t("wizard.zalo.webhookSecretKeep"),
195
+ inputPrompt: t("wizard.zalo.webhookSecretInput"),
196
+ preferredEnvVar: "ZALO_WEBHOOK_SECRET"
197
+ });
198
+ }
199
+ const webhookSecret = webhookSecretResult.action === "set" ? webhookSecretResult.value : resolvedAccount.config.webhookSecret;
200
+ const webhookPath = (await prompter.text({
201
+ message: t("wizard.zalo.webhookPathPrompt"),
202
+ initialValue: resolvedAccount.config.webhookPath ?? defaultPath
203
+ })).trim();
204
+ next = setZaloUpdateMode(next, accountId, "webhook", webhookUrl, webhookSecret, webhookPath || void 0);
205
+ } else next = setZaloUpdateMode(next, accountId, "polling");
206
+ if (forceAllowFrom) next = await promptZaloAllowFrom({
207
+ cfg: next,
208
+ prompter,
209
+ accountId
210
+ });
211
+ return { cfg: next };
212
+ },
213
+ dmPolicy: zaloDmPolicy
214
+ };
215
+ //#endregion
216
+ export { zaloSetupWizard };
@@ -0,0 +1,2 @@
1
+ import { n as resolveZaloRuntimeGroupPolicy } from "./group-access-DTQVR6Nd.js";
2
+ export { resolveZaloRuntimeGroupPolicy };
package/index.test.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { assertBundledChannelEntries } from "klaw/plugin-sdk/channel-test-helpers";
2
+ import { describe } from "vitest";
3
+ import entry from "./index.js";
4
+ import setupEntry from "./setup-entry.js";
5
+
6
+ describe("zalo bundled entries", () => {
7
+ assertBundledChannelEntries({
8
+ entry,
9
+ expectedId: "zalo",
10
+ expectedName: "Zalo",
11
+ setupEntry,
12
+ channelMessage: "declares the channel plugin without a runtime-barrel cycle",
13
+ setupMessage: "declares the setup plugin without a runtime-barrel cycle",
14
+ });
15
+ });
package/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { defineBundledChannelEntry } from "klaw/plugin-sdk/channel-entry-contract";
2
+
3
+ export default defineBundledChannelEntry({
4
+ id: "zalo",
5
+ name: "Zalo",
6
+ description: "Zalo channel plugin",
7
+ importMetaUrl: import.meta.url,
8
+ plugin: {
9
+ specifier: "./channel-plugin-api.js",
10
+ exportName: "zaloPlugin",
11
+ },
12
+ secrets: {
13
+ specifier: "./secret-contract-api.js",
14
+ exportName: "channelSecrets",
15
+ },
16
+ runtime: {
17
+ specifier: "./runtime-api.js",
18
+ exportName: "setZaloRuntime",
19
+ },
20
+ });