@openclaw/matrix 2026.7.2-beta.4 → 2026.7.2-beta.5
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/README.md +1 -1
- package/dist/api.js +4 -4
- package/dist/{approval-handler.runtime-AsawryfP.js → approval-handler.runtime-D1ibJgSk.js} +4 -4
- package/dist/{approval-ids-XAMP8vN9.js → approval-ids-2OQj32-K.js} +1 -1
- package/dist/{approval-reaction-auth-DButmM13.js → approval-reaction-auth-CCAWWkbu.js} +2 -2
- package/dist/{channel-MBtrY36B.js → channel-Cmi248PA.js} +28 -32
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-Bi4Dgy2P.js → channel.runtime-BaPXFRgT.js} +34 -40
- package/dist/{cli-CcPuMyCk.js → cli-0CNHkps5.js} +863 -843
- package/dist/{cli-metadata-DAhDhbYX.js → cli-metadata-DnXxNCoj.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{client-Dg8dk8NW.js → client-BFRg0kd4.js} +2 -2
- package/dist/{client-BwX6rURh.js → client-CitERujx.js} +2 -2
- package/dist/{client-bootstrap-ZAaO9fZ-.js → client-bootstrap-CkAnkzB6.js} +1 -1
- package/dist/{config-schema-CggnuwnJ.js → config-schema-BShrVROw.js} +16 -2
- package/dist/contract-api.js +2 -2
- package/dist/{create-client-Und1YmJ2.js → create-client-f-CkRllE.js} +3 -3
- package/dist/{crypto-runtime-_j7TpS7k.js → crypto-runtime-D9_6J5tZ.js} +2 -2
- package/dist/{device-health-D4LBxuPq.js → device-health-B4-YXtJR.js} +6 -1
- package/dist/{directory-live-B6fbX6jf.js → directory-live-YRgYDx2w.js} +3 -3
- package/dist/{doctor-C0LPJGTz.js → doctor-CM8ijNpW.js} +1 -1
- package/dist/{doctor-contract-CWVdlRQR.js → doctor-contract-BMSJkkAE.js} +21 -37
- package/dist/doctor-contract-api.js +4 -4
- package/dist/{draft-stream-BfibauH1.js → draft-stream-CIjafRr0.js} +1 -1
- package/dist/{file-sync-store-DUEWCEjb.js → file-sync-store-DiiFsayX.js} +1 -1
- package/dist/{http-client-DOyTG9l2.js → http-client-CycYxU9-.js} +1 -1
- package/dist/{idb-persistence-C6zQfW2w.js → idb-persistence-B6x7dMsF.js} +5 -11
- package/dist/index.js +1 -1
- package/dist/{logging-QH-48Gr6.js → logging-DV-p52N0.js} +8 -1
- package/dist/{media-text-Cv1VIHXW.js → media-text-DlQC_k_K.js} +1 -1
- package/dist/{messages-ClTgfFl6.js → messages-Bf_s--M9.js} +3 -3
- package/dist/{monitor-2BjKS9RV.js → monitor-s--XqoxF.js} +2037 -1803
- package/dist/plugin-entry.handlers.runtime.js +1 -1
- package/dist/probe.runtime-BJOvCHnZ.js +3 -0
- package/dist/{profile-update-C2My3TML.js → profile-update-z3aM46KS.js} +2 -2
- package/dist/{reaction-events-Cj6thhmc.js → reaction-events-DrK9Zua7.js} +2 -2
- package/dist/{recovery-key-store-0O8ARdT_.js → recovery-key-store-BNnHvXdk.js} +1 -1
- package/dist/{resolve-targets-Dn11HT76.js → resolve-targets-nNMcrV3W.js} +1 -1
- package/dist/{resolver.runtime-Zguh0hH9.js → resolver.runtime-BvaFlVLg.js} +1 -1
- package/dist/{room-info-B6vKD5DF.js → room-info-CAFZ3Z9J.js} +13 -12
- package/dist/{sdk-DiRXiRRf.js → sdk-UzPd8tst.js} +227 -181
- package/dist/{send-CZCmDQu8.js → send-C9Ssx-iV.js} +623 -108
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/{setup-bootstrap-C9w01xQK.js → setup-bootstrap-BBGpPKgy.js} +2 -2
- package/dist/{setup-core-D6gyoyeg.js → setup-core-a542Ernq.js} +29 -27
- package/dist/setup-plugin-api.js +3 -3
- package/dist/{setup-surface-DZIEWtQC.js → setup-surface-BJrCI6KT.js} +32 -30
- package/dist/{shared-C7Vm9RxI.js → shared-CUH5otj8.js} +5 -12
- package/dist/{startup-verification-D1nscMh8.js → startup-verification-wm3_i88s.js} +1 -1
- package/dist/{storage-BrkTJZov.js → storage-BvAkgzvT.js} +20 -20
- package/dist/{thread-bindings-BcYBELC7.js → thread-bindings-D3RfVgAF.js} +4 -3
- package/dist/{tool-actions.runtime-Dbco_Vwn.js → tool-actions.runtime-Dh5ow2EK.js} +8 -8
- package/dist/{verification-DhMBWxOJ.js → verification-ZdAXdmuh.js} +1 -1
- package/package.json +4 -5
- package/dist/probe.runtime-BWkgfbiE.js +0 -3
- package/npm-shrinkwrap.json +0 -557
|
@@ -5,13 +5,14 @@ import { r as normalizeMatrixResolvableTarget, t as isMatrixQualifiedUserId } fr
|
|
|
5
5
|
import { n as MATRIX_REACTION_EVENT_TYPE, r as buildMatrixReactionContent, t as MATRIX_ANNOTATION_RELATION_TYPE } from "./reaction-common-DkrQdBSZ.js";
|
|
6
6
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
7
7
|
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
|
|
8
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
|
+
import { normalizeLowercaseStringOrEmpty, normalizeNullableString, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
+
import { FormatCapabilityProfile, convertMarkdownTables, findCodeRegions, isInsideCode, markdownToIR, renderMarkdownWithMarkers, tokenizeHtmlTags } from "openclaw/plugin-sdk/text-chunking";
|
|
9
10
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
10
11
|
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
11
12
|
import { normalizePollInput } from "openclaw/plugin-sdk/poll-runtime";
|
|
12
|
-
import { isVoiceMessageCompatibleAudio } from "openclaw/plugin-sdk/media-runtime";
|
|
13
13
|
import MarkdownIt from "markdown-it";
|
|
14
14
|
import { isAutoLinkedFileRef } from "openclaw/plugin-sdk/text-autolink-runtime";
|
|
15
|
+
import { isVoiceMessageCompatibleAudio } from "openclaw/plugin-sdk/media-runtime";
|
|
15
16
|
import { parseBuffer } from "music-metadata";
|
|
16
17
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
17
18
|
//#region extensions/matrix/src/matrix/poll-types.ts
|
|
@@ -228,36 +229,252 @@ function buildPollResponseContent(pollEventId, answerIds) {
|
|
|
228
229
|
};
|
|
229
230
|
}
|
|
230
231
|
//#endregion
|
|
231
|
-
//#region extensions/matrix/src/matrix/
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
const
|
|
240
|
-
|
|
232
|
+
//#region extensions/matrix/src/matrix/format-profile.ts
|
|
233
|
+
function createMatrixPrivateMarkers(markdown, exhaustedMessage) {
|
|
234
|
+
const used = new Set(Array.from(markdown, (character) => character.charCodeAt(0)));
|
|
235
|
+
for (const match of markdown.matchAll(/&#(?:x([0-9a-f]+)|(\d+));/giu)) {
|
|
236
|
+
const radix = match[1] ? 16 : 10;
|
|
237
|
+
const value = Number.parseInt(match[1] ?? match[2] ?? "", radix);
|
|
238
|
+
if (Number.isFinite(value) && value <= 65535) used.add(value);
|
|
239
|
+
}
|
|
240
|
+
const markers = [];
|
|
241
|
+
for (let code = 57344; code <= 63743 && markers.length < 3; code += 1) if (!used.has(code)) markers.push(String.fromCharCode(code));
|
|
242
|
+
if (markers.length < 3) throw new Error(exhaustedMessage);
|
|
243
|
+
return {
|
|
244
|
+
open: markers[0] ?? "",
|
|
245
|
+
close: markers[1] ?? "",
|
|
246
|
+
padding: markers[2] ?? ""
|
|
247
|
+
};
|
|
241
248
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
249
|
+
const MATRIX_FORMAT_PROFILE = FormatCapabilityProfile.define({
|
|
250
|
+
mechanism: "html",
|
|
251
|
+
constructs: {
|
|
252
|
+
taskList: "fallback",
|
|
253
|
+
image: "fallback"
|
|
254
|
+
},
|
|
255
|
+
chunk: {
|
|
256
|
+
limit: 4e3,
|
|
257
|
+
unit: "chars"
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
function isMarkdownEscaped(markdown, index) {
|
|
261
|
+
let slashCount = 0;
|
|
262
|
+
let cursor = index - 1;
|
|
263
|
+
while (cursor >= 0 && markdown[cursor] === "\\") {
|
|
264
|
+
slashCount += 1;
|
|
265
|
+
cursor -= 1;
|
|
266
|
+
}
|
|
267
|
+
return slashCount % 2 === 1;
|
|
247
268
|
}
|
|
248
|
-
|
|
249
|
-
return
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
269
|
+
function projectMatrixMarkdown(markdown) {
|
|
270
|
+
return renderMarkdownWithMarkers({
|
|
271
|
+
text: (markdown ?? "").replace(/\r\n?/gu, "\n"),
|
|
272
|
+
styles: [],
|
|
273
|
+
links: []
|
|
274
|
+
}, {
|
|
275
|
+
styleMarkers: {},
|
|
276
|
+
escapeText: (text) => text
|
|
277
|
+
}, MATRIX_FORMAT_PROFILE);
|
|
253
278
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
279
|
+
function renderMatrixMarkdownTables(markdown, mode) {
|
|
280
|
+
return MATRIX_FORMAT_PROFILE.constructs.table === "native" && (mode === "off" || mode === "block") ? markdown : convertMarkdownTables(markdown, mode);
|
|
281
|
+
}
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region extensions/matrix/src/matrix/format-table-ranges.ts
|
|
284
|
+
const tableParser = new MarkdownIt({
|
|
285
|
+
html: false,
|
|
286
|
+
linkify: false,
|
|
287
|
+
typographer: false
|
|
288
|
+
});
|
|
289
|
+
function findMatrixTableSourceRanges(markdown) {
|
|
290
|
+
const lineStarts = [0];
|
|
291
|
+
for (let index = 0; index < markdown.length; index += 1) if (markdown[index] === "\n") lineStarts.push(index + 1);
|
|
292
|
+
lineStarts.push(markdown.length);
|
|
293
|
+
return tableParser.parse(markdown, {}).flatMap((token) => {
|
|
294
|
+
if (token.type !== "table_open" || !token.map) return [];
|
|
295
|
+
return [{
|
|
296
|
+
start: lineStarts[token.map[0]] ?? 0,
|
|
297
|
+
end: lineStarts[token.map[1]] ?? markdown.length
|
|
298
|
+
}];
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region extensions/matrix/src/matrix/format-spoiler-ranges.ts
|
|
303
|
+
const spoilerParser = new MarkdownIt({
|
|
304
|
+
html: false,
|
|
305
|
+
linkify: true,
|
|
306
|
+
typographer: false
|
|
307
|
+
});
|
|
308
|
+
function findInlineMetadataRanges(markdown, references) {
|
|
309
|
+
const ranges = [];
|
|
310
|
+
const labelStack = [];
|
|
311
|
+
const codeRegions = findCodeRegions(markdown);
|
|
312
|
+
const underlineTags = [...tokenizeHtmlTags(markdown)].filter((tag) => tag.name === "u" || tag.name === "ins");
|
|
313
|
+
for (let index = 0; index < markdown.length - 1; index += 1) {
|
|
314
|
+
const underlineTag = underlineTags.find((tag) => tag.start === index);
|
|
315
|
+
if (underlineTag) {
|
|
316
|
+
index = underlineTag.end - 1;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (isInsideCode(index, codeRegions)) continue;
|
|
320
|
+
if (markdown[index] === "\n" && markdown[index + 1] === "\n") {
|
|
321
|
+
labelStack.length = 0;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (markdown[index] === "[" && !isMarkdownEscaped(markdown, index)) {
|
|
325
|
+
labelStack.push(index);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (markdown[index] === "]" && markdown[index + 1] === "(" && !isMarkdownEscaped(markdown, index) && labelStack.pop() !== void 0) {
|
|
329
|
+
const start = index + 2;
|
|
330
|
+
let cursor = start;
|
|
331
|
+
while (/[\s]/u.test(markdown[cursor] ?? "")) cursor += 1;
|
|
332
|
+
const destination = spoilerParser.helpers.parseLinkDestination(markdown, cursor, markdown.length);
|
|
333
|
+
if (destination.ok) {
|
|
334
|
+
cursor = destination.pos;
|
|
335
|
+
while (/[\s]/u.test(markdown[cursor] ?? "")) cursor += 1;
|
|
336
|
+
const title = spoilerParser.helpers.parseLinkTitle(markdown, cursor, markdown.length);
|
|
337
|
+
if (title.ok) {
|
|
338
|
+
cursor = title.pos;
|
|
339
|
+
while (/[\s]/u.test(markdown[cursor] ?? "")) cursor += 1;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (destination.ok && markdown[cursor] === ")") {
|
|
343
|
+
ranges.push({
|
|
344
|
+
start,
|
|
345
|
+
end: cursor + 1
|
|
346
|
+
});
|
|
347
|
+
index = cursor;
|
|
348
|
+
}
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (markdown[index] === "]" && markdown[index + 1] === "[" && !isMarkdownEscaped(markdown, index) && labelStack.pop() !== void 0) {
|
|
352
|
+
let end = index + 2;
|
|
353
|
+
while (end < markdown.length && (markdown[end] !== "]" || isMarkdownEscaped(markdown, end))) end += 1;
|
|
354
|
+
const reference = spoilerParser.utils.normalizeReference(markdown.slice(index + 2, end));
|
|
355
|
+
if (end < markdown.length && references.has(reference)) {
|
|
356
|
+
ranges.push({
|
|
357
|
+
start: index + 2,
|
|
358
|
+
end
|
|
359
|
+
});
|
|
360
|
+
index = end;
|
|
361
|
+
}
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (markdown[index] === "]" && !isMarkdownEscaped(markdown, index)) labelStack.pop();
|
|
365
|
+
const autolink = /^<[A-Za-z][A-Za-z0-9+.-]{1,31}:[^<>\s]*>/u.exec(markdown.slice(index));
|
|
366
|
+
if (autolink && !isMarkdownEscaped(markdown, index)) {
|
|
367
|
+
ranges.push({
|
|
368
|
+
start: index,
|
|
369
|
+
end: index + autolink[0].length
|
|
370
|
+
});
|
|
371
|
+
index += autolink[0].length - 1;
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
const emailAutolink = /^<[^<>\s@]+@[^<>\s@]+>/u.exec(markdown.slice(index));
|
|
375
|
+
if (emailAutolink && !isMarkdownEscaped(markdown, index)) {
|
|
376
|
+
ranges.push({
|
|
377
|
+
start: index,
|
|
378
|
+
end: index + emailAutolink[0].length
|
|
379
|
+
});
|
|
380
|
+
index += emailAutolink[0].length - 1;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return ranges;
|
|
384
|
+
}
|
|
385
|
+
function findMatrixMarkdownMetadataRanges(markdown) {
|
|
386
|
+
const env = {};
|
|
387
|
+
const tokens = spoilerParser.parse(markdown, env);
|
|
388
|
+
const references = new Set(Object.keys(env.references ?? {}));
|
|
389
|
+
const lineStarts = [0];
|
|
390
|
+
for (let index = 0; index < markdown.length; index += 1) if (markdown[index] === "\n") lineStarts.push(index + 1);
|
|
391
|
+
lineStarts.push(markdown.length);
|
|
392
|
+
const ranges = tokens.flatMap((token) => {
|
|
393
|
+
if (token.type !== "inline" || !token.map) return [];
|
|
394
|
+
const start = lineStarts[token.map[0]] ?? 0;
|
|
395
|
+
const end = lineStarts[token.map[1]] ?? markdown.length;
|
|
396
|
+
return findInlineMetadataRanges(markdown.slice(start, end), references).map((range) => ({
|
|
397
|
+
start: start + range.start,
|
|
398
|
+
end: start + range.end
|
|
399
|
+
}));
|
|
400
|
+
});
|
|
401
|
+
for (const match of markdown.matchAll(/^\s*\[[^\]\n]+\]:\s*.+$/gmu)) {
|
|
402
|
+
const start = match.index ?? 0;
|
|
403
|
+
const labelEnd = match[0].indexOf("]:");
|
|
404
|
+
const reference = spoilerParser.utils.normalizeReference(match[0].slice(1, labelEnd));
|
|
405
|
+
if (references.has(reference)) {
|
|
406
|
+
let end = start + match[0].length;
|
|
407
|
+
const continuation = /^\n[ \t]+(?:"[^"\n]*"|'[^'\n]*'|\([^\n)]*\))[ \t]*/u.exec(markdown.slice(end));
|
|
408
|
+
end += continuation?.[0].length ?? 0;
|
|
409
|
+
ranges.push({
|
|
410
|
+
start,
|
|
411
|
+
end
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const codeRegions = findCodeRegions(markdown);
|
|
416
|
+
for (const match of spoilerParser.linkify.match(markdown) ?? []) if (!isInsideCode(match.index, codeRegions)) ranges.push({
|
|
417
|
+
start: match.index,
|
|
418
|
+
end: match.lastIndex
|
|
419
|
+
});
|
|
420
|
+
return ranges;
|
|
421
|
+
}
|
|
422
|
+
function findMatrixSpoilerDelimiterOffsets(markdown) {
|
|
423
|
+
const projected = projectMatrixMarkdown(markdown);
|
|
424
|
+
const tokens = spoilerParser.parse(projected, {});
|
|
425
|
+
const lineStarts = [0];
|
|
426
|
+
for (let index = 0; index < projected.length; index += 1) if (projected[index] === "\n") lineStarts.push(index + 1);
|
|
427
|
+
lineStarts.push(projected.length);
|
|
428
|
+
const excludedRanges = [
|
|
429
|
+
...findCodeRegions(projected),
|
|
430
|
+
...findMatrixMarkdownMetadataRanges(projected),
|
|
431
|
+
...[...tokenizeHtmlTags(projected)].flatMap((tag) => tag.name === "u" || tag.name === "ins" ? [{
|
|
432
|
+
start: tag.start,
|
|
433
|
+
end: tag.end
|
|
434
|
+
}] : [])
|
|
435
|
+
];
|
|
436
|
+
const offsets = [];
|
|
437
|
+
for (const token of tokens) {
|
|
438
|
+
if (token.type !== "inline" || !token.map) continue;
|
|
439
|
+
const start = lineStarts[token.map[0]] ?? 0;
|
|
440
|
+
const end = lineStarts[token.map[1]] ?? projected.length;
|
|
441
|
+
const candidates = [];
|
|
442
|
+
for (let index = start; index < end - 1; index += 1) {
|
|
443
|
+
if (projected[index] !== "|" || projected[index + 1] !== "|") continue;
|
|
444
|
+
const excluded = excludedRanges.some((range) => index >= range.start && index < range.end);
|
|
445
|
+
if (isMarkdownEscaped(projected, index) || excluded) continue;
|
|
446
|
+
candidates.push(index);
|
|
447
|
+
index += 1;
|
|
448
|
+
}
|
|
449
|
+
candidates.length -= candidates.length % 2;
|
|
450
|
+
offsets.push(...candidates);
|
|
451
|
+
}
|
|
452
|
+
return [...new Set(offsets)].toSorted((left, right) => left - right);
|
|
453
|
+
}
|
|
454
|
+
function hasMatrixSpoilerMetadataCollision(markdown) {
|
|
455
|
+
const projected = projectMatrixMarkdown(markdown);
|
|
456
|
+
const ordinary = new Set(findMatrixSpoilerDelimiterOffsets(projected));
|
|
457
|
+
const tables = findMatrixTableSourceRanges(projected);
|
|
458
|
+
for (let index = 0; index < projected.length - 1; index += 1) {
|
|
459
|
+
if (projected[index] !== "|" || projected[index + 1] !== "|") continue;
|
|
460
|
+
if (ordinary.has(index) || isMarkdownEscaped(projected, index)) continue;
|
|
461
|
+
if (tables.some((range) => index >= range.start && index < range.end)) continue;
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
return false;
|
|
258
465
|
}
|
|
259
466
|
//#endregion
|
|
260
467
|
//#region extensions/matrix/src/matrix/format.ts
|
|
468
|
+
const MATRIX_STYLE_MARKERS = {
|
|
469
|
+
underline: {
|
|
470
|
+
open: "<u>",
|
|
471
|
+
close: "</u>"
|
|
472
|
+
},
|
|
473
|
+
spoiler: {
|
|
474
|
+
open: "<span data-mx-spoiler>",
|
|
475
|
+
close: "</span>"
|
|
476
|
+
}
|
|
477
|
+
};
|
|
261
478
|
const md = new MarkdownIt({
|
|
262
479
|
html: false,
|
|
263
480
|
linkify: true,
|
|
@@ -270,6 +487,27 @@ const ESCAPED_MENTION_SENTINEL = "";
|
|
|
270
487
|
const MENTION_PATTERN = /@[A-Za-z0-9._=+\-/:[\]]+/g;
|
|
271
488
|
const MATRIX_MENTION_USER_ID_PATTERN = new RegExp(`^@[A-Za-z0-9._=+\\-/]+:(?:${/(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)(?:\.(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?))*(?::\d+)?/.source}|\\[[0-9A-Fa-f:.]+\\](?::\\d+)?)$`);
|
|
272
489
|
const TRIMMABLE_MENTION_SUFFIX = /[),.!?:;\]]/;
|
|
490
|
+
const parseMatrixUnderline = (state, silent) => {
|
|
491
|
+
if (state.src.charCodeAt(state.pos) !== 60) return false;
|
|
492
|
+
const tag = tokenizeHtmlTags(state.src.slice(state.pos)).next().value;
|
|
493
|
+
if (!tag || tag.start !== 0 || tag.name !== "u" && tag.name !== "ins") return false;
|
|
494
|
+
if (!silent) {
|
|
495
|
+
const token = state.push(tag.selfClosing ? "text" : tag.closing ? "matrix_underline_close" : "matrix_underline_open", tag.selfClosing ? "" : "u", tag.selfClosing ? 0 : tag.closing ? -1 : 1);
|
|
496
|
+
if (tag.selfClosing) token.content = tag.raw;
|
|
497
|
+
}
|
|
498
|
+
state.pos += tag.end;
|
|
499
|
+
return true;
|
|
500
|
+
};
|
|
501
|
+
md.inline.ruler.before("html_inline", "matrix_underline", parseMatrixUnderline);
|
|
502
|
+
md.renderer.rules.matrix_underline_open = () => MATRIX_STYLE_MARKERS.underline.open;
|
|
503
|
+
md.renderer.rules.matrix_underline_close = () => MATRIX_STYLE_MARKERS.underline.close;
|
|
504
|
+
md.renderer.rules.matrix_spoiler_open = () => MATRIX_STYLE_MARKERS.spoiler.open;
|
|
505
|
+
md.renderer.rules.matrix_spoiler_close = () => MATRIX_STYLE_MARKERS.spoiler.close;
|
|
506
|
+
md.core.ruler.after("inline", "matrix_spoilers", (state) => {
|
|
507
|
+
const markers = state.env.matrixSpoilerMarkers;
|
|
508
|
+
if (!markers) return;
|
|
509
|
+
for (const token of state.tokens) if (token.children?.length) token.children = normalizeMatrixSpoilerNesting(injectProtectedMatrixSpoilers(token.children, markers));
|
|
510
|
+
});
|
|
273
511
|
function shouldSuppressAutoLink(tokens, idx) {
|
|
274
512
|
const token = tokens[idx];
|
|
275
513
|
if (token?.type !== "link_open" || token.info !== "auto") return false;
|
|
@@ -277,7 +515,10 @@ function shouldSuppressAutoLink(tokens, idx) {
|
|
|
277
515
|
const label = tokens[idx + 1]?.type === "text" ? tokens[idx + 1]?.content ?? "" : "";
|
|
278
516
|
return Boolean(href && label && isAutoLinkedFileRef(href, label));
|
|
279
517
|
}
|
|
280
|
-
md.renderer.rules.image = (tokens, idx) =>
|
|
518
|
+
md.renderer.rules.image = (tokens, idx, options, env, self) => {
|
|
519
|
+
const token = tokens[idx];
|
|
520
|
+
return token?.children?.length ? self.renderInline(token.children, options, env) : escapeHtml(token?.content ?? "");
|
|
521
|
+
};
|
|
281
522
|
md.renderer.rules.html_block = (tokens, idx) => escapeHtml(tokens[idx]?.content ?? "");
|
|
282
523
|
md.renderer.rules.html_inline = (tokens, idx) => escapeHtml(tokens[idx]?.content ?? "");
|
|
283
524
|
md.renderer.rules.link_open = (tokens, idx, _options, _env, self) => shouldSuppressAutoLink(tokens, idx) ? "" : self.renderToken(tokens, idx, _options);
|
|
@@ -310,15 +551,6 @@ function maskEscapedMentions(markdown) {
|
|
|
310
551
|
}
|
|
311
552
|
return masked;
|
|
312
553
|
}
|
|
313
|
-
function isMarkdownEscaped(markdown, idx) {
|
|
314
|
-
let slashCount = 0;
|
|
315
|
-
let cursor = idx - 1;
|
|
316
|
-
while (cursor >= 0 && markdown[cursor] === "\\") {
|
|
317
|
-
slashCount += 1;
|
|
318
|
-
cursor -= 1;
|
|
319
|
-
}
|
|
320
|
-
return slashCount % 2 === 1;
|
|
321
|
-
}
|
|
322
554
|
function restoreEscapedMentions(text) {
|
|
323
555
|
return text.replaceAll(ESCAPED_MENTION_SENTINEL, "@");
|
|
324
556
|
}
|
|
@@ -388,6 +620,67 @@ function createTextToken(sample, content) {
|
|
|
388
620
|
token.content = content;
|
|
389
621
|
return token;
|
|
390
622
|
}
|
|
623
|
+
function injectProtectedMatrixSpoilers(tokens, markers) {
|
|
624
|
+
const result = [];
|
|
625
|
+
for (const token of tokens) {
|
|
626
|
+
if (token.type !== "text") {
|
|
627
|
+
if (token.children?.length) token.children = normalizeMatrixSpoilerNesting(injectProtectedMatrixSpoilers(token.children, markers));
|
|
628
|
+
result.push(token);
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
let cursor = 0;
|
|
632
|
+
for (let index = 0; index < token.content.length; index += 1) {
|
|
633
|
+
const marker = token.content[index];
|
|
634
|
+
if (marker !== markers.open && marker !== markers.close || token.content[index + 1] !== markers.padding) continue;
|
|
635
|
+
if (index > cursor) result.push(createTextToken(token, token.content.slice(cursor, index)));
|
|
636
|
+
result.push(createToken(token, marker === markers.open ? "matrix_spoiler_open" : "matrix_spoiler_close", "span", marker === markers.open ? 1 : -1));
|
|
637
|
+
index += 1;
|
|
638
|
+
cursor = index + 1;
|
|
639
|
+
}
|
|
640
|
+
if (cursor < token.content.length) result.push(createTextToken(token, token.content.slice(cursor)));
|
|
641
|
+
}
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
function copyInlineToken(sample, type, tag, nesting) {
|
|
645
|
+
const token = createToken(sample, type, tag, nesting);
|
|
646
|
+
token.markup = sample.markup;
|
|
647
|
+
token.attrs = sample.attrs ? [...sample.attrs] : null;
|
|
648
|
+
return token;
|
|
649
|
+
}
|
|
650
|
+
function normalizeMatrixSpoilerNesting(tokens) {
|
|
651
|
+
const result = [];
|
|
652
|
+
const stack = [];
|
|
653
|
+
for (const token of tokens) {
|
|
654
|
+
if (token.nesting === 1) {
|
|
655
|
+
stack.push(token);
|
|
656
|
+
result.push(token);
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (token.nesting !== -1) {
|
|
660
|
+
result.push(token);
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
const openIndex = stack.findLastIndex((open) => open.tag === token.tag);
|
|
664
|
+
if (openIndex < 0) {
|
|
665
|
+
result.push(token);
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
if (openIndex === stack.length - 1) {
|
|
669
|
+
stack.pop();
|
|
670
|
+
result.push(token);
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
const crossing = stack.splice(openIndex + 1);
|
|
674
|
+
for (const open of crossing.toReversed()) result.push(copyInlineToken(open, open.type.replace(/_open$/u, "_close"), open.tag, -1));
|
|
675
|
+
stack.pop();
|
|
676
|
+
result.push(token);
|
|
677
|
+
for (const open of crossing) {
|
|
678
|
+
result.push(copyInlineToken(open, open.type, open.tag, 1));
|
|
679
|
+
stack.push(open);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return result;
|
|
683
|
+
}
|
|
391
684
|
function createMentionLinkTokens(params) {
|
|
392
685
|
const open = createToken(params.sample, "link_open", "a", 1);
|
|
393
686
|
open.attrSet("href", params.href);
|
|
@@ -497,14 +790,64 @@ function compactLooseListTokens(tokens) {
|
|
|
497
790
|
else if (token.type === "paragraph_close") currentItem.immediateParagraphCloseIndexes.push(index);
|
|
498
791
|
}
|
|
499
792
|
}
|
|
500
|
-
function markdownToMatrixHtml(markdown) {
|
|
501
|
-
|
|
793
|
+
function markdownToMatrixHtml(markdown, options = {}) {
|
|
794
|
+
if (hasMatrixSpoilerMetadataCollision(markdown)) return renderMatrixFallbackHtml(markdown);
|
|
795
|
+
const tokens = parseMatrixMarkdown(projectMatrixMarkdown(markdown), options.tableMode);
|
|
502
796
|
compactLooseListTokens(tokens);
|
|
503
797
|
return md.renderer.render(tokens, md.options, {}).trimEnd();
|
|
504
798
|
}
|
|
799
|
+
function protectMatrixSpoilerDelimiters(markdown) {
|
|
800
|
+
const offsets = findMatrixSpoilerDelimiterOffsets(markdown);
|
|
801
|
+
if (offsets.length === 0) return { markdown };
|
|
802
|
+
const markers = createMatrixPrivateMarkers(markdown, "Matrix spoiler formatting exhausted its private marker pool");
|
|
803
|
+
let protectedMarkdown = "";
|
|
804
|
+
let cursor = 0;
|
|
805
|
+
for (const [index, offset] of offsets.entries()) {
|
|
806
|
+
const marker = index % 2 === 0 ? markers.open : markers.close;
|
|
807
|
+
protectedMarkdown += `${markdown.slice(cursor, offset)}${marker}${markers.padding}`;
|
|
808
|
+
cursor = offset + 2;
|
|
809
|
+
}
|
|
810
|
+
protectedMarkdown += markdown.slice(cursor);
|
|
811
|
+
return {
|
|
812
|
+
markdown: protectedMarkdown,
|
|
813
|
+
markers
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function parseMatrixMarkdown(markdown, tableMode) {
|
|
817
|
+
const protectedSpoilers = protectMatrixSpoilerDelimiters(markdown);
|
|
818
|
+
if (tableMode === "off") md.disable("table");
|
|
819
|
+
try {
|
|
820
|
+
return md.parse(protectedSpoilers.markdown, { matrixSpoilerMarkers: protectedSpoilers.markers });
|
|
821
|
+
} finally {
|
|
822
|
+
if (tableMode === "off") md.enable("table");
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
function markdownToMatrixBody(markdown) {
|
|
826
|
+
const projected = projectMatrixMarkdown(markdown);
|
|
827
|
+
const offsets = findMatrixSpoilerDelimiterOffsets(projected);
|
|
828
|
+
const metadataCollision = hasMatrixSpoilerMetadataCollision(projected);
|
|
829
|
+
if (offsets.length === 0 && !metadataCollision) return projected;
|
|
830
|
+
let body = projected;
|
|
831
|
+
if (metadataCollision) body = "[Spoiler]";
|
|
832
|
+
else for (let index = offsets.length - 2; index >= 0; index -= 2) {
|
|
833
|
+
const open = offsets[index];
|
|
834
|
+
const close = offsets[index + 1];
|
|
835
|
+
if (open !== void 0 && close !== void 0) body = `${body.slice(0, open)}[Spoiler]${body.slice(close + 2)}`;
|
|
836
|
+
}
|
|
837
|
+
return renderMarkdownWithMarkers(markdownToIR(body, {
|
|
838
|
+
enableHtmlUnderline: true,
|
|
839
|
+
headingStyle: "rich",
|
|
840
|
+
linkify: true
|
|
841
|
+
}), {
|
|
842
|
+
styleMarkers: {},
|
|
843
|
+
escapeText: (text) => text
|
|
844
|
+
}, MATRIX_FORMAT_PROFILE);
|
|
845
|
+
}
|
|
846
|
+
function renderMatrixFallbackHtml(markdown) {
|
|
847
|
+
return `<p>${escapeHtml(markdownToMatrixBody(markdown)).replaceAll("\n", "<br>\n")}</p>`;
|
|
848
|
+
}
|
|
505
849
|
async function resolveMarkdownMentionState(params) {
|
|
506
|
-
const
|
|
507
|
-
const tokens = md.parse(markdown, {});
|
|
850
|
+
const tokens = parseMatrixMarkdown(maskEscapedMentions(projectMatrixMarkdown(params.markdown)), params.tableMode);
|
|
508
851
|
restoreEscapedMentionsInBlockTokens(tokens);
|
|
509
852
|
const selfUserId = await resolveMatrixSelfUserId(params.client);
|
|
510
853
|
const userIds = [];
|
|
@@ -534,6 +877,17 @@ async function resolveMatrixMentionsInMarkdown(params) {
|
|
|
534
877
|
}
|
|
535
878
|
async function renderMarkdownToMatrixHtmlWithMentions(params) {
|
|
536
879
|
const state = await resolveMarkdownMentionState(params);
|
|
880
|
+
if (hasMatrixSpoilerMetadataCollision(params.markdown)) {
|
|
881
|
+
const redacted = markdownToMatrixBody(params.markdown);
|
|
882
|
+
const redactedState = await resolveMarkdownMentionState({
|
|
883
|
+
...params,
|
|
884
|
+
markdown: redacted
|
|
885
|
+
});
|
|
886
|
+
return {
|
|
887
|
+
html: renderMatrixFallbackHtml(params.markdown),
|
|
888
|
+
mentions: redactedState.mentions
|
|
889
|
+
};
|
|
890
|
+
}
|
|
537
891
|
compactLooseListTokens(state.tokens);
|
|
538
892
|
return {
|
|
539
893
|
html: md.renderer.render(state.tokens, md.options, {}).trimEnd() || void 0,
|
|
@@ -541,6 +895,189 @@ async function renderMarkdownToMatrixHtmlWithMentions(params) {
|
|
|
541
895
|
};
|
|
542
896
|
}
|
|
543
897
|
//#endregion
|
|
898
|
+
//#region extensions/matrix/src/matrix/send/chunking.ts
|
|
899
|
+
const getCore$2 = () => getMatrixRuntime();
|
|
900
|
+
function protectMatrixUnderlineTags(markdown) {
|
|
901
|
+
const codeRegions = findCodeRegions(markdown);
|
|
902
|
+
const metadataRanges = findMatrixMarkdownMetadataRanges(markdown);
|
|
903
|
+
const tags = [...tokenizeHtmlTags(markdown)].filter((tag) => (tag.name === "u" || tag.name === "ins") && !tag.selfClosing && !isInsideCode(tag.start, codeRegions) && !isMarkdownEscaped(markdown, tag.start) && !metadataRanges.some((range) => tag.start >= range.start && tag.start < range.end));
|
|
904
|
+
if (tags.length === 0) return { markdown };
|
|
905
|
+
const markers = createMatrixPrivateMarkers(markdown, "Matrix underline chunking exhausted its private marker pool");
|
|
906
|
+
let depth = 0;
|
|
907
|
+
const replacements = tags.flatMap((tag) => {
|
|
908
|
+
if (!tag.closing) {
|
|
909
|
+
depth += 1;
|
|
910
|
+
return [{
|
|
911
|
+
tag,
|
|
912
|
+
marker: depth === 1 ? markers.open : ""
|
|
913
|
+
}];
|
|
914
|
+
}
|
|
915
|
+
if (depth === 0) return [];
|
|
916
|
+
depth -= 1;
|
|
917
|
+
return [{
|
|
918
|
+
tag,
|
|
919
|
+
marker: depth === 0 ? markers.close : ""
|
|
920
|
+
}];
|
|
921
|
+
});
|
|
922
|
+
let protectedMarkdown = markdown;
|
|
923
|
+
for (const { tag, marker } of replacements.toReversed()) protectedMarkdown = `${protectedMarkdown.slice(0, tag.start)}${marker}${markers.padding.repeat(tag.raw.length - marker.length)}${protectedMarkdown.slice(tag.end)}`;
|
|
924
|
+
return {
|
|
925
|
+
markdown: protectedMarkdown,
|
|
926
|
+
markers
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
function restoreMatrixStyleChunks(chunks, spoiler, underline) {
|
|
930
|
+
const stack = [];
|
|
931
|
+
const syntax = {
|
|
932
|
+
spoiler: {
|
|
933
|
+
open: "||",
|
|
934
|
+
close: "||",
|
|
935
|
+
markers: spoiler
|
|
936
|
+
},
|
|
937
|
+
underline: {
|
|
938
|
+
open: "<u>",
|
|
939
|
+
close: "</u>",
|
|
940
|
+
markers: underline
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
return chunks.map((chunk) => {
|
|
944
|
+
let restored = stack.map((style) => syntax[style].open).join("");
|
|
945
|
+
for (const character of chunk) {
|
|
946
|
+
const opening = Object.keys(syntax).find((style) => character === syntax[style].markers?.open);
|
|
947
|
+
const closing = Object.keys(syntax).find((style) => character === syntax[style].markers?.close);
|
|
948
|
+
if (opening) {
|
|
949
|
+
stack.push(opening);
|
|
950
|
+
restored += syntax[opening].open;
|
|
951
|
+
} else if (closing) {
|
|
952
|
+
const stackIndex = stack.lastIndexOf(closing);
|
|
953
|
+
if (stackIndex >= 0) {
|
|
954
|
+
const above = stack.slice(stackIndex + 1);
|
|
955
|
+
restored += above.toReversed().map((style) => syntax[style].close).join("");
|
|
956
|
+
restored += syntax[closing].close;
|
|
957
|
+
stack.splice(stackIndex, 1);
|
|
958
|
+
restored += above.map((style) => syntax[style].open).join("");
|
|
959
|
+
}
|
|
960
|
+
} else if (character !== spoiler?.padding && character !== underline?.padding) restored += character;
|
|
961
|
+
}
|
|
962
|
+
return restored + stack.toReversed().map((style) => syntax[style].close).join("");
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
function splitMatrixTableSegments(markdown) {
|
|
966
|
+
const segments = [];
|
|
967
|
+
let cursor = 0;
|
|
968
|
+
for (const range of findMatrixTableSourceRanges(markdown)) {
|
|
969
|
+
const plain = markdown.slice(cursor, range.start).replace(/(?:[ \t]*\n)+$/u, "");
|
|
970
|
+
if (plain.trim()) segments.push({
|
|
971
|
+
table: false,
|
|
972
|
+
text: plain
|
|
973
|
+
});
|
|
974
|
+
const rawTable = markdown.slice(range.start, range.end).trimEnd();
|
|
975
|
+
const indent = /^ +/u.exec(rawTable)?.[0] ?? "";
|
|
976
|
+
const table = indent ? rawTable.split("\n").map((line) => line.startsWith(indent) ? line.slice(indent.length) : line).join("\n") : rawTable;
|
|
977
|
+
segments.push({
|
|
978
|
+
table: true,
|
|
979
|
+
text: table
|
|
980
|
+
});
|
|
981
|
+
cursor = range.end;
|
|
982
|
+
}
|
|
983
|
+
const tail = markdown.slice(cursor).replace(/^(?:[ \t]*\n)+/u, "");
|
|
984
|
+
if (tail.trim()) segments.push({
|
|
985
|
+
table: false,
|
|
986
|
+
text: tail
|
|
987
|
+
});
|
|
988
|
+
return segments;
|
|
989
|
+
}
|
|
990
|
+
function prepareMatrixSingleText(text, opts) {
|
|
991
|
+
const normalizedText = text.replace(/\r\n?/gu, "\n");
|
|
992
|
+
const trimmedText = opts.preserveWhitespace ? normalizedText : normalizedText.trim();
|
|
993
|
+
const cfg = requireRuntimeConfig(opts.cfg, "Matrix text preparation");
|
|
994
|
+
const tableMode = opts.tableMode ?? getCore$2().channel.text.resolveMarkdownTableMode({
|
|
995
|
+
cfg,
|
|
996
|
+
channel: "matrix",
|
|
997
|
+
accountId: opts.accountId,
|
|
998
|
+
supportsBlockTables: MATRIX_FORMAT_PROFILE.constructs.table === "native"
|
|
999
|
+
});
|
|
1000
|
+
const singleEventLimit = Math.min(getCore$2().channel.text.resolveTextChunkLimit(cfg, "matrix", opts.accountId), MATRIX_FORMAT_PROFILE.chunk.limit);
|
|
1001
|
+
const convertedText = renderMatrixMarkdownTables(trimmedText, tableMode);
|
|
1002
|
+
const eventTextLength = Math.max(convertedText.length, markdownToMatrixBody(convertedText).length);
|
|
1003
|
+
return {
|
|
1004
|
+
trimmedText,
|
|
1005
|
+
convertedText,
|
|
1006
|
+
singleEventLimit,
|
|
1007
|
+
eventTextLength,
|
|
1008
|
+
fitsInSingleEvent: eventTextLength <= singleEventLimit,
|
|
1009
|
+
tableMode
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
function chunkMatrixText(text, opts) {
|
|
1013
|
+
const preparedText = prepareMatrixSingleText(text, opts);
|
|
1014
|
+
if (preparedText.fitsInSingleEvent) return {
|
|
1015
|
+
...preparedText,
|
|
1016
|
+
chunks: preparedText.convertedText ? [preparedText.convertedText] : []
|
|
1017
|
+
};
|
|
1018
|
+
const cfg = requireRuntimeConfig(opts.cfg, "Matrix text chunking");
|
|
1019
|
+
const chunkMode = getCore$2().channel.text.resolveChunkMode(cfg, "matrix", opts.accountId);
|
|
1020
|
+
const collisionRedacted = hasMatrixSpoilerMetadataCollision(preparedText.convertedText) ? markdownToMatrixBody(preparedText.convertedText) : void 0;
|
|
1021
|
+
const chunkSegment = (segmentText) => {
|
|
1022
|
+
const protectedUnderline = protectMatrixUnderlineTags(hasMatrixSpoilerMetadataCollision(segmentText) ? markdownToMatrixBody(segmentText) : segmentText);
|
|
1023
|
+
const protectedSpoilers = protectMatrixSpoilerDelimiters(protectedUnderline.markdown);
|
|
1024
|
+
const wrapperReserve = (protectedSpoilers.markers ? 4 : 0) + (protectedUnderline.markers ? 7 : 0);
|
|
1025
|
+
const privateMarkers = [protectedSpoilers.markers, protectedUnderline.markers].flatMap((markers) => markers ? [
|
|
1026
|
+
markers.open,
|
|
1027
|
+
markers.close,
|
|
1028
|
+
markers.padding
|
|
1029
|
+
] : []);
|
|
1030
|
+
let reserve = wrapperReserve;
|
|
1031
|
+
while (reserve < preparedText.singleEventLimit) {
|
|
1032
|
+
const protectedChunks = getCore$2().channel.text.chunkMarkdownTextWithMode(protectedSpoilers.markdown, preparedText.singleEventLimit - reserve, chunkMode);
|
|
1033
|
+
const restored = restoreMatrixStyleChunks(protectedChunks, protectedSpoilers.markers, protectedUnderline.markers).filter((_, index) => {
|
|
1034
|
+
return privateMarkers.reduce((value, marker) => value.replaceAll(marker, ""), protectedChunks[index] ?? "").length > 0;
|
|
1035
|
+
});
|
|
1036
|
+
const overflow = Math.max(0, ...restored.map((chunk) => Math.max(chunk.length, markdownToMatrixBody(chunk).length) - preparedText.singleEventLimit));
|
|
1037
|
+
if (overflow === 0) return restored;
|
|
1038
|
+
reserve += overflow;
|
|
1039
|
+
}
|
|
1040
|
+
throw new Error("Matrix text chunk limit is too small for formatted content");
|
|
1041
|
+
};
|
|
1042
|
+
const chunks = collisionRedacted !== void 0 ? chunkSegment(collisionRedacted) : preparedText.tableMode === "block" ? splitMatrixTableSegments(preparedText.convertedText).flatMap((segment) => {
|
|
1043
|
+
if (!segment.table) return chunkSegment(segment.text);
|
|
1044
|
+
return segment.text.length <= preparedText.singleEventLimit ? [segment.text] : chunkSegment(renderMatrixMarkdownTables(segment.text, "bullets"));
|
|
1045
|
+
}) : chunkSegment(preparedText.convertedText);
|
|
1046
|
+
return {
|
|
1047
|
+
...preparedText,
|
|
1048
|
+
chunks
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
//#endregion
|
|
1052
|
+
//#region extensions/matrix/src/matrix/send/client.ts
|
|
1053
|
+
const loadMatrixSendClientRuntime = createLazyRuntimeModule(() => import("./client-bootstrap-CkAnkzB6.js").then((n) => n.t));
|
|
1054
|
+
function resolveMediaMaxBytes(accountId, cfg) {
|
|
1055
|
+
if (!cfg) throw new Error("Matrix media limits requires a resolved runtime config. Load and resolve config at the command or gateway boundary, then pass cfg through the runtime path.");
|
|
1056
|
+
const matrixCfg = resolveMatrixAccountConfig({
|
|
1057
|
+
cfg: requireRuntimeConfig(cfg, "Matrix media limits"),
|
|
1058
|
+
accountId
|
|
1059
|
+
});
|
|
1060
|
+
const mediaMaxMb = typeof matrixCfg.mediaMaxMb === "number" ? matrixCfg.mediaMaxMb : void 0;
|
|
1061
|
+
if (typeof mediaMaxMb === "number") return mediaMaxMb * 1024 * 1024;
|
|
1062
|
+
}
|
|
1063
|
+
async function withResolvedMatrixSendClient(opts, run) {
|
|
1064
|
+
return await withResolvedMatrixClient({
|
|
1065
|
+
...opts,
|
|
1066
|
+
readiness: "started"
|
|
1067
|
+
}, run, "persist");
|
|
1068
|
+
}
|
|
1069
|
+
async function withResolvedMatrixControlClient(opts, run) {
|
|
1070
|
+
return await withResolvedMatrixClient({
|
|
1071
|
+
...opts,
|
|
1072
|
+
readiness: "none"
|
|
1073
|
+
}, run);
|
|
1074
|
+
}
|
|
1075
|
+
async function withResolvedMatrixClient(opts, run, shutdownBehavior) {
|
|
1076
|
+
if (opts.client) return await run(opts.client);
|
|
1077
|
+
const { withResolvedRuntimeMatrixClient } = await loadMatrixSendClientRuntime();
|
|
1078
|
+
return await withResolvedRuntimeMatrixClient(opts, run, shutdownBehavior);
|
|
1079
|
+
}
|
|
1080
|
+
//#endregion
|
|
544
1081
|
//#region extensions/matrix/src/matrix/send/types.ts
|
|
545
1082
|
const MsgType = {
|
|
546
1083
|
Text: "m.text",
|
|
@@ -572,15 +1109,21 @@ const MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY = "com.openclaw.finalized_preview";
|
|
|
572
1109
|
const MSC4357_LIVE_KEY = "org.matrix.msc4357.live";
|
|
573
1110
|
//#endregion
|
|
574
1111
|
//#region extensions/matrix/src/matrix/send/formatting.ts
|
|
575
|
-
const getCore$
|
|
1112
|
+
const getCore$1 = () => getMatrixRuntime();
|
|
576
1113
|
async function renderMatrixFormattedContent(params) {
|
|
577
1114
|
const markdown = params.markdown ?? "";
|
|
578
|
-
|
|
1115
|
+
const body = markdownToMatrixBody(markdown);
|
|
1116
|
+
if (params.includeMentions === false) return {
|
|
1117
|
+
body,
|
|
1118
|
+
html: markdownToMatrixHtml(markdown, { tableMode: params.tableMode }).trimEnd() || void 0
|
|
1119
|
+
};
|
|
579
1120
|
const { html, mentions } = await renderMarkdownToMatrixHtmlWithMentions({
|
|
580
1121
|
markdown,
|
|
581
|
-
client: params.client
|
|
1122
|
+
client: params.client,
|
|
1123
|
+
tableMode: params.tableMode
|
|
582
1124
|
});
|
|
583
1125
|
return {
|
|
1126
|
+
body,
|
|
584
1127
|
html,
|
|
585
1128
|
mentions
|
|
586
1129
|
};
|
|
@@ -597,11 +1140,13 @@ function buildTextContent(body, relation, opts = {}) {
|
|
|
597
1140
|
};
|
|
598
1141
|
}
|
|
599
1142
|
async function enrichMatrixFormattedContent(params) {
|
|
600
|
-
const { html, mentions } = await renderMatrixFormattedContent({
|
|
1143
|
+
const { body, html, mentions } = await renderMatrixFormattedContent({
|
|
601
1144
|
client: params.client,
|
|
602
1145
|
markdown: params.markdown,
|
|
603
|
-
includeMentions: params.includeMentions
|
|
1146
|
+
includeMentions: params.includeMentions,
|
|
1147
|
+
tableMode: params.tableMode
|
|
604
1148
|
});
|
|
1149
|
+
params.content.body = body || params.content.body;
|
|
605
1150
|
if (mentions) params.content["m.mentions"] = mentions;
|
|
606
1151
|
else delete params.content["m.mentions"];
|
|
607
1152
|
if (!html) {
|
|
@@ -658,7 +1203,7 @@ function buildThreadRelation(threadId, replyToId) {
|
|
|
658
1203
|
return relation;
|
|
659
1204
|
}
|
|
660
1205
|
function resolveMatrixMsgType(contentType, _fileName) {
|
|
661
|
-
switch (getCore$
|
|
1206
|
+
switch (getCore$1().media.mediaKindFromMime(contentType ?? "")) {
|
|
662
1207
|
case "image": return MsgType.Image;
|
|
663
1208
|
case "audio": return MsgType.Audio;
|
|
664
1209
|
case "video": return MsgType.Video;
|
|
@@ -678,7 +1223,7 @@ function isMatrixVoiceCompatibleAudio(opts) {
|
|
|
678
1223
|
}
|
|
679
1224
|
//#endregion
|
|
680
1225
|
//#region extensions/matrix/src/matrix/send/media.ts
|
|
681
|
-
const getCore
|
|
1226
|
+
const getCore = () => getMatrixRuntime();
|
|
682
1227
|
function buildMatrixMediaInfo(params) {
|
|
683
1228
|
const base = {};
|
|
684
1229
|
if (Number.isFinite(params.size)) base.size = params.size;
|
|
@@ -726,20 +1271,20 @@ function buildMediaContent(params) {
|
|
|
726
1271
|
const THUMBNAIL_MAX_SIDE = 800;
|
|
727
1272
|
const THUMBNAIL_QUALITY = 80;
|
|
728
1273
|
async function prepareImageInfo(params) {
|
|
729
|
-
const meta = await getCore
|
|
1274
|
+
const meta = await getCore().media.getImageMetadata(params.buffer).catch(() => null);
|
|
730
1275
|
if (!meta) return;
|
|
731
1276
|
const imageInfo = {
|
|
732
1277
|
w: meta.width,
|
|
733
1278
|
h: meta.height
|
|
734
1279
|
};
|
|
735
1280
|
if (Math.max(meta.width, meta.height) > THUMBNAIL_MAX_SIDE) try {
|
|
736
|
-
const thumbBuffer = await getCore
|
|
1281
|
+
const thumbBuffer = await getCore().media.resizeToJpeg({
|
|
737
1282
|
buffer: params.buffer,
|
|
738
1283
|
maxSide: THUMBNAIL_MAX_SIDE,
|
|
739
1284
|
quality: THUMBNAIL_QUALITY,
|
|
740
1285
|
withoutEnlargement: true
|
|
741
1286
|
});
|
|
742
|
-
const thumbMeta = await getCore
|
|
1287
|
+
const thumbMeta = await getCore().media.getImageMetadata(thumbBuffer).catch(() => null);
|
|
743
1288
|
const result = await uploadMediaWithEncryption(params.client, thumbBuffer, {
|
|
744
1289
|
contentType: "image/jpeg",
|
|
745
1290
|
filename: "thumbnail.jpg",
|
|
@@ -807,18 +1352,13 @@ var direct_room_exports = /* @__PURE__ */ __exportAll({
|
|
|
807
1352
|
isStrictDirectRoom: () => isStrictDirectRoom,
|
|
808
1353
|
readJoinedMatrixMembers: () => readJoinedMatrixMembers
|
|
809
1354
|
});
|
|
810
|
-
function trimMaybeString(value) {
|
|
811
|
-
if (typeof value !== "string") return null;
|
|
812
|
-
const trimmed = value.trim();
|
|
813
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
814
|
-
}
|
|
815
1355
|
function normalizeJoinedMatrixMembers(joinedMembers) {
|
|
816
1356
|
if (!Array.isArray(joinedMembers)) return [];
|
|
817
|
-
return joinedMembers.map((entry) =>
|
|
1357
|
+
return joinedMembers.map((entry) => normalizeNullableString(entry)).filter((entry) => Boolean(entry));
|
|
818
1358
|
}
|
|
819
1359
|
function isStrictDirectMembership(params) {
|
|
820
|
-
const selfUserId =
|
|
821
|
-
const remoteUserId =
|
|
1360
|
+
const selfUserId = normalizeNullableString(params.selfUserId);
|
|
1361
|
+
const remoteUserId = normalizeNullableString(params.remoteUserId);
|
|
822
1362
|
const joinedMembers = params.joinedMembers ?? [];
|
|
823
1363
|
return Boolean(selfUserId && remoteUserId && joinedMembers.length === 2 && joinedMembers.includes(selfUserId) && joinedMembers.includes(remoteUserId));
|
|
824
1364
|
}
|
|
@@ -830,7 +1370,7 @@ async function readJoinedMatrixMembers(client, roomId) {
|
|
|
830
1370
|
}
|
|
831
1371
|
}
|
|
832
1372
|
async function hasDirectMatrixMemberFlag(client, roomId, userId) {
|
|
833
|
-
const normalizedUserId =
|
|
1373
|
+
const normalizedUserId = normalizeNullableString(userId);
|
|
834
1374
|
if (!normalizedUserId) return null;
|
|
835
1375
|
try {
|
|
836
1376
|
const state = await client.getRoomStateEvent(roomId, "m.room.member", normalizedUserId);
|
|
@@ -842,7 +1382,7 @@ async function hasDirectMatrixMemberFlag(client, roomId, userId) {
|
|
|
842
1382
|
}
|
|
843
1383
|
}
|
|
844
1384
|
async function inspectMatrixDirectRoomEvidence(params) {
|
|
845
|
-
const selfUserId = params.selfUserId !== void 0 ?
|
|
1385
|
+
const selfUserId = params.selfUserId !== void 0 ? normalizeNullableString(params.selfUserId) : normalizeNullableString(await params.client.getUserId().catch(() => null));
|
|
846
1386
|
const joinedMembers = await readJoinedMatrixMembers(params.client, params.roomId);
|
|
847
1387
|
const strict = isStrictDirectMembership({
|
|
848
1388
|
selfUserId,
|
|
@@ -1166,8 +1706,6 @@ var send_exports = /* @__PURE__ */ __exportAll({
|
|
|
1166
1706
|
sendSingleTextMessageMatrix: () => sendSingleTextMessageMatrix,
|
|
1167
1707
|
sendTypingMatrix: () => sendTypingMatrix
|
|
1168
1708
|
});
|
|
1169
|
-
const MATRIX_TEXT_LIMIT = 4e3;
|
|
1170
|
-
const getCore = () => getMatrixRuntime();
|
|
1171
1709
|
function createMatrixSendReceipt(params) {
|
|
1172
1710
|
return createMessageReceiptFromOutboundResults({
|
|
1173
1711
|
kind: params.kind,
|
|
@@ -1230,32 +1768,6 @@ async function resolvePreviousEditMentions(params) {
|
|
|
1230
1768
|
body
|
|
1231
1769
|
});
|
|
1232
1770
|
}
|
|
1233
|
-
function prepareMatrixSingleText(text, opts) {
|
|
1234
|
-
const trimmedText = text.trim();
|
|
1235
|
-
const cfg = requireRuntimeConfig(opts.cfg, "Matrix text preparation");
|
|
1236
|
-
const tableMode = opts.tableMode ?? getCore().channel.text.resolveMarkdownTableMode({
|
|
1237
|
-
cfg,
|
|
1238
|
-
channel: "matrix",
|
|
1239
|
-
accountId: opts.accountId
|
|
1240
|
-
});
|
|
1241
|
-
const convertedText = getCore().channel.text.convertMarkdownTables(trimmedText, tableMode);
|
|
1242
|
-
const singleEventLimit = Math.min(getCore().channel.text.resolveTextChunkLimit(cfg, "matrix", opts.accountId), MATRIX_TEXT_LIMIT);
|
|
1243
|
-
return {
|
|
1244
|
-
trimmedText,
|
|
1245
|
-
convertedText,
|
|
1246
|
-
singleEventLimit,
|
|
1247
|
-
fitsInSingleEvent: convertedText.length <= singleEventLimit
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
function chunkMatrixText(text, opts) {
|
|
1251
|
-
const preparedText = prepareMatrixSingleText(text, opts);
|
|
1252
|
-
const cfg = requireRuntimeConfig(opts.cfg, "Matrix text chunking");
|
|
1253
|
-
const chunkMode = getCore().channel.text.resolveChunkMode(cfg, "matrix", opts.accountId);
|
|
1254
|
-
return {
|
|
1255
|
-
...preparedText,
|
|
1256
|
-
chunks: getCore().channel.text.chunkMarkdownTextWithMode(preparedText.convertedText, preparedText.singleEventLimit, chunkMode)
|
|
1257
|
-
};
|
|
1258
|
-
}
|
|
1259
1771
|
async function sendMessageMatrix(to, message, opts) {
|
|
1260
1772
|
const trimmedMessage = message?.trim() ?? "";
|
|
1261
1773
|
if (!trimmedMessage && !opts.mediaUrl) throw new Error("Matrix send requires text or media");
|
|
@@ -1267,7 +1779,7 @@ async function sendMessageMatrix(to, message, opts) {
|
|
|
1267
1779
|
}, async (client) => {
|
|
1268
1780
|
const roomId = await resolveMatrixRoomId(client, to);
|
|
1269
1781
|
const cfg = requireRuntimeConfig(opts.cfg, "Matrix send");
|
|
1270
|
-
const { chunks } = chunkMatrixText(trimmedMessage, {
|
|
1782
|
+
const { chunks, tableMode } = chunkMatrixText(trimmedMessage, {
|
|
1271
1783
|
cfg,
|
|
1272
1784
|
accountId: opts.accountId
|
|
1273
1785
|
});
|
|
@@ -1344,7 +1856,8 @@ async function sendMessageMatrix(to, message, opts) {
|
|
|
1344
1856
|
await enrichMatrixFormattedContent({
|
|
1345
1857
|
client,
|
|
1346
1858
|
content,
|
|
1347
|
-
markdown: captionMarkdown
|
|
1859
|
+
markdown: captionMarkdown,
|
|
1860
|
+
tableMode
|
|
1348
1861
|
});
|
|
1349
1862
|
const eventId = await sendContent(content, receiptKind);
|
|
1350
1863
|
lastMessageId = eventId ?? lastMessageId;
|
|
@@ -1352,26 +1865,28 @@ async function sendMessageMatrix(to, message, opts) {
|
|
|
1352
1865
|
const textChunks = useVoice ? chunks : rest;
|
|
1353
1866
|
const followupRelation = useVoice || threadId ? relation : void 0;
|
|
1354
1867
|
for (const chunk of textChunks) {
|
|
1355
|
-
const text = chunk
|
|
1356
|
-
if (!text) continue;
|
|
1868
|
+
const text = chunk;
|
|
1869
|
+
if (!text.trim()) continue;
|
|
1357
1870
|
const followup = buildTextContent(text, followupRelation);
|
|
1358
1871
|
await enrichMatrixFormattedContent({
|
|
1359
1872
|
client,
|
|
1360
1873
|
content: followup,
|
|
1361
|
-
markdown: text
|
|
1874
|
+
markdown: text,
|
|
1875
|
+
tableMode
|
|
1362
1876
|
});
|
|
1363
1877
|
const followupEventId = await sendContent(followup, "text");
|
|
1364
1878
|
lastMessageId = followupEventId ?? lastMessageId;
|
|
1365
1879
|
if (followupEventId) platformMessageIds.push(followupEventId);
|
|
1366
1880
|
}
|
|
1367
1881
|
} else for (const chunk of chunks.length ? chunks : [""]) {
|
|
1368
|
-
const text = chunk
|
|
1369
|
-
if (!text) continue;
|
|
1882
|
+
const text = chunk;
|
|
1883
|
+
if (!text.trim()) continue;
|
|
1370
1884
|
const content = buildTextContent(text, relation);
|
|
1371
1885
|
await enrichMatrixFormattedContent({
|
|
1372
1886
|
client,
|
|
1373
1887
|
content,
|
|
1374
|
-
markdown: text
|
|
1888
|
+
markdown: text,
|
|
1889
|
+
tableMode
|
|
1375
1890
|
});
|
|
1376
1891
|
const eventId = await sendContent(content, "text");
|
|
1377
1892
|
lastMessageId = eventId ?? lastMessageId;
|
|
@@ -1445,12 +1960,12 @@ async function sendReadReceiptMatrix(roomId, eventId, client) {
|
|
|
1445
1960
|
});
|
|
1446
1961
|
}
|
|
1447
1962
|
async function sendSingleTextMessageMatrix(roomId, text, opts) {
|
|
1448
|
-
const { trimmedText, convertedText, singleEventLimit, fitsInSingleEvent } = prepareMatrixSingleText(text, {
|
|
1963
|
+
const { trimmedText, convertedText, singleEventLimit, eventTextLength, fitsInSingleEvent, tableMode } = prepareMatrixSingleText(text, {
|
|
1449
1964
|
cfg: opts.cfg,
|
|
1450
1965
|
accountId: opts.accountId
|
|
1451
1966
|
});
|
|
1452
1967
|
if (!trimmedText) throw new Error("Matrix single-message send requires text");
|
|
1453
|
-
if (!fitsInSingleEvent) throw new Error(`Matrix single-message text exceeds limit (${
|
|
1968
|
+
if (!fitsInSingleEvent) throw new Error(`Matrix single-message text exceeds limit (${eventTextLength} > ${singleEventLimit})`);
|
|
1454
1969
|
return await withResolvedMatrixSendClient({
|
|
1455
1970
|
client: opts.client,
|
|
1456
1971
|
cfg: opts.cfg,
|
|
@@ -1464,7 +1979,8 @@ async function sendSingleTextMessageMatrix(roomId, text, opts) {
|
|
|
1464
1979
|
client,
|
|
1465
1980
|
content,
|
|
1466
1981
|
markdown: convertedText,
|
|
1467
|
-
includeMentions: opts.includeMentions
|
|
1982
|
+
includeMentions: opts.includeMentions,
|
|
1983
|
+
tableMode
|
|
1468
1984
|
});
|
|
1469
1985
|
if (opts.live) content[MSC4357_LIVE_KEY] = {};
|
|
1470
1986
|
const eventId = await client.sendMessage(resolvedRoom, content);
|
|
@@ -1495,19 +2011,18 @@ async function editMessageMatrix(roomId, originalEventId, newText, opts) {
|
|
|
1495
2011
|
timeoutMs: opts.timeoutMs
|
|
1496
2012
|
}, async (client) => {
|
|
1497
2013
|
const resolvedRoom = await resolveMatrixRoomId(client, roomId);
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
accountId: opts.accountId
|
|
2014
|
+
const { convertedText, tableMode } = prepareMatrixSingleText(newText, {
|
|
2015
|
+
cfg: requireRuntimeConfig(opts.cfg, "Matrix message edit"),
|
|
2016
|
+
accountId: opts.accountId,
|
|
2017
|
+
preserveWhitespace: true
|
|
1503
2018
|
});
|
|
1504
|
-
const convertedText = getCore().channel.text.convertMarkdownTables(newText, tableMode);
|
|
1505
2019
|
const newContent = withMatrixExtraContentFields(buildTextContent(convertedText, void 0, { msgtype: opts.msgtype }), opts.extraContent);
|
|
1506
2020
|
await enrichMatrixFormattedContent({
|
|
1507
2021
|
client,
|
|
1508
2022
|
content: newContent,
|
|
1509
2023
|
markdown: convertedText,
|
|
1510
|
-
includeMentions: opts.includeMentions
|
|
2024
|
+
includeMentions: opts.includeMentions,
|
|
2025
|
+
tableMode
|
|
1511
2026
|
});
|
|
1512
2027
|
const previousEvent = await getPreviousMatrixEvent(client, resolvedRoom, originalEventId);
|
|
1513
2028
|
const replaceMentions = opts.includeMentions === false ? void 0 : diffMatrixMentions(extractMatrixMentions(newContent), await resolvePreviousEditMentions({
|
|
@@ -1524,7 +2039,7 @@ async function editMessageMatrix(roomId, originalEventId, newText, opts) {
|
|
|
1524
2039
|
}
|
|
1525
2040
|
const content = {
|
|
1526
2041
|
...newContent,
|
|
1527
|
-
body: `* ${
|
|
2042
|
+
body: `* ${newContent.body}`,
|
|
1528
2043
|
...typeof newContent.formatted_body === "string" ? { formatted_body: `* ${newContent.formatted_body}` } : {},
|
|
1529
2044
|
"m.new_content": newContent,
|
|
1530
2045
|
"m.relates_to": replaceRelation
|
|
@@ -1551,4 +2066,4 @@ async function reactMatrixMessage(roomId, messageId, emoji, opts) {
|
|
|
1551
2066
|
});
|
|
1552
2067
|
}
|
|
1553
2068
|
//#endregion
|
|
1554
|
-
export { formatPollResultsAsText as C, parsePollStartContent as D, parsePollStart as E, resolvePollReferenceEventId as O, formatPollAsText as S, isPollStartType as T,
|
|
2069
|
+
export { formatPollResultsAsText as C, parsePollStartContent as D, parsePollStart as E, resolvePollReferenceEventId as O, formatPollAsText as S, isPollStartType as T, MsgType as _, sendSingleTextMessageMatrix as a, buildPollResponseContent as b, resolveMatrixRoomId as c, repairMatrixDirectRooms as d, direct_room_exports as f, MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY as g, readJoinedMatrixMembers as h, sendPollMatrix as i, direct_management_exports as l, isStrictDirectMembership as m, reactMatrixMessage as n, sendTypingMatrix as o, hasDirectMatrixMemberFlag as p, sendMessageMatrix as r, send_exports as s, editMessageMatrix as t, promoteMatrixDirectRoomCandidate as u, chunkMatrixText as v, isPollEventType as w, buildPollResultsSummary as x, prepareMatrixSingleText as y };
|