@openclaw/line 2026.7.2-beta.3 → 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/{accounts-BUBOoW5Q.js → accounts-CSH5sk8U.js} +9 -11
- package/dist/api.js +4 -3
- package/dist/{card-command-DQ-epsgt.js → card-command-BEMIm8D8.js} +1 -1
- package/dist/{channel-uT5RTtpi.js → channel-CTaWrzfl.js} +15 -11
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel.runtime-D4Paci2y.js +4 -0
- package/dist/contract-api.js +1 -1
- package/dist/{flex-templates-K1lS9i8L.js → flex-templates-DVy_wog4.js} +318 -107
- package/dist/index.js +1 -1
- package/dist/{markdown-to-line-D1vapcdP.js → markdown-to-line-Dn00k1bq.js} +239 -229
- package/dist/{monitor-Bk-lpoOZ.js → monitor-DzFU5UPV.js} +317 -323
- package/dist/monitor.runtime-B8xjVqev.js +2 -0
- package/dist/outbound.runtime-eHl7NNHu.js +2 -0
- package/dist/{probe-BslD77tJ.js → probe-CM03wo6r.js} +7 -9
- package/dist/probe.runtime-D13ZtXsd.js +2 -0
- package/dist/quick-reply-fallback-D86FwAfr.js +56 -0
- package/dist/{reply-payload-transform-r9sa-TYT.js → reply-payload-transform-BRM2fRvK.js} +3 -164
- package/dist/runtime-api.js +9 -8
- package/dist/send-receipt-CY2ey8XH.js +107 -0
- package/dist/setup-api.js +1 -1
- package/dist/{setup-surface-BEt4mazl.js → setup-surface-BHQOSD8R.js} +107 -67
- 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/openclaw.plugin.json +0 -18
- package/package.json +71 -7
- package/dist/channel.runtime-BqNglqnr.js +0 -4
- package/dist/monitor.runtime-CHlqxGVL.js +0 -2
- package/dist/outbound.runtime-ByZ0Dsvu.js +0 -2
- package/dist/probe.runtime-CRhVGqwl.js +0 -2
- package/npm-shrinkwrap.json +0 -60
|
@@ -1,14 +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-CSH5sk8U.js";
|
|
2
|
+
import { a as validateLineMediaUrl, t as createLineSendReceipt } from "./send-receipt-CY2ey8XH.js";
|
|
3
|
+
import { _ as postbackAction, g as normalizeLineMessageActions, h as normalizeLineAction, m as messageAction, o as createReceiptCard, v as uriAction } from "./flex-templates-DVy_wog4.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";
|
|
10
9
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
11
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
|
|
12
23
|
//#region extensions/line/src/template-messages.ts
|
|
13
24
|
const COMPACT_TEMPLATE_TEXT_LIMIT = 60;
|
|
14
25
|
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
@@ -43,6 +54,19 @@ function formatProductCarouselText(description, price) {
|
|
|
43
54
|
const descriptionText = truncateTemplateText(description, Math.max(0, COMPACT_TEMPLATE_TEXT_LIMIT - priceText.length - 1));
|
|
44
55
|
return descriptionText ? `${descriptionText}\n${priceText}` : priceText;
|
|
45
56
|
}
|
|
57
|
+
function normalizeCarouselColumnActions(column) {
|
|
58
|
+
return {
|
|
59
|
+
...column,
|
|
60
|
+
actions: column.actions.map((action) => normalizeLineAction(action)),
|
|
61
|
+
defaultAction: column.defaultAction === void 0 ? void 0 : normalizeLineAction(column.defaultAction)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function normalizeImageCarouselColumnAction(column) {
|
|
65
|
+
return {
|
|
66
|
+
...column,
|
|
67
|
+
action: normalizeLineAction(column.action, 12)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
46
70
|
/**
|
|
47
71
|
* Create a confirm template (yes/no style dialog)
|
|
48
72
|
*/
|
|
@@ -50,7 +74,7 @@ function createConfirmTemplate(text, confirmAction, cancelAction, altText) {
|
|
|
50
74
|
const template = {
|
|
51
75
|
type: "confirm",
|
|
52
76
|
text: truncateTemplateText(text, 240),
|
|
53
|
-
actions: [confirmAction, cancelAction]
|
|
77
|
+
actions: [normalizeLineAction(confirmAction), normalizeLineAction(cancelAction)]
|
|
54
78
|
};
|
|
55
79
|
return {
|
|
56
80
|
type: "template",
|
|
@@ -72,12 +96,12 @@ function createButtonTemplate(title, text, actions, options) {
|
|
|
72
96
|
type: "buttons",
|
|
73
97
|
...normalizedTitle ? { title: truncateTemplateText(normalizedTitle, 40) } : {},
|
|
74
98
|
text: truncateTemplateText(text, textLimit),
|
|
75
|
-
actions: actions.slice(0, 4),
|
|
99
|
+
actions: actions.slice(0, 4).map((action) => normalizeLineAction(action)),
|
|
76
100
|
thumbnailImageUrl: options?.thumbnailImageUrl,
|
|
77
101
|
imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
|
|
78
102
|
imageSize: options?.imageSize ?? "cover",
|
|
79
103
|
imageBackgroundColor: options?.imageBackgroundColor,
|
|
80
|
-
defaultAction: options?.defaultAction
|
|
104
|
+
defaultAction: options?.defaultAction === void 0 ? void 0 : normalizeLineAction(options.defaultAction)
|
|
81
105
|
};
|
|
82
106
|
return {
|
|
83
107
|
type: "template",
|
|
@@ -91,7 +115,7 @@ function createButtonTemplate(title, text, actions, options) {
|
|
|
91
115
|
function createTemplateCarousel(columns, options) {
|
|
92
116
|
const template = {
|
|
93
117
|
type: "carousel",
|
|
94
|
-
columns: columns.slice(0, 10),
|
|
118
|
+
columns: columns.slice(0, 10).map(normalizeCarouselColumnActions),
|
|
95
119
|
imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
|
|
96
120
|
imageSize: options?.imageSize ?? "cover"
|
|
97
121
|
};
|
|
@@ -112,10 +136,10 @@ function createCarouselColumn(params) {
|
|
|
112
136
|
return {
|
|
113
137
|
title: truncateOptionalTemplateText(params.title, 40),
|
|
114
138
|
text: truncateTemplateText(params.text, textLimit),
|
|
115
|
-
actions: params.actions.slice(0, 3),
|
|
139
|
+
actions: params.actions.slice(0, 3).map((action) => normalizeLineAction(action)),
|
|
116
140
|
thumbnailImageUrl: params.thumbnailImageUrl,
|
|
117
141
|
imageBackgroundColor: params.imageBackgroundColor,
|
|
118
|
-
defaultAction: params.defaultAction
|
|
142
|
+
defaultAction: params.defaultAction === void 0 ? void 0 : normalizeLineAction(params.defaultAction)
|
|
119
143
|
};
|
|
120
144
|
}
|
|
121
145
|
/**
|
|
@@ -124,7 +148,7 @@ function createCarouselColumn(params) {
|
|
|
124
148
|
function createImageCarousel(columns, altText) {
|
|
125
149
|
const template = {
|
|
126
150
|
type: "image_carousel",
|
|
127
|
-
columns: columns.slice(0, 10)
|
|
151
|
+
columns: columns.slice(0, 10).map(normalizeImageCarouselColumnAction)
|
|
128
152
|
};
|
|
129
153
|
return {
|
|
130
154
|
type: "template",
|
|
@@ -138,7 +162,7 @@ function createImageCarousel(columns, altText) {
|
|
|
138
162
|
function createImageCarouselColumn(imageUrl, action) {
|
|
139
163
|
return {
|
|
140
164
|
imageUrl,
|
|
141
|
-
action
|
|
165
|
+
action: normalizeLineAction(action, 12)
|
|
142
166
|
};
|
|
143
167
|
}
|
|
144
168
|
/**
|
|
@@ -320,9 +344,10 @@ function resolveLineReceiptKind(messages) {
|
|
|
320
344
|
async function pushLineMessages(to, messages, opts, behavior = {}) {
|
|
321
345
|
if (messages.length === 0) throw new Error("Message must be non-empty for LINE sends");
|
|
322
346
|
const { account, client, chatId } = createLinePushContext(to, opts);
|
|
347
|
+
const normalizedMessages = messages.map(normalizeLineMessageActions);
|
|
323
348
|
const pushRequest = client.pushMessage({
|
|
324
349
|
to: chatId,
|
|
325
|
-
messages
|
|
350
|
+
messages: normalizedMessages
|
|
326
351
|
});
|
|
327
352
|
if (behavior.errorContext) await pushRequest.catch((err) => {
|
|
328
353
|
logLineHttpError(err, behavior.errorContext);
|
|
@@ -344,9 +369,10 @@ async function pushLineMessages(to, messages, opts, behavior = {}) {
|
|
|
344
369
|
}
|
|
345
370
|
async function replyLineMessages(replyToken, messages, opts, behavior = {}) {
|
|
346
371
|
const { account, client } = createLineMessagingClient(opts);
|
|
372
|
+
const normalizedMessages = messages.map(normalizeLineMessageActions);
|
|
347
373
|
await client.replyMessage({
|
|
348
374
|
replyToken,
|
|
349
|
-
messages
|
|
375
|
+
messages: normalizedMessages
|
|
350
376
|
});
|
|
351
377
|
recordLineOutboundActivity(account.accountId);
|
|
352
378
|
if (opts.verbose) logVerbose(behavior.verboseMessage?.(messages.length) ?? `line: replied with ${messages.length} messages`);
|
|
@@ -493,88 +519,184 @@ async function getUserDisplayName(userId, opts) {
|
|
|
493
519
|
}
|
|
494
520
|
//#endregion
|
|
495
521
|
//#region extensions/line/src/markdown-to-line.ts
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
522
|
+
const LINE_MARKDOWN_OPTIONS = {
|
|
523
|
+
assistantTranscriptRoleHeaders: true,
|
|
524
|
+
autolink: false,
|
|
525
|
+
blockquotePrefix: "",
|
|
526
|
+
headingStyle: "none",
|
|
527
|
+
horizontalRuleText: "",
|
|
528
|
+
linkify: false,
|
|
529
|
+
preserveSourceBlockSpacing: true
|
|
530
|
+
};
|
|
531
|
+
const TRANSCRIPT_ROLE_PREFIX = "[assistant-authored transcript] ";
|
|
532
|
+
function parseLineMarkdown(text, tableMode = "block") {
|
|
533
|
+
return markdownToIRWithMeta(text, {
|
|
534
|
+
...LINE_MARKDOWN_OPTIONS,
|
|
535
|
+
tableMode
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function toMarkdownTable(table) {
|
|
539
|
+
return {
|
|
540
|
+
headers: table.headers,
|
|
541
|
+
rows: table.rows,
|
|
542
|
+
headerCells: table.headerCells,
|
|
543
|
+
rowCells: table.rowCells
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function codeBlockSpans(ir) {
|
|
547
|
+
return ir.styles.filter((span) => span.style === "code_block");
|
|
548
|
+
}
|
|
549
|
+
function toCodeBlock(ir, span) {
|
|
550
|
+
return {
|
|
551
|
+
...span.language ? { language: span.language } : {},
|
|
552
|
+
code: ir.text.slice(span.start, span.end).trim()
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function rangesOverlap(left, right) {
|
|
556
|
+
return left.start < right.end && right.start < left.end;
|
|
557
|
+
}
|
|
558
|
+
function projectPlainText(ir, omitted = []) {
|
|
559
|
+
const insertions = [];
|
|
560
|
+
for (const link of ir.links) {
|
|
561
|
+
if (omitted.some((range) => rangesOverlap(range, link))) continue;
|
|
562
|
+
const href = link.href.trim();
|
|
563
|
+
const label = ir.text.slice(link.start, link.end).trim();
|
|
564
|
+
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
565
|
+
if (href && label && label !== href && label !== comparableHref) insertions.push({
|
|
566
|
+
position: link.end,
|
|
567
|
+
text: ` (${href})`
|
|
523
568
|
});
|
|
524
569
|
}
|
|
525
|
-
for (const
|
|
526
|
-
|
|
527
|
-
|
|
570
|
+
for (const annotation of ir.annotations ?? []) if (annotation.type === "assistant_transcript_role" && !omitted.some((range) => rangesOverlap(range, annotation))) insertions.push({
|
|
571
|
+
position: annotation.start,
|
|
572
|
+
text: TRANSCRIPT_ROLE_PREFIX
|
|
573
|
+
});
|
|
574
|
+
const inlineCodeSpans = ir.styles.filter((span) => span.style === "code" && !omitted.some((range) => rangesOverlap(range, span)));
|
|
575
|
+
for (const span of inlineCodeSpans) if (stripMarkdown(ir.text.slice(span.start, span.end), { assistantTranscriptRoleHeaders: true }).startsWith(TRANSCRIPT_ROLE_PREFIX)) insertions.push({
|
|
576
|
+
position: span.start,
|
|
577
|
+
text: TRANSCRIPT_ROLE_PREFIX
|
|
578
|
+
});
|
|
579
|
+
insertions.sort((left, right) => left.position - right.position);
|
|
580
|
+
const underlineTags = [...ir.text.matchAll(/<\/?u>/gi)].map((match) => ({
|
|
581
|
+
start: match.index,
|
|
582
|
+
end: match.index + match[0].length
|
|
583
|
+
})).filter((tag) => !inlineCodeSpans.some((span) => rangesOverlap(tag, span)) && !omitted.some((span) => rangesOverlap(tag, span)));
|
|
584
|
+
const removed = [...omitted, ...underlineTags].toSorted((left, right) => left.start - right.start);
|
|
585
|
+
let output = "";
|
|
586
|
+
let cursor = 0;
|
|
587
|
+
let insertionIndex = 0;
|
|
588
|
+
const appendRange = (end) => {
|
|
589
|
+
while (insertionIndex < insertions.length) {
|
|
590
|
+
const insertion = insertions[insertionIndex];
|
|
591
|
+
if (!insertion || insertion.position > end) break;
|
|
592
|
+
if (insertion.position >= cursor) {
|
|
593
|
+
output += ir.text.slice(cursor, insertion.position) + insertion.text;
|
|
594
|
+
cursor = insertion.position;
|
|
595
|
+
}
|
|
596
|
+
insertionIndex += 1;
|
|
597
|
+
}
|
|
598
|
+
output += ir.text.slice(cursor, end);
|
|
599
|
+
cursor = end;
|
|
600
|
+
};
|
|
601
|
+
for (const range of removed) {
|
|
602
|
+
appendRange(range.start);
|
|
603
|
+
cursor = Math.max(cursor, range.end);
|
|
604
|
+
while (insertionIndex < insertions.length && (insertions[insertionIndex]?.position ?? cursor) < cursor) insertionIndex += 1;
|
|
605
|
+
}
|
|
606
|
+
appendRange(ir.text.length);
|
|
607
|
+
return output.trim();
|
|
608
|
+
}
|
|
609
|
+
function sameSpanStyle(left, right) {
|
|
610
|
+
return left.weight === right.weight && left.style === right.style && left.decoration === right.decoration;
|
|
611
|
+
}
|
|
612
|
+
function renderTableCell(cell, fallback) {
|
|
613
|
+
if (!cell?.text.trim()) return {
|
|
614
|
+
text: fallback,
|
|
615
|
+
hasMarkup: false
|
|
616
|
+
};
|
|
617
|
+
const codeSpans = cell.styles.filter((span) => span.style === "code");
|
|
618
|
+
const tags = [...cell.text.matchAll(/<\/?u>/gi)].map((match) => ({
|
|
619
|
+
start: match.index,
|
|
620
|
+
end: match.index + match[0].length,
|
|
621
|
+
closing: match[0][1] === "/"
|
|
622
|
+
})).filter((tag) => !codeSpans.some((span) => rangesOverlap(tag, span)));
|
|
623
|
+
const boundaries = /* @__PURE__ */ new Set([0, cell.text.length]);
|
|
624
|
+
for (const style of cell.styles) {
|
|
625
|
+
boundaries.add(style.start);
|
|
626
|
+
boundaries.add(style.end);
|
|
627
|
+
}
|
|
628
|
+
for (const link of cell.links) boundaries.add(link.end);
|
|
629
|
+
for (const tag of tags) {
|
|
630
|
+
boundaries.add(tag.start);
|
|
631
|
+
boundaries.add(tag.end);
|
|
632
|
+
}
|
|
633
|
+
const sortedBoundaries = [...boundaries].toSorted((left, right) => left - right);
|
|
634
|
+
const spans = [];
|
|
635
|
+
let underlineDepth = 0;
|
|
636
|
+
let hasMarkup = false;
|
|
637
|
+
const appendSpan = (span) => {
|
|
638
|
+
const previous = spans.at(-1);
|
|
639
|
+
if (previous && sameSpanStyle(previous, span)) previous.text = `${previous.text ?? ""}${span.text ?? ""}`;
|
|
640
|
+
else spans.push(span);
|
|
641
|
+
};
|
|
642
|
+
for (let index = 0; index < sortedBoundaries.length - 1; index += 1) {
|
|
643
|
+
const start = sortedBoundaries[index];
|
|
644
|
+
const end = sortedBoundaries[index + 1];
|
|
645
|
+
if (start === void 0 || end === void 0) continue;
|
|
646
|
+
const tag = tags.find((candidate) => candidate.start === start);
|
|
647
|
+
if (tag) {
|
|
648
|
+
underlineDepth += tag.closing ? -1 : 1;
|
|
649
|
+
hasMarkup = true;
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
const text = cell.text.slice(start, end);
|
|
653
|
+
if (text) {
|
|
654
|
+
const active = new Set(cell.styles.filter((style) => style.start <= start && style.end >= end).map((style) => style.style));
|
|
655
|
+
const weight = active.has("bold") ? "bold" : void 0;
|
|
656
|
+
const style = active.has("italic") ? "italic" : void 0;
|
|
657
|
+
const decoration = active.has("strikethrough") ? "line-through" : underlineDepth > 0 ? "underline" : void 0;
|
|
658
|
+
hasMarkup ||= weight !== void 0 || style !== void 0 || decoration !== void 0;
|
|
659
|
+
appendSpan({
|
|
660
|
+
type: "span",
|
|
661
|
+
text,
|
|
662
|
+
weight,
|
|
663
|
+
style,
|
|
664
|
+
decoration
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
for (const link of cell.links.filter((candidate) => candidate.end === end)) {
|
|
668
|
+
const href = link.href.trim();
|
|
669
|
+
const label = cell.text.slice(link.start, link.end).trim();
|
|
670
|
+
if (href && label && label !== href) {
|
|
671
|
+
appendSpan({
|
|
672
|
+
type: "span",
|
|
673
|
+
text: ` (${href})`
|
|
674
|
+
});
|
|
675
|
+
hasMarkup = true;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
528
678
|
}
|
|
529
679
|
return {
|
|
530
|
-
|
|
531
|
-
|
|
680
|
+
text: spans.map((span) => span.text ?? "").join("").trim() || fallback,
|
|
681
|
+
...hasMarkup ? { contents: spans } : {},
|
|
682
|
+
hasMarkup
|
|
532
683
|
};
|
|
533
684
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
*/
|
|
537
|
-
function parseTableRow(row) {
|
|
538
|
-
return row.split("|").map((cell) => cell.trim()).filter((cell, index, arr) => {
|
|
539
|
-
if (index === 0 && cell === "") return false;
|
|
540
|
-
if (index === arr.length - 1 && cell === "") return false;
|
|
541
|
-
return true;
|
|
542
|
-
});
|
|
685
|
+
function plainTableCell(text) {
|
|
686
|
+
return parseLineMarkdown(text, "off").ir;
|
|
543
687
|
}
|
|
544
|
-
/**
|
|
545
|
-
* Convert a markdown table to a LINE Flex Message bubble
|
|
546
|
-
*/
|
|
688
|
+
/** Convert a markdown table to a LINE Flex Message bubble. */
|
|
547
689
|
function convertTableToFlexBubble(table) {
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
if (!raw) return {
|
|
551
|
-
text: "-",
|
|
552
|
-
bold: false,
|
|
553
|
-
hasMarkup: false
|
|
554
|
-
};
|
|
555
|
-
let hasMarkup = false;
|
|
556
|
-
return {
|
|
557
|
-
text: raw.replace(/\*\*(.+?)\*\*/g, (_, inner) => {
|
|
558
|
-
hasMarkup = true;
|
|
559
|
-
return String(inner);
|
|
560
|
-
}).trim() || "-",
|
|
561
|
-
bold: /^\*\*.+\*\*$/.test(raw),
|
|
562
|
-
hasMarkup
|
|
563
|
-
};
|
|
564
|
-
};
|
|
565
|
-
const headerCells = table.headers.map((header) => parseCell(header));
|
|
566
|
-
const rowCells = table.rows.map((row) => row.map((cell) => parseCell(cell)));
|
|
690
|
+
const headerCells = (table.headerCells ?? table.headers.map(plainTableCell)).map((cell) => renderTableCell(cell, "-"));
|
|
691
|
+
const rowCells = (table.rowCells ?? table.rows.map((row) => row.map(plainTableCell))).map((row) => row.map((cell) => renderTableCell(cell, "-")));
|
|
567
692
|
const hasInlineMarkup = headerCells.some((cell) => cell.hasMarkup) || rowCells.some((row) => row.some((cell) => cell.hasMarkup));
|
|
568
|
-
if (table.headers.length === 2 && !hasInlineMarkup) {
|
|
569
|
-
|
|
693
|
+
if (table.headers.length === 2 && !hasInlineMarkup) return createReceiptCard({
|
|
694
|
+
title: headerCells.map((cell) => cell.text).join(" / "),
|
|
695
|
+
items: rowCells.map((row) => ({
|
|
570
696
|
name: row[0]?.text ?? "-",
|
|
571
697
|
value: row[1]?.text ?? "-"
|
|
572
|
-
}))
|
|
573
|
-
|
|
574
|
-
title: headerCells.map((cell) => cell.text).join(" / "),
|
|
575
|
-
items
|
|
576
|
-
});
|
|
577
|
-
}
|
|
698
|
+
}))
|
|
699
|
+
});
|
|
578
700
|
return {
|
|
579
701
|
type: "bubble",
|
|
580
702
|
body: {
|
|
@@ -587,6 +709,7 @@ function convertTableToFlexBubble(table) {
|
|
|
587
709
|
contents: headerCells.map((cell) => ({
|
|
588
710
|
type: "text",
|
|
589
711
|
text: cell.text,
|
|
712
|
+
contents: cell.contents,
|
|
590
713
|
weight: "bold",
|
|
591
714
|
size: "sm",
|
|
592
715
|
color: "#333333",
|
|
@@ -599,67 +722,32 @@ function convertTableToFlexBubble(table) {
|
|
|
599
722
|
type: "separator",
|
|
600
723
|
margin: "sm"
|
|
601
724
|
},
|
|
602
|
-
...rowCells.slice(0, 10).map((row, rowIndex) => {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
margin: rowIndex === 0 ? "md" : "sm"
|
|
623
|
-
};
|
|
624
|
-
})
|
|
725
|
+
...rowCells.slice(0, 10).map((row, rowIndex) => ({
|
|
726
|
+
type: "box",
|
|
727
|
+
layout: "horizontal",
|
|
728
|
+
contents: table.headers.map((_, colIndex) => {
|
|
729
|
+
const cell = row[colIndex] ?? {
|
|
730
|
+
text: "-",
|
|
731
|
+
hasMarkup: false
|
|
732
|
+
};
|
|
733
|
+
return {
|
|
734
|
+
type: "text",
|
|
735
|
+
text: cell.text,
|
|
736
|
+
contents: cell.contents,
|
|
737
|
+
size: "sm",
|
|
738
|
+
color: "#666666",
|
|
739
|
+
flex: 1,
|
|
740
|
+
wrap: true
|
|
741
|
+
};
|
|
742
|
+
}),
|
|
743
|
+
margin: rowIndex === 0 ? "md" : "sm"
|
|
744
|
+
}))
|
|
625
745
|
],
|
|
626
746
|
paddingAll: "lg"
|
|
627
747
|
}
|
|
628
748
|
};
|
|
629
749
|
}
|
|
630
|
-
/**
|
|
631
|
-
* Detect and extract code blocks from text
|
|
632
|
-
*/
|
|
633
|
-
function extractCodeBlocks(text) {
|
|
634
|
-
const codeBlocks = [];
|
|
635
|
-
let textWithoutCode = text;
|
|
636
|
-
MARKDOWN_CODE_BLOCK_REGEX.lastIndex = 0;
|
|
637
|
-
let match;
|
|
638
|
-
const matches = [];
|
|
639
|
-
while ((match = MARKDOWN_CODE_BLOCK_REGEX.exec(text)) !== null) {
|
|
640
|
-
const fullMatch = expectDefined(match[0], "Markdown code block match");
|
|
641
|
-
const language = match[1] || void 0;
|
|
642
|
-
const code = expectDefined(match[2], "Markdown code body capture");
|
|
643
|
-
matches.push({
|
|
644
|
-
fullMatch,
|
|
645
|
-
block: {
|
|
646
|
-
language,
|
|
647
|
-
code: code.trim()
|
|
648
|
-
}
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
for (const { fullMatch, block } of matches.toReversed()) {
|
|
652
|
-
codeBlocks.unshift(block);
|
|
653
|
-
textWithoutCode = textWithoutCode.replace(fullMatch, "");
|
|
654
|
-
}
|
|
655
|
-
return {
|
|
656
|
-
codeBlocks,
|
|
657
|
-
textWithoutCode
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* Convert a code block to a LINE Flex Message bubble
|
|
662
|
-
*/
|
|
750
|
+
/** Convert a code block to a LINE Flex Message bubble. */
|
|
663
751
|
function convertCodeBlockToFlexBubble(block) {
|
|
664
752
|
const titleText = block.language ? `Code (${block.language})` : "Code";
|
|
665
753
|
const displayCode = block.code.length > 2e3 ? truncateUtf16Safe(block.code, 2e3) + "\n..." : block.code;
|
|
@@ -693,97 +781,19 @@ function convertCodeBlockToFlexBubble(block) {
|
|
|
693
781
|
}
|
|
694
782
|
};
|
|
695
783
|
}
|
|
696
|
-
/**
|
|
697
|
-
* Extract markdown links from text
|
|
698
|
-
*/
|
|
699
|
-
function extractLinks(text) {
|
|
700
|
-
const links = [];
|
|
701
|
-
MARKDOWN_LINK_REGEX.lastIndex = 0;
|
|
702
|
-
let match;
|
|
703
|
-
while ((match = MARKDOWN_LINK_REGEX.exec(text)) !== null) links.push({
|
|
704
|
-
text: expectDefined(match[1], "Markdown link text capture"),
|
|
705
|
-
url: expectDefined(match[2], "Markdown link URL capture")
|
|
706
|
-
});
|
|
707
|
-
return {
|
|
708
|
-
links,
|
|
709
|
-
textWithLinks: text.replace(MARKDOWN_LINK_REGEX, "$1")
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
/**
|
|
713
|
-
* Create a Flex Message with tappable link buttons
|
|
714
|
-
*/
|
|
715
|
-
function convertLinksToFlexBubble(links) {
|
|
716
|
-
return {
|
|
717
|
-
type: "bubble",
|
|
718
|
-
body: {
|
|
719
|
-
type: "box",
|
|
720
|
-
layout: "vertical",
|
|
721
|
-
contents: [{
|
|
722
|
-
type: "text",
|
|
723
|
-
text: "Links",
|
|
724
|
-
weight: "bold",
|
|
725
|
-
size: "md",
|
|
726
|
-
color: "#333333"
|
|
727
|
-
}],
|
|
728
|
-
paddingAll: "lg",
|
|
729
|
-
paddingBottom: "sm"
|
|
730
|
-
},
|
|
731
|
-
footer: {
|
|
732
|
-
type: "box",
|
|
733
|
-
layout: "vertical",
|
|
734
|
-
contents: links.slice(0, 4).map((link, index) => ({
|
|
735
|
-
type: "button",
|
|
736
|
-
action: uriAction(link.text, link.url),
|
|
737
|
-
style: index === 0 ? "primary" : "secondary",
|
|
738
|
-
margin: index > 0 ? "sm" : void 0
|
|
739
|
-
})),
|
|
740
|
-
paddingAll: "md"
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
/**
|
|
745
|
-
* Main function: Process text for LINE output
|
|
746
|
-
* - Extracts tables → Flex Messages
|
|
747
|
-
* - Extracts code blocks → Flex Messages
|
|
748
|
-
* - Strips remaining markdown
|
|
749
|
-
* - Returns processed text + Flex Messages
|
|
750
|
-
*/
|
|
784
|
+
/** Parse once, route existing block surfaces to Flex, and project the remainder as plain text. */
|
|
751
785
|
function processLineMessage(text) {
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
const { tables, textWithoutTables } = extractMarkdownTables(processedText);
|
|
755
|
-
processedText = textWithoutTables;
|
|
756
|
-
for (const table of tables) {
|
|
757
|
-
const bubble = convertTableToFlexBubble(table);
|
|
758
|
-
flexMessages.push(toFlexMessage("Table", bubble));
|
|
759
|
-
}
|
|
760
|
-
const { codeBlocks, textWithoutCode } = extractCodeBlocks(processedText);
|
|
761
|
-
processedText = textWithoutCode;
|
|
762
|
-
for (const block of codeBlocks) {
|
|
763
|
-
const bubble = convertCodeBlockToFlexBubble(block);
|
|
764
|
-
flexMessages.push(toFlexMessage("Code", bubble));
|
|
765
|
-
}
|
|
766
|
-
const { textWithLinks } = extractLinks(processedText);
|
|
767
|
-
processedText = textWithLinks;
|
|
768
|
-
processedText = stripMarkdown(processedText, { assistantTranscriptRoleHeaders: true });
|
|
786
|
+
const { ir, tables } = parseLineMarkdown(text);
|
|
787
|
+
const codeSpans = codeBlockSpans(ir);
|
|
769
788
|
return {
|
|
770
|
-
text:
|
|
771
|
-
flexMessages
|
|
789
|
+
text: projectPlainText(ir, codeSpans),
|
|
790
|
+
flexMessages: [...tables.map((table) => toFlexMessage("Table", convertTableToFlexBubble(toMarkdownTable(table)))), ...codeSpans.map((span) => toFlexMessage("Code", convertCodeBlockToFlexBubble(toCodeBlock(ir, span))))]
|
|
772
791
|
};
|
|
773
792
|
}
|
|
774
|
-
/**
|
|
775
|
-
* Check if text contains markdown that needs conversion
|
|
776
|
-
*/
|
|
793
|
+
/** Check if text contains markdown that needs conversion. */
|
|
777
794
|
function hasMarkdownToConvert(text) {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
MARKDOWN_CODE_BLOCK_REGEX.lastIndex = 0;
|
|
781
|
-
if (MARKDOWN_CODE_BLOCK_REGEX.test(text)) return true;
|
|
782
|
-
if (/\*\*[^*]+\*\*/.test(text)) return true;
|
|
783
|
-
if (/~~[^~]+~~/.test(text)) return true;
|
|
784
|
-
if (/^#{1,6}\s+/m.test(text)) return true;
|
|
785
|
-
if (/^>\s+/m.test(text)) return true;
|
|
786
|
-
return false;
|
|
795
|
+
const { ir, tables } = parseLineMarkdown(text);
|
|
796
|
+
return tables.length > 0 || ir.styles.length > 0 || ir.links.length > 0 || /<\/?u>/i.test(ir.text) || ir.text !== text.trimEnd();
|
|
787
797
|
}
|
|
788
798
|
//#endregion
|
|
789
|
-
export {
|
|
799
|
+
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 };
|