@openclaw/line 2026.7.2-beta.2 → 2026.7.2-beta.4
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/dist/{accounts-DJVOv1JI.js → accounts-BUBOoW5Q.js} +95 -33
- package/dist/api.js +4 -3
- package/dist/basic-cards-Rb-Ow7LN.js +307 -0
- package/dist/{card-command-DQ-epsgt.js → card-command-Ch0TwcDW.js} +2 -1
- package/dist/{channel-BHR-GoJ0.js → channel-CNcv74n2.js} +22 -10
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel.runtime-BBCZvRa_.js +4 -0
- package/dist/contract-api.js +1 -1
- package/dist/{flex-templates-K1lS9i8L.js → flex-templates-KiKaVYgi.js} +1 -318
- package/dist/index.js +1 -1
- package/dist/{markdown-to-line-XceqeKRP.js → markdown-to-line-DWIdzBfy.js} +224 -220
- package/dist/{monitor-Db2rZsSX.js → monitor-BinAXvIY.js} +454 -288
- package/dist/monitor.runtime-DKj4FHkA.js +2 -0
- package/dist/outbound.runtime-DRyoVa81.js +2 -0
- package/dist/quick-reply-fallback-D86FwAfr.js +56 -0
- package/dist/{reply-payload-transform-r9sa-TYT.js → reply-payload-transform-d57WYHFm.js} +3 -164
- package/dist/runtime-api.js +10 -24
- package/dist/send-receipt-CY2ey8XH.js +107 -0
- package/dist/setup-api.js +1 -1
- package/dist/{setup-surface-B7W6pwn3.js → setup-surface-Bili5gWy.js} +64 -5
- package/node_modules/@line/bot-sdk/dist/cjs/manage-audience/model/audienceGroupCreateRoute.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/manage-audience/model/audienceGroupFailedType.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/manage-audience/model/audienceGroupJobFailedType.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/manage-audience/model/audienceGroupJobStatus.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/manage-audience/model/audienceGroupStatus.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/flexBoxBorderWidth.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/flexBoxCornerRadius.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/flexBubble.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/flexIconSize.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/flexSpanSize.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/flexTextFontSize.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/numberOfMessagesResponse.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/postbackAction.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/messaging-api/model/subscriptionPeriodDemographic.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/version.d.ts +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/version.js +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/event.d.ts +2 -1
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/event.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/messageEditedEvent.d.ts +24 -0
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/messageEditedEvent.d.ts.map +1 -0
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/messageEditedEvent.js +14 -0
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/messageEditedEvent.js.map +1 -0
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/models.d.ts +1 -0
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/models.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/models.js +1 -0
- package/node_modules/@line/bot-sdk/dist/cjs/webhook/model/models.js.map +1 -1
- package/node_modules/@line/bot-sdk/dist/manage-audience/model/audienceGroupCreateRoute.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/manage-audience/model/audienceGroupFailedType.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/manage-audience/model/audienceGroupJobFailedType.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/manage-audience/model/audienceGroupJobStatus.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/manage-audience/model/audienceGroupStatus.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/flexBoxBorderWidth.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/flexBoxCornerRadius.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/flexBubble.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/flexIconSize.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/flexSpanSize.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/flexTextFontSize.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/numberOfMessagesResponse.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/postbackAction.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/messaging-api/model/subscriptionPeriodDemographic.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/version.d.ts +1 -1
- package/node_modules/@line/bot-sdk/dist/version.js +1 -1
- package/node_modules/@line/bot-sdk/dist/webhook/model/event.d.ts +2 -1
- package/node_modules/@line/bot-sdk/dist/webhook/model/event.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/webhook/model/messageEditedEvent.d.ts +24 -0
- package/node_modules/@line/bot-sdk/dist/webhook/model/messageEditedEvent.d.ts.map +1 -0
- package/node_modules/@line/bot-sdk/dist/webhook/model/messageEditedEvent.js +13 -0
- package/node_modules/@line/bot-sdk/dist/webhook/model/messageEditedEvent.js.map +1 -0
- package/node_modules/@line/bot-sdk/dist/webhook/model/models.d.ts +1 -0
- package/node_modules/@line/bot-sdk/dist/webhook/model/models.d.ts.map +1 -1
- package/node_modules/@line/bot-sdk/dist/webhook/model/models.js +1 -0
- package/node_modules/@line/bot-sdk/dist/webhook/model/models.js.map +1 -1
- package/node_modules/@line/bot-sdk/lib/insight/model/getNumberOfFollowersResponse.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/liff/model/liffScope.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/manage-audience/model/audienceGroupCreateRoute.ts +1 -4
- package/node_modules/@line/bot-sdk/lib/manage-audience/model/audienceGroupFailedType.ts +1 -2
- package/node_modules/@line/bot-sdk/lib/manage-audience/model/audienceGroupJobFailedType.ts +1 -2
- package/node_modules/@line/bot-sdk/lib/manage-audience/model/audienceGroupJobStatus.ts +1 -4
- package/node_modules/@line/bot-sdk/lib/manage-audience/model/audienceGroupStatus.ts +1 -6
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/botInfoResponse.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/flexBoxBorderWidth.ts +1 -6
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/flexBoxCornerRadius.ts +1 -7
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/flexBubble.ts +1 -7
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/flexIconSize.ts +1 -10
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/flexSpanSize.ts +1 -10
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/flexTextFontSize.ts +1 -10
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/getAggregationUnitNameListResponse.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/getFollowersResponse.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/getJoinedMembershipUsersResponse.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/issueLinkTokenResponse.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/numberOfMessagesResponse.ts +2 -5
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/postbackAction.ts +1 -4
- package/node_modules/@line/bot-sdk/lib/messaging-api/model/subscriptionPeriodDemographic.ts +1 -5
- package/node_modules/@line/bot-sdk/lib/version.ts +1 -1
- package/node_modules/@line/bot-sdk/lib/webhook/.openapi-generator/FILES +1 -0
- package/node_modules/@line/bot-sdk/lib/webhook/model/event.ts +2 -0
- package/node_modules/@line/bot-sdk/lib/webhook/model/messageEditedEvent.ts +32 -0
- package/node_modules/@line/bot-sdk/lib/webhook/model/models.ts +1 -0
- package/node_modules/@line/bot-sdk/lib/webhook/model/stickerMessageContent.ts +1 -1
- package/node_modules/@line/bot-sdk/package.json +3 -3
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/fs/promises.d.ts +16 -5
- package/node_modules/@types/node/package.json +3 -3
- package/npm-shrinkwrap.json +10 -10
- package/openclaw.plugin.json +0 -18
- package/package.json +71 -6
- package/dist/channel.runtime-DFgZ_Xwn.js +0 -4
- package/dist/monitor.runtime-CZuQgsEE.js +0 -2
- package/dist/outbound.runtime-DnpU0Cms.js +0 -2
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import { i as resolveLineAccount } from "./accounts-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { stripMarkdown, stripMarkdown as stripMarkdown$1 } from "openclaw/plugin-sdk/text-chunking";
|
|
1
|
+
import { i as resolveLineAccount } from "./accounts-BUBOoW5Q.js";
|
|
2
|
+
import { a as validateLineMediaUrl, t as createLineSendReceipt } from "./send-receipt-CY2ey8XH.js";
|
|
3
|
+
import { a as messageAction, o as postbackAction, s as uriAction, u as createReceiptCard } from "./flex-templates-KiKaVYgi.js";
|
|
4
|
+
import { markdownToIRWithMeta, stripMarkdown, stripMarkdown as stripMarkdown$1 } from "openclaw/plugin-sdk/text-chunking";
|
|
5
5
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
6
|
-
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
7
6
|
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
8
7
|
import { messagingApi } from "@line/bot-sdk";
|
|
9
8
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
9
|
+
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
10
10
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
11
|
+
//#region extensions/line/src/flex-templates/message.ts
|
|
12
|
+
/**
|
|
13
|
+
* Wrap a FlexContainer in a FlexMessage
|
|
14
|
+
*/
|
|
15
|
+
function toFlexMessage(altText, contents) {
|
|
16
|
+
return {
|
|
17
|
+
type: "flex",
|
|
18
|
+
altText,
|
|
19
|
+
contents
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
11
23
|
//#region extensions/line/src/template-messages.ts
|
|
12
24
|
const COMPACT_TEMPLATE_TEXT_LIMIT = 60;
|
|
13
25
|
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
@@ -221,6 +233,14 @@ function resolveLineChannelAccessToken(explicit, params) {
|
|
|
221
233
|
//#region extensions/line/src/send.ts
|
|
222
234
|
const userProfileCache = /* @__PURE__ */ new Map();
|
|
223
235
|
const PROFILE_CACHE_TTL_MS = 300 * 1e3;
|
|
236
|
+
const PROFILE_CACHE_MAX_ENTRIES = 1e3;
|
|
237
|
+
function cacheUserProfile(userId, profile) {
|
|
238
|
+
userProfileCache.delete(userId);
|
|
239
|
+
userProfileCache.set(userId, profile);
|
|
240
|
+
if (userProfileCache.size <= PROFILE_CACHE_MAX_ENTRIES) return;
|
|
241
|
+
for (const [key, cached] of userProfileCache) if (profile.fetchedAt - cached.fetchedAt >= PROFILE_CACHE_TTL_MS) userProfileCache.delete(key);
|
|
242
|
+
pruneMapToMaxSize(userProfileCache, PROFILE_CACHE_MAX_ENTRIES);
|
|
243
|
+
}
|
|
224
244
|
function normalizeTarget(to) {
|
|
225
245
|
const trimmed = to.trim();
|
|
226
246
|
if (!trimmed) throw new Error("Recipient is required for LINE sends");
|
|
@@ -469,7 +489,7 @@ async function getUserProfile(userId, opts) {
|
|
|
469
489
|
displayName: profile.displayName,
|
|
470
490
|
pictureUrl: profile.pictureUrl
|
|
471
491
|
};
|
|
472
|
-
|
|
492
|
+
cacheUserProfile(userId, {
|
|
473
493
|
...result,
|
|
474
494
|
fetchedAt: Date.now()
|
|
475
495
|
});
|
|
@@ -484,88 +504,184 @@ async function getUserDisplayName(userId, opts) {
|
|
|
484
504
|
}
|
|
485
505
|
//#endregion
|
|
486
506
|
//#region extensions/line/src/markdown-to-line.ts
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
507
|
+
const LINE_MARKDOWN_OPTIONS = {
|
|
508
|
+
assistantTranscriptRoleHeaders: true,
|
|
509
|
+
autolink: false,
|
|
510
|
+
blockquotePrefix: "",
|
|
511
|
+
headingStyle: "none",
|
|
512
|
+
horizontalRuleText: "",
|
|
513
|
+
linkify: false,
|
|
514
|
+
preserveSourceBlockSpacing: true
|
|
515
|
+
};
|
|
516
|
+
const TRANSCRIPT_ROLE_PREFIX = "[assistant-authored transcript] ";
|
|
517
|
+
function parseLineMarkdown(text, tableMode = "block") {
|
|
518
|
+
return markdownToIRWithMeta(text, {
|
|
519
|
+
...LINE_MARKDOWN_OPTIONS,
|
|
520
|
+
tableMode
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
function toMarkdownTable(table) {
|
|
524
|
+
return {
|
|
525
|
+
headers: table.headers,
|
|
526
|
+
rows: table.rows,
|
|
527
|
+
headerCells: table.headerCells,
|
|
528
|
+
rowCells: table.rowCells
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function codeBlockSpans(ir) {
|
|
532
|
+
return ir.styles.filter((span) => span.style === "code_block");
|
|
533
|
+
}
|
|
534
|
+
function toCodeBlock(ir, span) {
|
|
535
|
+
return {
|
|
536
|
+
...span.language ? { language: span.language } : {},
|
|
537
|
+
code: ir.text.slice(span.start, span.end).trim()
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function rangesOverlap(left, right) {
|
|
541
|
+
return left.start < right.end && right.start < left.end;
|
|
542
|
+
}
|
|
543
|
+
function projectPlainText(ir, omitted = []) {
|
|
544
|
+
const insertions = [];
|
|
545
|
+
for (const link of ir.links) {
|
|
546
|
+
if (omitted.some((range) => rangesOverlap(range, link))) continue;
|
|
547
|
+
const href = link.href.trim();
|
|
548
|
+
const label = ir.text.slice(link.start, link.end).trim();
|
|
549
|
+
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
550
|
+
if (href && label && label !== href && label !== comparableHref) insertions.push({
|
|
551
|
+
position: link.end,
|
|
552
|
+
text: ` (${href})`
|
|
514
553
|
});
|
|
515
554
|
}
|
|
516
|
-
for (const
|
|
517
|
-
|
|
518
|
-
|
|
555
|
+
for (const annotation of ir.annotations ?? []) if (annotation.type === "assistant_transcript_role" && !omitted.some((range) => rangesOverlap(range, annotation))) insertions.push({
|
|
556
|
+
position: annotation.start,
|
|
557
|
+
text: TRANSCRIPT_ROLE_PREFIX
|
|
558
|
+
});
|
|
559
|
+
const inlineCodeSpans = ir.styles.filter((span) => span.style === "code" && !omitted.some((range) => rangesOverlap(range, span)));
|
|
560
|
+
for (const span of inlineCodeSpans) if (stripMarkdown(ir.text.slice(span.start, span.end), { assistantTranscriptRoleHeaders: true }).startsWith(TRANSCRIPT_ROLE_PREFIX)) insertions.push({
|
|
561
|
+
position: span.start,
|
|
562
|
+
text: TRANSCRIPT_ROLE_PREFIX
|
|
563
|
+
});
|
|
564
|
+
insertions.sort((left, right) => left.position - right.position);
|
|
565
|
+
const underlineTags = [...ir.text.matchAll(/<\/?u>/gi)].map((match) => ({
|
|
566
|
+
start: match.index,
|
|
567
|
+
end: match.index + match[0].length
|
|
568
|
+
})).filter((tag) => !inlineCodeSpans.some((span) => rangesOverlap(tag, span)) && !omitted.some((span) => rangesOverlap(tag, span)));
|
|
569
|
+
const removed = [...omitted, ...underlineTags].toSorted((left, right) => left.start - right.start);
|
|
570
|
+
let output = "";
|
|
571
|
+
let cursor = 0;
|
|
572
|
+
let insertionIndex = 0;
|
|
573
|
+
const appendRange = (end) => {
|
|
574
|
+
while (insertionIndex < insertions.length) {
|
|
575
|
+
const insertion = insertions[insertionIndex];
|
|
576
|
+
if (!insertion || insertion.position > end) break;
|
|
577
|
+
if (insertion.position >= cursor) {
|
|
578
|
+
output += ir.text.slice(cursor, insertion.position) + insertion.text;
|
|
579
|
+
cursor = insertion.position;
|
|
580
|
+
}
|
|
581
|
+
insertionIndex += 1;
|
|
582
|
+
}
|
|
583
|
+
output += ir.text.slice(cursor, end);
|
|
584
|
+
cursor = end;
|
|
585
|
+
};
|
|
586
|
+
for (const range of removed) {
|
|
587
|
+
appendRange(range.start);
|
|
588
|
+
cursor = Math.max(cursor, range.end);
|
|
589
|
+
while (insertionIndex < insertions.length && (insertions[insertionIndex]?.position ?? cursor) < cursor) insertionIndex += 1;
|
|
590
|
+
}
|
|
591
|
+
appendRange(ir.text.length);
|
|
592
|
+
return output.trim();
|
|
593
|
+
}
|
|
594
|
+
function sameSpanStyle(left, right) {
|
|
595
|
+
return left.weight === right.weight && left.style === right.style && left.decoration === right.decoration;
|
|
596
|
+
}
|
|
597
|
+
function renderTableCell(cell, fallback) {
|
|
598
|
+
if (!cell?.text.trim()) return {
|
|
599
|
+
text: fallback,
|
|
600
|
+
hasMarkup: false
|
|
601
|
+
};
|
|
602
|
+
const codeSpans = cell.styles.filter((span) => span.style === "code");
|
|
603
|
+
const tags = [...cell.text.matchAll(/<\/?u>/gi)].map((match) => ({
|
|
604
|
+
start: match.index,
|
|
605
|
+
end: match.index + match[0].length,
|
|
606
|
+
closing: match[0][1] === "/"
|
|
607
|
+
})).filter((tag) => !codeSpans.some((span) => rangesOverlap(tag, span)));
|
|
608
|
+
const boundaries = /* @__PURE__ */ new Set([0, cell.text.length]);
|
|
609
|
+
for (const style of cell.styles) {
|
|
610
|
+
boundaries.add(style.start);
|
|
611
|
+
boundaries.add(style.end);
|
|
612
|
+
}
|
|
613
|
+
for (const link of cell.links) boundaries.add(link.end);
|
|
614
|
+
for (const tag of tags) {
|
|
615
|
+
boundaries.add(tag.start);
|
|
616
|
+
boundaries.add(tag.end);
|
|
617
|
+
}
|
|
618
|
+
const sortedBoundaries = [...boundaries].toSorted((left, right) => left - right);
|
|
619
|
+
const spans = [];
|
|
620
|
+
let underlineDepth = 0;
|
|
621
|
+
let hasMarkup = false;
|
|
622
|
+
const appendSpan = (span) => {
|
|
623
|
+
const previous = spans.at(-1);
|
|
624
|
+
if (previous && sameSpanStyle(previous, span)) previous.text = `${previous.text ?? ""}${span.text ?? ""}`;
|
|
625
|
+
else spans.push(span);
|
|
626
|
+
};
|
|
627
|
+
for (let index = 0; index < sortedBoundaries.length - 1; index += 1) {
|
|
628
|
+
const start = sortedBoundaries[index];
|
|
629
|
+
const end = sortedBoundaries[index + 1];
|
|
630
|
+
if (start === void 0 || end === void 0) continue;
|
|
631
|
+
const tag = tags.find((candidate) => candidate.start === start);
|
|
632
|
+
if (tag) {
|
|
633
|
+
underlineDepth += tag.closing ? -1 : 1;
|
|
634
|
+
hasMarkup = true;
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const text = cell.text.slice(start, end);
|
|
638
|
+
if (text) {
|
|
639
|
+
const active = new Set(cell.styles.filter((style) => style.start <= start && style.end >= end).map((style) => style.style));
|
|
640
|
+
const weight = active.has("bold") ? "bold" : void 0;
|
|
641
|
+
const style = active.has("italic") ? "italic" : void 0;
|
|
642
|
+
const decoration = active.has("strikethrough") ? "line-through" : underlineDepth > 0 ? "underline" : void 0;
|
|
643
|
+
hasMarkup ||= weight !== void 0 || style !== void 0 || decoration !== void 0;
|
|
644
|
+
appendSpan({
|
|
645
|
+
type: "span",
|
|
646
|
+
text,
|
|
647
|
+
weight,
|
|
648
|
+
style,
|
|
649
|
+
decoration
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
for (const link of cell.links.filter((candidate) => candidate.end === end)) {
|
|
653
|
+
const href = link.href.trim();
|
|
654
|
+
const label = cell.text.slice(link.start, link.end).trim();
|
|
655
|
+
if (href && label && label !== href) {
|
|
656
|
+
appendSpan({
|
|
657
|
+
type: "span",
|
|
658
|
+
text: ` (${href})`
|
|
659
|
+
});
|
|
660
|
+
hasMarkup = true;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
519
663
|
}
|
|
520
664
|
return {
|
|
521
|
-
|
|
522
|
-
|
|
665
|
+
text: spans.map((span) => span.text ?? "").join("").trim() || fallback,
|
|
666
|
+
...hasMarkup ? { contents: spans } : {},
|
|
667
|
+
hasMarkup
|
|
523
668
|
};
|
|
524
669
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
*/
|
|
528
|
-
function parseTableRow(row) {
|
|
529
|
-
return row.split("|").map((cell) => cell.trim()).filter((cell, index, arr) => {
|
|
530
|
-
if (index === 0 && cell === "") return false;
|
|
531
|
-
if (index === arr.length - 1 && cell === "") return false;
|
|
532
|
-
return true;
|
|
533
|
-
});
|
|
670
|
+
function plainTableCell(text) {
|
|
671
|
+
return parseLineMarkdown(text, "off").ir;
|
|
534
672
|
}
|
|
535
|
-
/**
|
|
536
|
-
* Convert a markdown table to a LINE Flex Message bubble
|
|
537
|
-
*/
|
|
673
|
+
/** Convert a markdown table to a LINE Flex Message bubble. */
|
|
538
674
|
function convertTableToFlexBubble(table) {
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
if (!raw) return {
|
|
542
|
-
text: "-",
|
|
543
|
-
bold: false,
|
|
544
|
-
hasMarkup: false
|
|
545
|
-
};
|
|
546
|
-
let hasMarkup = false;
|
|
547
|
-
return {
|
|
548
|
-
text: raw.replace(/\*\*(.+?)\*\*/g, (_, inner) => {
|
|
549
|
-
hasMarkup = true;
|
|
550
|
-
return String(inner);
|
|
551
|
-
}).trim() || "-",
|
|
552
|
-
bold: /^\*\*.+\*\*$/.test(raw),
|
|
553
|
-
hasMarkup
|
|
554
|
-
};
|
|
555
|
-
};
|
|
556
|
-
const headerCells = table.headers.map((header) => parseCell(header));
|
|
557
|
-
const rowCells = table.rows.map((row) => row.map((cell) => parseCell(cell)));
|
|
675
|
+
const headerCells = (table.headerCells ?? table.headers.map(plainTableCell)).map((cell) => renderTableCell(cell, "-"));
|
|
676
|
+
const rowCells = (table.rowCells ?? table.rows.map((row) => row.map(plainTableCell))).map((row) => row.map((cell) => renderTableCell(cell, "-")));
|
|
558
677
|
const hasInlineMarkup = headerCells.some((cell) => cell.hasMarkup) || rowCells.some((row) => row.some((cell) => cell.hasMarkup));
|
|
559
|
-
if (table.headers.length === 2 && !hasInlineMarkup) {
|
|
560
|
-
|
|
678
|
+
if (table.headers.length === 2 && !hasInlineMarkup) return createReceiptCard({
|
|
679
|
+
title: headerCells.map((cell) => cell.text).join(" / "),
|
|
680
|
+
items: rowCells.map((row) => ({
|
|
561
681
|
name: row[0]?.text ?? "-",
|
|
562
682
|
value: row[1]?.text ?? "-"
|
|
563
|
-
}))
|
|
564
|
-
|
|
565
|
-
title: headerCells.map((cell) => cell.text).join(" / "),
|
|
566
|
-
items
|
|
567
|
-
});
|
|
568
|
-
}
|
|
683
|
+
}))
|
|
684
|
+
});
|
|
569
685
|
return {
|
|
570
686
|
type: "bubble",
|
|
571
687
|
body: {
|
|
@@ -578,6 +694,7 @@ function convertTableToFlexBubble(table) {
|
|
|
578
694
|
contents: headerCells.map((cell) => ({
|
|
579
695
|
type: "text",
|
|
580
696
|
text: cell.text,
|
|
697
|
+
contents: cell.contents,
|
|
581
698
|
weight: "bold",
|
|
582
699
|
size: "sm",
|
|
583
700
|
color: "#333333",
|
|
@@ -590,67 +707,32 @@ function convertTableToFlexBubble(table) {
|
|
|
590
707
|
type: "separator",
|
|
591
708
|
margin: "sm"
|
|
592
709
|
},
|
|
593
|
-
...rowCells.slice(0, 10).map((row, rowIndex) => {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
margin: rowIndex === 0 ? "md" : "sm"
|
|
614
|
-
};
|
|
615
|
-
})
|
|
710
|
+
...rowCells.slice(0, 10).map((row, rowIndex) => ({
|
|
711
|
+
type: "box",
|
|
712
|
+
layout: "horizontal",
|
|
713
|
+
contents: table.headers.map((_, colIndex) => {
|
|
714
|
+
const cell = row[colIndex] ?? {
|
|
715
|
+
text: "-",
|
|
716
|
+
hasMarkup: false
|
|
717
|
+
};
|
|
718
|
+
return {
|
|
719
|
+
type: "text",
|
|
720
|
+
text: cell.text,
|
|
721
|
+
contents: cell.contents,
|
|
722
|
+
size: "sm",
|
|
723
|
+
color: "#666666",
|
|
724
|
+
flex: 1,
|
|
725
|
+
wrap: true
|
|
726
|
+
};
|
|
727
|
+
}),
|
|
728
|
+
margin: rowIndex === 0 ? "md" : "sm"
|
|
729
|
+
}))
|
|
616
730
|
],
|
|
617
731
|
paddingAll: "lg"
|
|
618
732
|
}
|
|
619
733
|
};
|
|
620
734
|
}
|
|
621
|
-
/**
|
|
622
|
-
* Detect and extract code blocks from text
|
|
623
|
-
*/
|
|
624
|
-
function extractCodeBlocks(text) {
|
|
625
|
-
const codeBlocks = [];
|
|
626
|
-
let textWithoutCode = text;
|
|
627
|
-
MARKDOWN_CODE_BLOCK_REGEX.lastIndex = 0;
|
|
628
|
-
let match;
|
|
629
|
-
const matches = [];
|
|
630
|
-
while ((match = MARKDOWN_CODE_BLOCK_REGEX.exec(text)) !== null) {
|
|
631
|
-
const fullMatch = expectDefined(match[0], "Markdown code block match");
|
|
632
|
-
const language = match[1] || void 0;
|
|
633
|
-
const code = expectDefined(match[2], "Markdown code body capture");
|
|
634
|
-
matches.push({
|
|
635
|
-
fullMatch,
|
|
636
|
-
block: {
|
|
637
|
-
language,
|
|
638
|
-
code: code.trim()
|
|
639
|
-
}
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
for (const { fullMatch, block } of matches.toReversed()) {
|
|
643
|
-
codeBlocks.unshift(block);
|
|
644
|
-
textWithoutCode = textWithoutCode.replace(fullMatch, "");
|
|
645
|
-
}
|
|
646
|
-
return {
|
|
647
|
-
codeBlocks,
|
|
648
|
-
textWithoutCode
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Convert a code block to a LINE Flex Message bubble
|
|
653
|
-
*/
|
|
735
|
+
/** Convert a code block to a LINE Flex Message bubble. */
|
|
654
736
|
function convertCodeBlockToFlexBubble(block) {
|
|
655
737
|
const titleText = block.language ? `Code (${block.language})` : "Code";
|
|
656
738
|
const displayCode = block.code.length > 2e3 ? truncateUtf16Safe(block.code, 2e3) + "\n..." : block.code;
|
|
@@ -684,97 +766,19 @@ function convertCodeBlockToFlexBubble(block) {
|
|
|
684
766
|
}
|
|
685
767
|
};
|
|
686
768
|
}
|
|
687
|
-
/**
|
|
688
|
-
* Extract markdown links from text
|
|
689
|
-
*/
|
|
690
|
-
function extractLinks(text) {
|
|
691
|
-
const links = [];
|
|
692
|
-
MARKDOWN_LINK_REGEX.lastIndex = 0;
|
|
693
|
-
let match;
|
|
694
|
-
while ((match = MARKDOWN_LINK_REGEX.exec(text)) !== null) links.push({
|
|
695
|
-
text: expectDefined(match[1], "Markdown link text capture"),
|
|
696
|
-
url: expectDefined(match[2], "Markdown link URL capture")
|
|
697
|
-
});
|
|
698
|
-
return {
|
|
699
|
-
links,
|
|
700
|
-
textWithLinks: text.replace(MARKDOWN_LINK_REGEX, "$1")
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
/**
|
|
704
|
-
* Create a Flex Message with tappable link buttons
|
|
705
|
-
*/
|
|
706
|
-
function convertLinksToFlexBubble(links) {
|
|
707
|
-
return {
|
|
708
|
-
type: "bubble",
|
|
709
|
-
body: {
|
|
710
|
-
type: "box",
|
|
711
|
-
layout: "vertical",
|
|
712
|
-
contents: [{
|
|
713
|
-
type: "text",
|
|
714
|
-
text: "Links",
|
|
715
|
-
weight: "bold",
|
|
716
|
-
size: "md",
|
|
717
|
-
color: "#333333"
|
|
718
|
-
}],
|
|
719
|
-
paddingAll: "lg",
|
|
720
|
-
paddingBottom: "sm"
|
|
721
|
-
},
|
|
722
|
-
footer: {
|
|
723
|
-
type: "box",
|
|
724
|
-
layout: "vertical",
|
|
725
|
-
contents: links.slice(0, 4).map((link, index) => ({
|
|
726
|
-
type: "button",
|
|
727
|
-
action: uriAction(link.text, link.url),
|
|
728
|
-
style: index === 0 ? "primary" : "secondary",
|
|
729
|
-
margin: index > 0 ? "sm" : void 0
|
|
730
|
-
})),
|
|
731
|
-
paddingAll: "md"
|
|
732
|
-
}
|
|
733
|
-
};
|
|
734
|
-
}
|
|
735
|
-
/**
|
|
736
|
-
* Main function: Process text for LINE output
|
|
737
|
-
* - Extracts tables → Flex Messages
|
|
738
|
-
* - Extracts code blocks → Flex Messages
|
|
739
|
-
* - Strips remaining markdown
|
|
740
|
-
* - Returns processed text + Flex Messages
|
|
741
|
-
*/
|
|
769
|
+
/** Parse once, route existing block surfaces to Flex, and project the remainder as plain text. */
|
|
742
770
|
function processLineMessage(text) {
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
const { tables, textWithoutTables } = extractMarkdownTables(processedText);
|
|
746
|
-
processedText = textWithoutTables;
|
|
747
|
-
for (const table of tables) {
|
|
748
|
-
const bubble = convertTableToFlexBubble(table);
|
|
749
|
-
flexMessages.push(toFlexMessage("Table", bubble));
|
|
750
|
-
}
|
|
751
|
-
const { codeBlocks, textWithoutCode } = extractCodeBlocks(processedText);
|
|
752
|
-
processedText = textWithoutCode;
|
|
753
|
-
for (const block of codeBlocks) {
|
|
754
|
-
const bubble = convertCodeBlockToFlexBubble(block);
|
|
755
|
-
flexMessages.push(toFlexMessage("Code", bubble));
|
|
756
|
-
}
|
|
757
|
-
const { textWithLinks } = extractLinks(processedText);
|
|
758
|
-
processedText = textWithLinks;
|
|
759
|
-
processedText = stripMarkdown(processedText, { assistantTranscriptRoleHeaders: true });
|
|
771
|
+
const { ir, tables } = parseLineMarkdown(text);
|
|
772
|
+
const codeSpans = codeBlockSpans(ir);
|
|
760
773
|
return {
|
|
761
|
-
text:
|
|
762
|
-
flexMessages
|
|
774
|
+
text: projectPlainText(ir, codeSpans),
|
|
775
|
+
flexMessages: [...tables.map((table) => toFlexMessage("Table", convertTableToFlexBubble(toMarkdownTable(table)))), ...codeSpans.map((span) => toFlexMessage("Code", convertCodeBlockToFlexBubble(toCodeBlock(ir, span))))]
|
|
763
776
|
};
|
|
764
777
|
}
|
|
765
|
-
/**
|
|
766
|
-
* Check if text contains markdown that needs conversion
|
|
767
|
-
*/
|
|
778
|
+
/** Check if text contains markdown that needs conversion. */
|
|
768
779
|
function hasMarkdownToConvert(text) {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
MARKDOWN_CODE_BLOCK_REGEX.lastIndex = 0;
|
|
772
|
-
if (MARKDOWN_CODE_BLOCK_REGEX.test(text)) return true;
|
|
773
|
-
if (/\*\*[^*]+\*\*/.test(text)) return true;
|
|
774
|
-
if (/~~[^~]+~~/.test(text)) return true;
|
|
775
|
-
if (/^#{1,6}\s+/m.test(text)) return true;
|
|
776
|
-
if (/^>\s+/m.test(text)) return true;
|
|
777
|
-
return false;
|
|
780
|
+
const { ir, tables } = parseLineMarkdown(text);
|
|
781
|
+
return tables.length > 0 || ir.styles.length > 0 || ir.links.length > 0 || /<\/?u>/i.test(ir.text) || ir.text !== text.trimEnd();
|
|
778
782
|
}
|
|
779
783
|
//#endregion
|
|
780
|
-
export {
|
|
784
|
+
export { createConfirmTemplate as A, sendMessageLine as C, createButtonMenu as D, buildTemplateMessageFromPayload as E, createTemplateCarousel as F, createYesNoConfirm as I, toFlexMessage as L, createImageCarouselColumn as M, createLinkMenu as N, createButtonTemplate as O, createProductCarousel as P, replyMessageLine as S, resolveLineChannelAccessToken as T, pushLocationMessage as _, stripMarkdown$1 as a, pushTemplateMessage as b, createImageMessage as c, createTextMessageWithQuickReplies as d, createVideoMessage as f, pushImageMessage as g, pushFlexMessage as h, processLineMessage as i, createImageCarousel as j, createCarouselColumn as k, createLocationMessage as l, getUserProfile as m, convertTableToFlexBubble as n, createAudioMessage as o, getUserDisplayName as p, hasMarkdownToConvert as r, createFlexMessage as s, convertCodeBlockToFlexBubble as t, createQuickReplyItems as u, pushMessageLine as v, showLoadingAnimation as w, pushTextMessageWithQuickReplies as x, pushMessagesLine as y };
|