@openclaw/zalouser 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 (95) hide show
  1. package/dist/accounts-C00IMUgd.js +63 -0
  2. package/dist/accounts.runtime-uG7S8cXT.js +2 -0
  3. package/dist/api-BRwdUWuS.js +139 -0
  4. package/dist/api.js +7 -0
  5. package/dist/channel-ou_w_2j-.js +484 -0
  6. package/dist/channel-plugin-api.js +2 -0
  7. package/dist/channel.runtime-C9WxiAiR.js +25 -0
  8. package/dist/channel.setup-CiDeBFrn.js +10 -0
  9. package/dist/contract-api.js +3 -0
  10. package/dist/doctor-contract-DgqHp8E2.js +128 -0
  11. package/dist/doctor-contract-api.js +2 -0
  12. package/dist/index.js +27 -0
  13. package/dist/monitor-Cg7K_s_s.js +705 -0
  14. package/dist/runtime-QNU7vLgI.js +106 -0
  15. package/dist/runtime-api.js +22 -0
  16. package/dist/secret-contract-api.js +5 -0
  17. package/dist/security-audit-BZLhil-V.js +34 -0
  18. package/dist/send-BsmySxe3.js +534 -0
  19. package/dist/session-route-C0-Xr8bt.js +92 -0
  20. package/dist/setup-core-CqipqY98.js +40 -0
  21. package/dist/setup-entry.js +11 -0
  22. package/dist/setup-plugin-api.js +2 -0
  23. package/dist/setup-surface-NCOuKu-l.js +359 -0
  24. package/dist/shared-DSy8aIUx.js +120 -0
  25. package/dist/test-api.js +5 -0
  26. package/dist/zalo-js-CHCUlY3c.js +1279 -0
  27. package/package.json +15 -6
  28. package/api.ts +0 -9
  29. package/channel-plugin-api.ts +0 -3
  30. package/contract-api.ts +0 -2
  31. package/doctor-contract-api.ts +0 -1
  32. package/index.ts +0 -34
  33. package/runtime-api.ts +0 -67
  34. package/secret-contract-api.ts +0 -4
  35. package/setup-entry.ts +0 -9
  36. package/setup-plugin-api.ts +0 -2
  37. package/src/accounts.runtime.ts +0 -1
  38. package/src/accounts.test-mocks.ts +0 -14
  39. package/src/accounts.test.ts +0 -266
  40. package/src/accounts.ts +0 -131
  41. package/src/channel-api.ts +0 -20
  42. package/src/channel.adapters.ts +0 -391
  43. package/src/channel.directory.test.ts +0 -59
  44. package/src/channel.runtime.ts +0 -12
  45. package/src/channel.sendpayload.test.ts +0 -172
  46. package/src/channel.setup.test.ts +0 -33
  47. package/src/channel.setup.ts +0 -12
  48. package/src/channel.test.ts +0 -377
  49. package/src/channel.ts +0 -219
  50. package/src/config-schema.ts +0 -33
  51. package/src/directory.ts +0 -54
  52. package/src/doctor-contract.ts +0 -156
  53. package/src/doctor.test.ts +0 -77
  54. package/src/doctor.ts +0 -37
  55. package/src/group-policy.test.ts +0 -61
  56. package/src/group-policy.ts +0 -83
  57. package/src/message-sid.test.ts +0 -66
  58. package/src/message-sid.ts +0 -80
  59. package/src/monitor.account-scope.test.ts +0 -107
  60. package/src/monitor.group-gating.test.ts +0 -816
  61. package/src/monitor.send-mocks.ts +0 -20
  62. package/src/monitor.ts +0 -1044
  63. package/src/probe.test.ts +0 -60
  64. package/src/probe.ts +0 -35
  65. package/src/qr-temp-file.ts +0 -22
  66. package/src/reaction.test.ts +0 -19
  67. package/src/reaction.ts +0 -32
  68. package/src/runtime.ts +0 -9
  69. package/src/security-audit.test.ts +0 -80
  70. package/src/security-audit.ts +0 -71
  71. package/src/send.test.ts +0 -395
  72. package/src/send.ts +0 -272
  73. package/src/session-route.ts +0 -121
  74. package/src/setup-core.ts +0 -33
  75. package/src/setup-surface.test.ts +0 -363
  76. package/src/setup-surface.ts +0 -470
  77. package/src/setup-test-helpers.ts +0 -42
  78. package/src/shared.ts +0 -92
  79. package/src/status-issues.test.ts +0 -31
  80. package/src/status-issues.ts +0 -58
  81. package/src/test-helpers.ts +0 -26
  82. package/src/text-styles.test.ts +0 -203
  83. package/src/text-styles.ts +0 -540
  84. package/src/tool.test.ts +0 -212
  85. package/src/tool.ts +0 -210
  86. package/src/types.ts +0 -125
  87. package/src/zalo-js.credentials.test.ts +0 -465
  88. package/src/zalo-js.test-mocks.ts +0 -89
  89. package/src/zalo-js.ts +0 -1911
  90. package/src/zca-client.test.ts +0 -24
  91. package/src/zca-client.ts +0 -259
  92. package/src/zca-constants.ts +0 -55
  93. package/src/zca-js-exports.d.ts +0 -22
  94. package/test-api.ts +0 -21
  95. package/tsconfig.json +0 -16
@@ -0,0 +1,534 @@
1
+ import { _ as sendZaloTypingEvent, f as sendZaloDeliveredEvent, g as sendZaloTextMessage, h as sendZaloSeenEvent, m as sendZaloReaction, p as sendZaloLink, x as TextStyle } from "./zalo-js-CHCUlY3c.js";
2
+ //#region extensions/zalouser/src/text-styles.ts
3
+ const ESCAPE_SENTINEL_START = "";
4
+ const ESCAPE_SENTINEL_END = "";
5
+ const TAG_STYLE_MAP = {
6
+ red: TextStyle.Red,
7
+ orange: TextStyle.Orange,
8
+ yellow: TextStyle.Yellow,
9
+ green: TextStyle.Green,
10
+ small: null,
11
+ big: TextStyle.Big,
12
+ underline: TextStyle.Underline
13
+ };
14
+ const INLINE_MARKERS = [
15
+ {
16
+ pattern: /`([^`\n]+)`/g,
17
+ extractText: (match) => match[0],
18
+ literal: true
19
+ },
20
+ {
21
+ pattern: /\\([*_~#\\{}>+\-`])/g,
22
+ extractText: (match) => match[1],
23
+ literal: true
24
+ },
25
+ {
26
+ pattern: new RegExp(`\\{(${Object.keys(TAG_STYLE_MAP).join("|")})\\}(.+?)\\{/\\1\\}`, "g"),
27
+ extractText: (match) => match[2],
28
+ resolveStyles: (match) => {
29
+ const style = TAG_STYLE_MAP[match[1]];
30
+ return style ? [style] : [];
31
+ }
32
+ },
33
+ {
34
+ pattern: /(?<!\*)\*\*\*(?=\S)([^\n]*?\S)(?<!\*)\*\*\*(?!\*)/g,
35
+ extractText: (match) => match[1],
36
+ resolveStyles: () => [TextStyle.Bold, TextStyle.Italic]
37
+ },
38
+ {
39
+ pattern: /(?<!\*)\*\*(?![\s*])([^\n]*?\S)(?<!\*)\*\*(?!\*)/g,
40
+ extractText: (match) => match[1],
41
+ resolveStyles: () => [TextStyle.Bold]
42
+ },
43
+ {
44
+ pattern: /(?<![\w_])__(?![\s_])([^\n]*?\S)(?<!_)__(?![\w_])/g,
45
+ extractText: (match) => match[1],
46
+ resolveStyles: () => [TextStyle.Bold]
47
+ },
48
+ {
49
+ pattern: /(?<!~)~~(?=\S)([^\n]*?\S)(?<!~)~~(?!~)/g,
50
+ extractText: (match) => match[1],
51
+ resolveStyles: () => [TextStyle.StrikeThrough]
52
+ },
53
+ {
54
+ pattern: /(?<!\*)\*(?![\s*])([^\n]*?\S)(?<!\*)\*(?!\*)/g,
55
+ extractText: (match) => match[1],
56
+ resolveStyles: () => [TextStyle.Italic]
57
+ },
58
+ {
59
+ pattern: /(?<![\w_])_(?![\s_])([^\n]*?\S)(?<!_)_(?![\w_])/g,
60
+ extractText: (match) => match[1],
61
+ resolveStyles: () => [TextStyle.Italic]
62
+ }
63
+ ];
64
+ function parseZalouserTextStyles(input) {
65
+ const allStyles = [];
66
+ const escapeMap = [];
67
+ const lines = input.replace(/\r\n?/g, "\n").split("\n");
68
+ const lineStyles = [];
69
+ const processedLines = [];
70
+ let activeFence = null;
71
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
72
+ const rawLine = lines[lineIndex];
73
+ const { text: unquotedLine, indent: baseIndent } = stripQuotePrefix(rawLine);
74
+ if (activeFence) {
75
+ const codeLine = activeFence.quoteIndent > 0 ? stripQuotePrefix(rawLine, activeFence.quoteIndent).text : rawLine;
76
+ if (isClosingFence(codeLine, activeFence)) {
77
+ activeFence = null;
78
+ continue;
79
+ }
80
+ processedLines.push(escapeLiteralText(normalizeCodeBlockLeadingWhitespace(stripCodeFenceIndent(codeLine, activeFence.indent)), escapeMap));
81
+ continue;
82
+ }
83
+ let line = unquotedLine;
84
+ const openingFence = resolveOpeningFence(rawLine);
85
+ if (openingFence) {
86
+ const fenceLine = openingFence.quoteIndent > 0 ? unquotedLine : rawLine;
87
+ if (!hasClosingFence(lines, lineIndex + 1, openingFence)) {
88
+ processedLines.push(escapeLiteralText(fenceLine, escapeMap));
89
+ activeFence = openingFence;
90
+ continue;
91
+ }
92
+ activeFence = openingFence;
93
+ continue;
94
+ }
95
+ const outputLineIndex = processedLines.length;
96
+ if (isIndentedCodeBlockLine(line)) {
97
+ if (baseIndent > 0) lineStyles.push({
98
+ lineIndex: outputLineIndex,
99
+ style: TextStyle.Indent,
100
+ indentSize: baseIndent
101
+ });
102
+ processedLines.push(escapeLiteralText(normalizeCodeBlockLeadingWhitespace(line), escapeMap));
103
+ continue;
104
+ }
105
+ const { text: markdownLine, size: markdownPadding } = stripOptionalMarkdownPadding(line);
106
+ const headingMatch = markdownLine.match(/^(#{1,4})\s(.*)$/);
107
+ if (headingMatch) {
108
+ const depth = headingMatch[1].length;
109
+ lineStyles.push({
110
+ lineIndex: outputLineIndex,
111
+ style: TextStyle.Bold
112
+ });
113
+ if (depth === 1) lineStyles.push({
114
+ lineIndex: outputLineIndex,
115
+ style: TextStyle.Big
116
+ });
117
+ if (baseIndent > 0) lineStyles.push({
118
+ lineIndex: outputLineIndex,
119
+ style: TextStyle.Indent,
120
+ indentSize: baseIndent
121
+ });
122
+ processedLines.push(headingMatch[2]);
123
+ continue;
124
+ }
125
+ const indentMatch = markdownLine.match(/^(\s+)(.*)$/);
126
+ let indentLevel = 0;
127
+ let content = markdownLine;
128
+ if (indentMatch) {
129
+ indentLevel = clampIndent(indentMatch[1].length);
130
+ content = indentMatch[2];
131
+ }
132
+ const totalIndent = Math.min(5, baseIndent + indentLevel);
133
+ if (/^[-*+]\s\[[ xX]\]\s/.test(content)) {
134
+ if (totalIndent > 0) lineStyles.push({
135
+ lineIndex: outputLineIndex,
136
+ style: TextStyle.Indent,
137
+ indentSize: totalIndent
138
+ });
139
+ processedLines.push(content);
140
+ continue;
141
+ }
142
+ const orderedListMatch = content.match(/^(\d+)\.\s(.*)$/);
143
+ if (orderedListMatch) {
144
+ if (totalIndent > 0) lineStyles.push({
145
+ lineIndex: outputLineIndex,
146
+ style: TextStyle.Indent,
147
+ indentSize: totalIndent
148
+ });
149
+ lineStyles.push({
150
+ lineIndex: outputLineIndex,
151
+ style: TextStyle.OrderedList
152
+ });
153
+ processedLines.push(orderedListMatch[2]);
154
+ continue;
155
+ }
156
+ const unorderedListMatch = content.match(/^[-*+]\s(.*)$/);
157
+ if (unorderedListMatch) {
158
+ if (totalIndent > 0) lineStyles.push({
159
+ lineIndex: outputLineIndex,
160
+ style: TextStyle.Indent,
161
+ indentSize: totalIndent
162
+ });
163
+ lineStyles.push({
164
+ lineIndex: outputLineIndex,
165
+ style: TextStyle.UnorderedList
166
+ });
167
+ processedLines.push(unorderedListMatch[1]);
168
+ continue;
169
+ }
170
+ if (markdownPadding > 0) {
171
+ if (baseIndent > 0) lineStyles.push({
172
+ lineIndex: outputLineIndex,
173
+ style: TextStyle.Indent,
174
+ indentSize: baseIndent
175
+ });
176
+ processedLines.push(line);
177
+ continue;
178
+ }
179
+ if (totalIndent > 0) {
180
+ lineStyles.push({
181
+ lineIndex: outputLineIndex,
182
+ style: TextStyle.Indent,
183
+ indentSize: totalIndent
184
+ });
185
+ processedLines.push(content);
186
+ continue;
187
+ }
188
+ processedLines.push(line);
189
+ }
190
+ const segments = parseInlineSegments(processedLines.join("\n"));
191
+ let plainText = "";
192
+ for (const segment of segments) {
193
+ const start = plainText.length;
194
+ plainText += segment.text;
195
+ for (const style of segment.styles) allStyles.push({
196
+ start,
197
+ len: segment.text.length,
198
+ st: style
199
+ });
200
+ }
201
+ if (escapeMap.length > 0) {
202
+ const escapeRegex = new RegExp(`${ESCAPE_SENTINEL_START}(\\d+)${ESCAPE_SENTINEL_END}`, "g");
203
+ const shifts = [];
204
+ let cumulativeDelta = 0;
205
+ for (const match of plainText.matchAll(escapeRegex)) {
206
+ const escapeIndex = Number.parseInt(match[1], 10);
207
+ cumulativeDelta += match[0].length - escapeMap[escapeIndex].length;
208
+ shifts.push({
209
+ pos: (match.index ?? 0) + match[0].length,
210
+ delta: cumulativeDelta
211
+ });
212
+ }
213
+ for (const style of allStyles) {
214
+ let startDelta = 0;
215
+ let endDelta = 0;
216
+ const end = style.start + style.len;
217
+ for (const shift of shifts) {
218
+ if (shift.pos <= style.start) startDelta = shift.delta;
219
+ if (shift.pos <= end) endDelta = shift.delta;
220
+ }
221
+ style.start -= startDelta;
222
+ style.len -= endDelta - startDelta;
223
+ }
224
+ plainText = plainText.replace(escapeRegex, (_match, index) => escapeMap[Number.parseInt(index, 10)]);
225
+ }
226
+ const finalLines = plainText.split("\n");
227
+ let offset = 0;
228
+ for (let lineIndex = 0; lineIndex < finalLines.length; lineIndex += 1) {
229
+ const lineLength = finalLines[lineIndex].length;
230
+ if (lineLength > 0) for (const lineStyle of lineStyles) {
231
+ if (lineStyle.lineIndex !== lineIndex) continue;
232
+ if (lineStyle.style === TextStyle.Indent) allStyles.push({
233
+ start: offset,
234
+ len: lineLength,
235
+ st: TextStyle.Indent,
236
+ indentSize: lineStyle.indentSize
237
+ });
238
+ else allStyles.push({
239
+ start: offset,
240
+ len: lineLength,
241
+ st: lineStyle.style
242
+ });
243
+ }
244
+ offset += lineLength + 1;
245
+ }
246
+ return {
247
+ text: plainText,
248
+ styles: allStyles
249
+ };
250
+ }
251
+ function clampIndent(spaceCount) {
252
+ return Math.min(5, Math.max(1, Math.floor(spaceCount / 2)));
253
+ }
254
+ function stripOptionalMarkdownPadding(line) {
255
+ const match = line.match(/^( {1,3})(?=\S)/);
256
+ if (!match) return {
257
+ text: line,
258
+ size: 0
259
+ };
260
+ return {
261
+ text: line.slice(match[1].length),
262
+ size: match[1].length
263
+ };
264
+ }
265
+ function hasClosingFence(lines, startIndex, fence) {
266
+ for (let index = startIndex; index < lines.length; index += 1) if (isClosingFence(fence.quoteIndent > 0 ? stripQuotePrefix(lines[index], fence.quoteIndent).text : lines[index], fence)) return true;
267
+ return false;
268
+ }
269
+ function resolveOpeningFence(line) {
270
+ const directFence = parseFenceMarker(line);
271
+ if (directFence) return {
272
+ ...directFence,
273
+ quoteIndent: 0
274
+ };
275
+ const quoted = stripQuotePrefix(line);
276
+ if (quoted.indent === 0) return null;
277
+ const quotedFence = parseFenceMarker(quoted.text);
278
+ if (!quotedFence) return null;
279
+ return {
280
+ ...quotedFence,
281
+ quoteIndent: quoted.indent
282
+ };
283
+ }
284
+ function stripQuotePrefix(line, maxDepth = Number.POSITIVE_INFINITY) {
285
+ let cursor = 0;
286
+ while (cursor < line.length && cursor < 3 && line[cursor] === " ") cursor += 1;
287
+ let removedDepth = 0;
288
+ let consumedCursor = cursor;
289
+ while (removedDepth < maxDepth && consumedCursor < line.length && line[consumedCursor] === ">") {
290
+ removedDepth += 1;
291
+ consumedCursor += 1;
292
+ if (line[consumedCursor] === " ") consumedCursor += 1;
293
+ }
294
+ if (removedDepth === 0) return {
295
+ text: line,
296
+ indent: 0
297
+ };
298
+ return {
299
+ text: line.slice(consumedCursor),
300
+ indent: Math.min(5, removedDepth)
301
+ };
302
+ }
303
+ function parseFenceMarker(line) {
304
+ const match = line.match(/^([ ]{0,3})(`{3,}|~{3,})(.*)$/);
305
+ if (!match) return null;
306
+ const marker = match[2];
307
+ const char = marker[0];
308
+ if (char !== "`" && char !== "~") return null;
309
+ return {
310
+ char,
311
+ length: marker.length,
312
+ indent: match[1].length
313
+ };
314
+ }
315
+ function isClosingFence(line, fence) {
316
+ const match = line.match(/^([ ]{0,3})(`{3,}|~{3,})[ \t]*$/);
317
+ if (!match) return false;
318
+ return match[2][0] === fence.char && match[2].length >= fence.length;
319
+ }
320
+ function escapeLiteralText(input, escapeMap) {
321
+ return input.replace(/[\\*_~{}`]/g, (ch) => {
322
+ const index = escapeMap.length;
323
+ escapeMap.push(ch);
324
+ return `\x01${index}\x02`;
325
+ });
326
+ }
327
+ function parseInlineSegments(text, inheritedStyles = []) {
328
+ const segments = [];
329
+ let cursor = 0;
330
+ while (cursor < text.length) {
331
+ const nextMatch = findNextInlineMatch(text, cursor);
332
+ if (!nextMatch) {
333
+ pushSegment(segments, text.slice(cursor), inheritedStyles);
334
+ break;
335
+ }
336
+ if (nextMatch.match.index > cursor) pushSegment(segments, text.slice(cursor, nextMatch.match.index), inheritedStyles);
337
+ const combinedStyles = [...inheritedStyles, ...nextMatch.styles];
338
+ if (nextMatch.marker.literal) pushSegment(segments, nextMatch.text, combinedStyles);
339
+ else segments.push(...parseInlineSegments(nextMatch.text, combinedStyles));
340
+ cursor = nextMatch.match.index + nextMatch.match[0].length;
341
+ }
342
+ return segments;
343
+ }
344
+ function findNextInlineMatch(text, startIndex) {
345
+ let bestMatch = null;
346
+ for (const [priority, marker] of INLINE_MARKERS.entries()) {
347
+ const regex = new RegExp(marker.pattern.source, marker.pattern.flags);
348
+ regex.lastIndex = startIndex;
349
+ const match = regex.exec(text);
350
+ if (!match) continue;
351
+ if (bestMatch && (match.index > bestMatch.match.index || match.index === bestMatch.match.index && priority > bestMatch.priority)) continue;
352
+ bestMatch = {
353
+ match,
354
+ marker,
355
+ text: marker.extractText(match),
356
+ styles: marker.resolveStyles?.(match) ?? [],
357
+ priority
358
+ };
359
+ }
360
+ return bestMatch;
361
+ }
362
+ function pushSegment(segments, text, styles) {
363
+ if (!text) return;
364
+ const lastSegment = segments.at(-1);
365
+ if (lastSegment && sameStyles(lastSegment.styles, styles)) {
366
+ lastSegment.text += text;
367
+ return;
368
+ }
369
+ segments.push({
370
+ text,
371
+ styles: [...styles]
372
+ });
373
+ }
374
+ function sameStyles(left, right) {
375
+ return left.length === right.length && left.every((style, index) => style === right[index]);
376
+ }
377
+ function normalizeCodeBlockLeadingWhitespace(line) {
378
+ return line.replace(/^[ \t]+/, (leadingWhitespace) => leadingWhitespace.replace(/\t/g, "\xA0\xA0\xA0\xA0").replace(/ /g, "\xA0"));
379
+ }
380
+ function isIndentedCodeBlockLine(line) {
381
+ return /^(?: {4,}|\t)/.test(line);
382
+ }
383
+ function stripCodeFenceIndent(line, indent) {
384
+ let consumed = 0;
385
+ let cursor = 0;
386
+ while (cursor < line.length && consumed < indent && line[cursor] === " ") {
387
+ cursor += 1;
388
+ consumed += 1;
389
+ }
390
+ return line.slice(cursor);
391
+ }
392
+ //#endregion
393
+ //#region extensions/zalouser/src/send.ts
394
+ const ZALO_TEXT_LIMIT = 2e3;
395
+ const DEFAULT_TEXT_CHUNK_MODE = "length";
396
+ async function sendMessageZalouser(threadId, text, options = {}) {
397
+ const prepared = options.textMode === "markdown" ? parseZalouserTextStyles(text) : {
398
+ text,
399
+ styles: options.textStyles
400
+ };
401
+ const textChunkLimit = options.textChunkLimit ?? ZALO_TEXT_LIMIT;
402
+ const chunks = splitStyledText(prepared.text, (prepared.styles?.length ?? 0) > 0 ? prepared.styles : void 0, textChunkLimit, options.textChunkMode);
403
+ let lastResult = null;
404
+ for (const [index, chunk] of chunks.entries()) {
405
+ const chunkOptions = index === 0 ? {
406
+ ...options,
407
+ textStyles: chunk.styles
408
+ } : {
409
+ ...options,
410
+ caption: void 0,
411
+ mediaLocalRoots: void 0,
412
+ mediaUrl: void 0,
413
+ textStyles: chunk.styles
414
+ };
415
+ const result = await sendZaloTextMessage(threadId, chunk.text, chunkOptions);
416
+ if (!result.ok) return result;
417
+ lastResult = result;
418
+ }
419
+ return lastResult ?? {
420
+ ok: false,
421
+ error: "No message content provided"
422
+ };
423
+ }
424
+ async function sendImageZalouser(threadId, imageUrl, options = {}) {
425
+ return await sendMessageZalouser(threadId, options.caption ?? "", {
426
+ ...options,
427
+ caption: void 0,
428
+ mediaUrl: imageUrl
429
+ });
430
+ }
431
+ async function sendLinkZalouser(threadId, url, options = {}) {
432
+ return await sendZaloLink(threadId, url, options);
433
+ }
434
+ async function sendTypingZalouser(threadId, options = {}) {
435
+ await sendZaloTypingEvent(threadId, options);
436
+ }
437
+ async function sendReactionZalouser(params) {
438
+ const result = await sendZaloReaction({
439
+ profile: params.profile,
440
+ threadId: params.threadId,
441
+ isGroup: params.isGroup,
442
+ msgId: params.msgId,
443
+ cliMsgId: params.cliMsgId,
444
+ emoji: params.emoji,
445
+ remove: params.remove
446
+ });
447
+ return {
448
+ ok: result.ok,
449
+ error: result.error
450
+ };
451
+ }
452
+ async function sendDeliveredZalouser(params) {
453
+ await sendZaloDeliveredEvent(params);
454
+ }
455
+ async function sendSeenZalouser(params) {
456
+ await sendZaloSeenEvent(params);
457
+ }
458
+ function splitStyledText(text, styles, limit, mode) {
459
+ if (text.length === 0) return [{
460
+ text,
461
+ styles: void 0
462
+ }];
463
+ const chunks = [];
464
+ for (const range of splitTextRanges(text, limit, mode ?? DEFAULT_TEXT_CHUNK_MODE)) {
465
+ const { start, end } = range;
466
+ chunks.push({
467
+ text: text.slice(start, end),
468
+ styles: sliceTextStyles(styles, start, end)
469
+ });
470
+ }
471
+ return chunks;
472
+ }
473
+ function sliceTextStyles(styles, start, end) {
474
+ if (!styles || styles.length === 0) return;
475
+ const chunkStyles = styles.map((style) => {
476
+ const overlapStart = Math.max(style.start, start);
477
+ const overlapEnd = Math.min(style.start + style.len, end);
478
+ if (overlapEnd <= overlapStart) return null;
479
+ if (style.st === TextStyle.Indent) return {
480
+ start: overlapStart - start,
481
+ len: overlapEnd - overlapStart,
482
+ st: style.st,
483
+ indentSize: style.indentSize
484
+ };
485
+ return {
486
+ start: overlapStart - start,
487
+ len: overlapEnd - overlapStart,
488
+ st: style.st
489
+ };
490
+ }).filter((style) => style !== null);
491
+ return chunkStyles.length > 0 ? chunkStyles : void 0;
492
+ }
493
+ function splitTextRanges(text, limit, mode) {
494
+ if (mode === "newline") return splitTextRangesByPreferredBreaks(text, limit);
495
+ const ranges = [];
496
+ for (let start = 0; start < text.length; start += limit) ranges.push({
497
+ start,
498
+ end: Math.min(text.length, start + limit)
499
+ });
500
+ return ranges;
501
+ }
502
+ function splitTextRangesByPreferredBreaks(text, limit) {
503
+ const ranges = [];
504
+ let start = 0;
505
+ while (start < text.length) {
506
+ const maxEnd = Math.min(text.length, start + limit);
507
+ let end = maxEnd;
508
+ if (maxEnd < text.length) end = findParagraphBreak(text, start, maxEnd) ?? findLastBreak(text, "\n", start, maxEnd) ?? findLastWhitespaceBreak(text, start, maxEnd) ?? maxEnd;
509
+ if (end <= start) end = maxEnd;
510
+ ranges.push({
511
+ start,
512
+ end
513
+ });
514
+ start = end;
515
+ }
516
+ return ranges;
517
+ }
518
+ function findParagraphBreak(text, start, end) {
519
+ const matches = text.slice(start, end).matchAll(/\n[\t ]*\n+/g);
520
+ let lastMatch;
521
+ for (const match of matches) lastMatch = match;
522
+ if (!lastMatch || lastMatch.index === void 0) return;
523
+ return start + lastMatch.index + lastMatch[0].length;
524
+ }
525
+ function findLastBreak(text, marker, start, end) {
526
+ const index = text.lastIndexOf(marker, end - 1);
527
+ if (index < start) return;
528
+ return index + marker.length;
529
+ }
530
+ function findLastWhitespaceBreak(text, start, end) {
531
+ for (let index = end - 1; index > start; index -= 1) if (/\s/.test(text[index])) return index + 1;
532
+ }
533
+ //#endregion
534
+ export { sendReactionZalouser as a, sendMessageZalouser as i, sendImageZalouser as n, sendSeenZalouser as o, sendLinkZalouser as r, sendTypingZalouser as s, sendDeliveredZalouser as t };
@@ -0,0 +1,92 @@
1
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
2
+ import { buildChannelOutboundSessionRoute } from "openclaw/plugin-sdk/core";
3
+ //#region extensions/zalouser/src/session-route.ts
4
+ function stripZalouserTargetPrefix(raw) {
5
+ return raw.trim().replace(/^(zalouser|zlu):/i, "").trim();
6
+ }
7
+ function normalizeZalouserTarget(raw) {
8
+ const trimmed = stripZalouserTargetPrefix(raw);
9
+ if (!trimmed) return;
10
+ const lower = normalizeLowercaseStringOrEmpty(trimmed);
11
+ if (lower.startsWith("group:")) {
12
+ const id = trimmed.slice(6).trim();
13
+ return id ? `group:${id}` : void 0;
14
+ }
15
+ if (lower.startsWith("g:")) {
16
+ const id = trimmed.slice(2).trim();
17
+ return id ? `group:${id}` : void 0;
18
+ }
19
+ if (lower.startsWith("user:")) {
20
+ const id = trimmed.slice(5).trim();
21
+ return id ? `user:${id}` : void 0;
22
+ }
23
+ if (lower.startsWith("dm:")) {
24
+ const id = trimmed.slice(3).trim();
25
+ return id ? `user:${id}` : void 0;
26
+ }
27
+ if (lower.startsWith("u:")) {
28
+ const id = trimmed.slice(2).trim();
29
+ return id ? `user:${id}` : void 0;
30
+ }
31
+ if (/^g-\S+$/i.test(trimmed)) return `group:${trimmed}`;
32
+ if (/^u-\S+$/i.test(trimmed)) return `user:${trimmed}`;
33
+ return trimmed;
34
+ }
35
+ function parseZalouserOutboundTarget(raw) {
36
+ const normalized = normalizeZalouserTarget(raw);
37
+ if (!normalized) throw new Error("Zalouser target is required");
38
+ const lowered = normalizeLowercaseStringOrEmpty(normalized);
39
+ if (lowered.startsWith("group:")) {
40
+ const threadId = normalized.slice(6).trim();
41
+ if (!threadId) throw new Error("Zalouser group target is missing group id");
42
+ return {
43
+ threadId,
44
+ isGroup: true
45
+ };
46
+ }
47
+ if (lowered.startsWith("user:")) {
48
+ const threadId = normalized.slice(5).trim();
49
+ if (!threadId) throw new Error("Zalouser user target is missing user id");
50
+ return {
51
+ threadId,
52
+ isGroup: false
53
+ };
54
+ }
55
+ return {
56
+ threadId: normalized,
57
+ isGroup: false
58
+ };
59
+ }
60
+ function parseZalouserDirectoryGroupId(raw) {
61
+ const normalized = normalizeZalouserTarget(raw);
62
+ if (!normalized) throw new Error("Zalouser group target is required");
63
+ const lowered = normalizeLowercaseStringOrEmpty(normalized);
64
+ if (lowered.startsWith("group:")) {
65
+ const groupId = normalized.slice(6).trim();
66
+ if (!groupId) throw new Error("Zalouser group target is missing group id");
67
+ return groupId;
68
+ }
69
+ if (lowered.startsWith("user:")) throw new Error("Zalouser group members lookup requires a group target (group:<id>)");
70
+ return normalized;
71
+ }
72
+ function resolveZalouserOutboundSessionRoute(params) {
73
+ const normalized = normalizeZalouserTarget(params.target);
74
+ if (!normalized) return null;
75
+ const isGroup = (normalizeOptionalLowercaseString(normalized) ?? "").startsWith("group:");
76
+ const peerId = normalized.replace(/^(group|user):/i, "").trim();
77
+ return buildChannelOutboundSessionRoute({
78
+ cfg: params.cfg,
79
+ agentId: params.agentId,
80
+ channel: "zalouser",
81
+ accountId: params.accountId,
82
+ peer: {
83
+ kind: isGroup ? "group" : "direct",
84
+ id: peerId
85
+ },
86
+ chatType: isGroup ? "group" : "direct",
87
+ from: isGroup ? `zalouser:group:${peerId}` : `zalouser:${peerId}`,
88
+ to: `zalouser:${peerId}`
89
+ });
90
+ }
91
+ //#endregion
92
+ export { resolveZalouserOutboundSessionRoute as i, parseZalouserDirectoryGroupId as n, parseZalouserOutboundTarget as r, normalizeZalouserTarget as t };
@@ -0,0 +1,40 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
4
+ import { createDelegatedSetupWizardProxy, createPatchedAccountSetupAdapter } from "openclaw/plugin-sdk/setup-runtime";
5
+ //#region extensions/zalouser/src/qr-temp-file.ts
6
+ async function writeQrDataUrlToTempFile(qrDataUrl, profile) {
7
+ const base64 = (qrDataUrl.trim().match(/^data:image\/png;base64,(.+)$/i)?.[1] ?? "").trim();
8
+ if (!base64) return null;
9
+ const safeProfile = profile.replace(/[^a-zA-Z0-9_-]+/g, "-") || "default";
10
+ const filePath = path.join(resolvePreferredOpenClawTmpDir(), `openclaw-zalouser-qr-${safeProfile}.png`);
11
+ await fsp.writeFile(filePath, Buffer.from(base64, "base64"));
12
+ return filePath;
13
+ }
14
+ //#endregion
15
+ //#region extensions/zalouser/src/setup-core.ts
16
+ const channel = "zalouser";
17
+ const zalouserSetupAdapter = createPatchedAccountSetupAdapter({
18
+ channelKey: channel,
19
+ validateInput: () => null,
20
+ buildPatch: () => ({})
21
+ });
22
+ function createZalouserSetupWizardProxy(loadWizard) {
23
+ return createDelegatedSetupWizardProxy({
24
+ channel,
25
+ loadWizard,
26
+ status: {
27
+ configuredLabel: "logged in",
28
+ unconfiguredLabel: "needs QR login",
29
+ configuredHint: "recommended · logged in",
30
+ unconfiguredHint: "recommended · QR login",
31
+ configuredScore: 1,
32
+ unconfiguredScore: 15
33
+ },
34
+ credentials: [],
35
+ delegatePrepare: true,
36
+ delegateFinalize: true
37
+ });
38
+ }
39
+ //#endregion
40
+ export { zalouserSetupAdapter as n, writeQrDataUrlToTempFile as r, createZalouserSetupWizardProxy as t };
@@ -0,0 +1,11 @@
1
+ import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
+ //#region extensions/zalouser/setup-entry.ts
3
+ var setup_entry_default = defineBundledChannelSetupEntry({
4
+ importMetaUrl: import.meta.url,
5
+ plugin: {
6
+ specifier: "./setup-plugin-api.js",
7
+ exportName: "zalouserSetupPlugin"
8
+ }
9
+ });
10
+ //#endregion
11
+ export { setup_entry_default as default };
@@ -0,0 +1,2 @@
1
+ import { t as zalouserSetupPlugin } from "./channel.setup-CiDeBFrn.js";
2
+ export { zalouserSetupPlugin };