@openclaw/line 2026.5.12 → 2026.5.14-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +1 -1
- package/dist/{basic-cards-7DTG6E-A.js → basic-cards-BISytiSa.js} +1 -1
- package/dist/{card-command-Dtj3Rx7T.js → card-command-B1iy-vnt.js} +2 -2
- package/dist/{channel-qjV9OG1s.js → channel-DjhMvw_m.js} +6 -8
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel.runtime-BlrtY7Wb.js +4 -0
- package/dist/index.js +1 -1
- package/dist/{markdown-to-line-CrXM4Bcw.js → markdown-to-line-Bh4K93vo.js} +2 -2
- package/dist/{monitor-CnqIZXPx.js → monitor--x8R-hee.js} +7 -39
- package/dist/monitor.runtime-ECp2P8T0.js +2 -0
- package/dist/{outbound.runtime-BQf7o-dT.js → outbound.runtime-CzgAHvIt.js} +1 -1
- package/dist/probe.runtime-tp_IgA31.js +2 -0
- package/dist/{reply-payload-transform-C3Dx5kxs.js → reply-payload-transform-D2yrTDIV.js} +127 -2
- package/dist/runtime-api.js +6 -7
- package/package.json +4 -4
- package/dist/channel.runtime-DZEOuAhp.js +0 -4
- package/dist/monitor.runtime-Cfi3VjQz.js +0 -2
- package/dist/probe.runtime-XkNsM6LR.js +0 -2
- package/dist/quick-reply-fallback-HskUUWsn.js +0 -55
- package/dist/send-receipt-zpAfxQ58.js +0 -73
- /package/dist/{probe-Cla0gZ0b.js → probe-CiPafR4R.js} +0 -0
- /package/dist/{schedule-cards-BwQChTdM.js → schedule-cards-D-yZMHDE.js} +0 -0
package/dist/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-
|
|
1
|
+
import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-DjhMvw_m.js";
|
|
2
2
|
import { n as lineSetupAdapter, t as lineSetupWizard } from "./setup-surface-BGjkWr_B.js";
|
|
3
3
|
//#region extensions/line/src/channel.setup.ts
|
|
4
4
|
const lineSetupPlugin = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as createReceiptCard } from "./schedule-cards-
|
|
2
|
-
import { a as createListCard, i as createInfoCard, r as createImageCard, t as createActionCard } from "./basic-cards-
|
|
1
|
+
import { r as createReceiptCard } from "./schedule-cards-D-yZMHDE.js";
|
|
2
|
+
import { a as createListCard, i as createInfoCard, r as createImageCard, t as createActionCard } from "./basic-cards-BISytiSa.js";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
//#region extensions/line/src/card-command.ts
|
|
5
5
|
const CARD_USAGE = `Usage: /card <type> "title" "body" [options]
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-UXAvdBo_.js";
|
|
2
2
|
import { n as lineSetupAdapter, r as hasLineCredentials, t as lineSetupWizard } from "./setup-surface-BGjkWr_B.js";
|
|
3
|
-
import {
|
|
4
|
-
import { n as parseLineDirectives, o as LineChannelConfigSchema, t as hasLineDirectives } from "./reply-payload-transform-C3Dx5kxs.js";
|
|
5
|
-
import { n as resolveLineOutboundMedia, t as createLineSendReceipt } from "./send-receipt-zpAfxQ58.js";
|
|
3
|
+
import { c as resolveLineOutboundMedia, f as LineChannelConfigSchema, m as resolveExactLineGroupConfigKey, n as parseLineDirectives, o as createLineSendReceipt, s as buildLineQuickReplyFallbackText, t as hasLineDirectives, u as getLineRuntime } from "./reply-payload-transform-D2yrTDIV.js";
|
|
6
4
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
7
5
|
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
8
6
|
import { createRestrictSendersChannelSecurity, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
@@ -107,8 +105,8 @@ const lineChannelPluginCommon = {
|
|
|
107
105
|
};
|
|
108
106
|
//#endregion
|
|
109
107
|
//#region extensions/line/src/gateway.ts
|
|
110
|
-
const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-
|
|
111
|
-
const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-
|
|
108
|
+
const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-tp_IgA31.js"));
|
|
109
|
+
const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-ECp2P8T0.js"));
|
|
112
110
|
const lineGatewayAdapter = {
|
|
113
111
|
startAccount: async (ctx) => {
|
|
114
112
|
const account = ctx.account;
|
|
@@ -212,7 +210,7 @@ function resolveLineGroupRequireMention(params) {
|
|
|
212
210
|
}
|
|
213
211
|
//#endregion
|
|
214
212
|
//#region extensions/line/src/outbound.ts
|
|
215
|
-
const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-
|
|
213
|
+
const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-CzgAHvIt.js"));
|
|
216
214
|
function isLineUserTarget(target) {
|
|
217
215
|
const normalized = target.trim().replace(/^line:(group|room|user):/i, "").replace(/^line:/i, "");
|
|
218
216
|
return /^U/i.test(normalized);
|
|
@@ -508,7 +506,7 @@ const lineMessageAdapter = defineChannelMessageAdapter({
|
|
|
508
506
|
});
|
|
509
507
|
//#endregion
|
|
510
508
|
//#region extensions/line/src/status.ts
|
|
511
|
-
const loadLineProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-
|
|
509
|
+
const loadLineProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-tp_IgA31.js"));
|
|
512
510
|
const collectLineStatusIssues = createDependentCredentialStatusIssueCollector({
|
|
513
511
|
channel: "line",
|
|
514
512
|
dependencySourceKey: "tokenSource",
|
|
@@ -533,7 +531,7 @@ const lineStatusAdapter = createComputedAccountStatusAdapter({
|
|
|
533
531
|
});
|
|
534
532
|
//#endregion
|
|
535
533
|
//#region extensions/line/src/channel.ts
|
|
536
|
-
const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
534
|
+
const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-BlrtY7Wb.js"));
|
|
537
535
|
const lineSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
538
536
|
channelKey: "line",
|
|
539
537
|
resolveDmPolicy: (account) => account.config.dmPolicy,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as linePlugin } from "./channel-
|
|
1
|
+
import { t as linePlugin } from "./channel-DjhMvw_m.js";
|
|
2
2
|
export { linePlugin };
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ let lineCardCommandPromise = null;
|
|
|
4
4
|
async function loadLineCardCommand(api) {
|
|
5
5
|
lineCardCommandPromise ??= (async () => {
|
|
6
6
|
let registered = null;
|
|
7
|
-
const { registerLineCardCommand } = await import("./card-command-
|
|
7
|
+
const { registerLineCardCommand } = await import("./card-command-B1iy-vnt.js");
|
|
8
8
|
registerLineCardCommand({
|
|
9
9
|
...api,
|
|
10
10
|
registerCommand(command) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as resolveLineAccount } from "./accounts-UXAvdBo_.js";
|
|
2
|
-
import {
|
|
3
|
-
import { r as createReceiptCard } from "./schedule-cards-
|
|
2
|
+
import { l as validateLineMediaUrl, o as createLineSendReceipt } from "./reply-payload-transform-D2yrTDIV.js";
|
|
3
|
+
import { r as createReceiptCard } from "./schedule-cards-D-yZMHDE.js";
|
|
4
4
|
import { messagingApi } from "@line/bot-sdk";
|
|
5
5
|
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
6
6
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { i as resolveLineAccount, r as resolveDefaultLineAccountId } from "./accounts-UXAvdBo_.js";
|
|
2
|
-
import {
|
|
3
|
-
import { A as buildTemplateMessageFromPayload, C as pushMessagesLine, E as replyMessageLine, O as showLoadingAnimation, S as pushMessageLine, T as pushTextMessageWithQuickReplies, _ as getUserDisplayName, c as processLineMessage, d as createFlexMessage, f as createImageMessage, h as createTextMessageWithQuickReplies, m as createQuickReplyItems, p as createLocationMessage } from "./markdown-to-line-
|
|
2
|
+
import { h as resolveLineGroupConfigEntry, s as buildLineQuickReplyFallbackText, u as getLineRuntime } from "./reply-payload-transform-D2yrTDIV.js";
|
|
3
|
+
import { A as buildTemplateMessageFromPayload, C as pushMessagesLine, E as replyMessageLine, O as showLoadingAnimation, S as pushMessageLine, T as pushTextMessageWithQuickReplies, _ as getUserDisplayName, c as processLineMessage, d as createFlexMessage, f as createImageMessage, h as createTextMessageWithQuickReplies, m as createQuickReplyItems, p as createLocationMessage } from "./markdown-to-line-Bh4K93vo.js";
|
|
4
4
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
5
5
|
import { createMessageReceiveContext, hasFinalChannelTurnDispatch } from "openclaw/plugin-sdk/channel-message";
|
|
6
6
|
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
7
|
-
import {
|
|
7
|
+
import { normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
8
|
import { firstDefined } from "openclaw/plugin-sdk/allow-from";
|
|
9
9
|
import { messagingApi } from "@line/bot-sdk";
|
|
10
|
-
import {
|
|
10
|
+
import { saveMediaStream } from "openclaw/plugin-sdk/media-store";
|
|
11
11
|
import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env";
|
|
12
12
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
13
13
|
import { chunkMarkdownText } from "openclaw/plugin-sdk/reply-runtime";
|
|
@@ -41,47 +41,15 @@ const normalizeAllowFrom = (list) => {
|
|
|
41
41
|
};
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region extensions/line/src/download.ts
|
|
44
|
-
const AUDIO_BRANDS = new Set([
|
|
45
|
-
"m4a ",
|
|
46
|
-
"m4b ",
|
|
47
|
-
"m4p ",
|
|
48
|
-
"m4r ",
|
|
49
|
-
"f4a ",
|
|
50
|
-
"f4b "
|
|
51
|
-
]);
|
|
52
44
|
async function downloadLineMedia(messageId, channelAccessToken, maxBytes = 10 * 1024 * 1024) {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
let totalSize = 0;
|
|
56
|
-
for await (const chunk of response) {
|
|
57
|
-
totalSize += chunk.length;
|
|
58
|
-
if (totalSize > maxBytes) throw new Error(`Media exceeds ${Math.round(maxBytes / (1024 * 1024))}MB limit`);
|
|
59
|
-
chunks.push(chunk);
|
|
60
|
-
}
|
|
61
|
-
const buffer = Buffer.concat(chunks);
|
|
62
|
-
const saved = await saveMediaBuffer(buffer, detectContentType(buffer), "inbound", maxBytes);
|
|
63
|
-
logVerbose(`line: persisted media ${messageId} to ${saved.path} (${buffer.length} bytes)`);
|
|
45
|
+
const saved = await saveMediaStream(await new messagingApi.MessagingApiBlobClient({ channelAccessToken }).getMessageContent(messageId), void 0, "inbound", maxBytes);
|
|
46
|
+
logVerbose(`line: persisted media ${messageId} to ${saved.path} (${saved.size} bytes)`);
|
|
64
47
|
return {
|
|
65
48
|
path: saved.path,
|
|
66
49
|
contentType: saved.contentType,
|
|
67
|
-
size:
|
|
50
|
+
size: saved.size
|
|
68
51
|
};
|
|
69
52
|
}
|
|
70
|
-
function detectContentType(buffer) {
|
|
71
|
-
const hasFtypBox = buffer.length >= 12 && buffer[4] === 102 && buffer[5] === 116 && buffer[6] === 121 && buffer[7] === 112;
|
|
72
|
-
if (buffer.length >= 2) {
|
|
73
|
-
if (buffer[0] === 255 && buffer[1] === 216) return "image/jpeg";
|
|
74
|
-
if (buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71) return "image/png";
|
|
75
|
-
if (buffer[0] === 71 && buffer[1] === 73 && buffer[2] === 70) return "image/gif";
|
|
76
|
-
if (buffer[0] === 82 && buffer[1] === 73 && buffer[2] === 70 && buffer[3] === 70 && buffer[8] === 87 && buffer[9] === 69 && buffer[10] === 66 && buffer[11] === 80) return "image/webp";
|
|
77
|
-
if (hasFtypBox) {
|
|
78
|
-
const majorBrand = lowercasePreservingWhitespace(buffer.toString("ascii", 8, 12));
|
|
79
|
-
if (AUDIO_BRANDS.has(majorBrand)) return "audio/mp4";
|
|
80
|
-
return "video/mp4";
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return "application/octet-stream";
|
|
84
|
-
}
|
|
85
53
|
//#endregion
|
|
86
54
|
//#region extensions/line/src/auto-reply-delivery.ts
|
|
87
55
|
async function deliverLineAutoReply(params) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as buildTemplateMessageFromPayload, C as pushMessagesLine, D as sendMessageLine, S as pushMessageLine, T as pushTextMessageWithQuickReplies, c as processLineMessage, m as createQuickReplyItems, w as pushTemplateMessage, x as pushLocationMessage, y as pushFlexMessage } from "./markdown-to-line-
|
|
1
|
+
import { A as buildTemplateMessageFromPayload, C as pushMessagesLine, D as sendMessageLine, S as pushMessageLine, T as pushTextMessageWithQuickReplies, c as processLineMessage, m as createQuickReplyItems, w as pushTemplateMessage, x as pushLocationMessage, y as pushFlexMessage } from "./markdown-to-line-Bh4K93vo.js";
|
|
2
2
|
export { buildTemplateMessageFromPayload, createQuickReplyItems, processLineMessage, pushFlexMessage, pushLocationMessage, pushMessageLine, pushMessagesLine, pushTemplateMessage, pushTextMessageWithQuickReplies, sendMessageLine };
|
|
@@ -1,8 +1,51 @@
|
|
|
1
|
-
import { n as createEventCard, t as createAgendaCard } from "./schedule-cards-
|
|
1
|
+
import { n as createEventCard, t as createAgendaCard } from "./schedule-cards-D-yZMHDE.js";
|
|
2
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
3
|
+
import { resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
|
|
2
4
|
import { buildChannelConfigSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
|
|
3
5
|
import { requireChannelOpenAllowFrom } from "openclaw/plugin-sdk/extension-shared";
|
|
4
6
|
import { z } from "zod";
|
|
7
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
8
|
+
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-message";
|
|
9
|
+
import { resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
5
10
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
11
|
+
//#region extensions/line/src/group-keys.ts
|
|
12
|
+
function resolveLineGroupLookupIds(groupId) {
|
|
13
|
+
const normalized = groupId?.trim();
|
|
14
|
+
if (!normalized) return [];
|
|
15
|
+
if (normalized.startsWith("group:") || normalized.startsWith("room:")) {
|
|
16
|
+
const rawId = normalized.split(":").slice(1).join(":");
|
|
17
|
+
return rawId ? [rawId, normalized] : [normalized];
|
|
18
|
+
}
|
|
19
|
+
return [
|
|
20
|
+
normalized,
|
|
21
|
+
`group:${normalized}`,
|
|
22
|
+
`room:${normalized}`
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function resolveLineGroupConfigEntry(groups, params) {
|
|
26
|
+
if (!groups) return;
|
|
27
|
+
for (const candidate of resolveLineGroupLookupIds(params.groupId)) {
|
|
28
|
+
const hit = groups[candidate];
|
|
29
|
+
if (hit) return hit;
|
|
30
|
+
}
|
|
31
|
+
for (const candidate of resolveLineGroupLookupIds(params.roomId)) {
|
|
32
|
+
const hit = groups[candidate];
|
|
33
|
+
if (hit) return hit;
|
|
34
|
+
}
|
|
35
|
+
return groups["*"];
|
|
36
|
+
}
|
|
37
|
+
function resolveLineGroupsConfig(cfg, accountId) {
|
|
38
|
+
const lineConfig = cfg.channels?.line;
|
|
39
|
+
if (!lineConfig) return;
|
|
40
|
+
const normalizedAccountId = normalizeAccountId(accountId);
|
|
41
|
+
return resolveAccountEntry(lineConfig.accounts, normalizedAccountId)?.groups ?? lineConfig.groups;
|
|
42
|
+
}
|
|
43
|
+
function resolveExactLineGroupConfigKey(params) {
|
|
44
|
+
const groups = resolveLineGroupsConfig(params.cfg, params.accountId);
|
|
45
|
+
if (!groups) return;
|
|
46
|
+
return resolveLineGroupLookupIds(params.groupId).find((candidate) => Object.hasOwn(groups, candidate));
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
6
49
|
//#region extensions/line/src/config-schema.ts
|
|
7
50
|
const DmPolicySchema = z.enum([
|
|
8
51
|
"open",
|
|
@@ -71,6 +114,88 @@ const LineConfigSchema = LineCommonConfigSchemaBase.extend({
|
|
|
71
114
|
});
|
|
72
115
|
const LineChannelConfigSchema = buildChannelConfigSchema(LineConfigSchema);
|
|
73
116
|
//#endregion
|
|
117
|
+
//#region extensions/line/src/runtime.ts
|
|
118
|
+
const { setRuntime: setLineRuntime, clearRuntime: clearLineRuntime, getRuntime: getLineRuntime } = createPluginRuntimeStore({
|
|
119
|
+
pluginId: "line",
|
|
120
|
+
errorMessage: "LINE runtime not initialized - plugin not registered"
|
|
121
|
+
});
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region extensions/line/src/outbound-media.ts
|
|
124
|
+
const LINE_OUTBOUND_MEDIA_SSRF_POLICY = { allowPrivateNetwork: false };
|
|
125
|
+
async function validateLineMediaUrl(url) {
|
|
126
|
+
let parsed;
|
|
127
|
+
try {
|
|
128
|
+
parsed = new URL(url);
|
|
129
|
+
} catch {
|
|
130
|
+
throw new Error(`LINE outbound media URL must be a valid URL: ${url}`);
|
|
131
|
+
}
|
|
132
|
+
if (parsed.protocol !== "https:") throw new Error(`LINE outbound media URL must use HTTPS: ${url}`);
|
|
133
|
+
if (url.length > 2e3) throw new Error(`LINE outbound media URL must be 2000 chars or less (got ${url.length})`);
|
|
134
|
+
await resolvePinnedHostnameWithPolicy(parsed.hostname, { policy: LINE_OUTBOUND_MEDIA_SSRF_POLICY });
|
|
135
|
+
}
|
|
136
|
+
function isHttpsUrl(url) {
|
|
137
|
+
try {
|
|
138
|
+
return new URL(url).protocol === "https:";
|
|
139
|
+
} catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function detectLineMediaKindFromUrl(url) {
|
|
144
|
+
try {
|
|
145
|
+
const pathname = normalizeLowercaseStringOrEmpty(new URL(url).pathname);
|
|
146
|
+
if (/\.(png|jpe?g|gif|webp|bmp|heic|heif|avif)$/i.test(pathname)) return "image";
|
|
147
|
+
if (/\.(mp4|mov|m4v|webm)$/i.test(pathname)) return "video";
|
|
148
|
+
if (/\.(mp3|m4a|aac|wav|ogg|oga)$/i.test(pathname)) return "audio";
|
|
149
|
+
} catch {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function resolveLineOutboundMedia(mediaUrl, opts = {}) {
|
|
154
|
+
const trimmedUrl = mediaUrl.trim();
|
|
155
|
+
if (isHttpsUrl(trimmedUrl)) {
|
|
156
|
+
await validateLineMediaUrl(trimmedUrl);
|
|
157
|
+
const previewImageUrl = opts.previewImageUrl?.trim();
|
|
158
|
+
if (previewImageUrl) await validateLineMediaUrl(previewImageUrl);
|
|
159
|
+
return {
|
|
160
|
+
mediaUrl: trimmedUrl,
|
|
161
|
+
mediaKind: opts.mediaKind ?? (typeof opts.durationMs === "number" ? "audio" : void 0) ?? (opts.trackingId?.trim() ? "video" : void 0) ?? detectLineMediaKindFromUrl(trimmedUrl) ?? "image",
|
|
162
|
+
...previewImageUrl ? { previewImageUrl } : {},
|
|
163
|
+
...typeof opts.durationMs === "number" ? { durationMs: opts.durationMs } : {},
|
|
164
|
+
...opts.trackingId ? { trackingId: opts.trackingId } : {}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
if (new URL(trimmedUrl).protocol !== "https:") throw new Error(`LINE outbound media URL must use HTTPS: ${trimmedUrl}`);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
if (e instanceof Error && e.message.startsWith("LINE outbound")) throw e;
|
|
171
|
+
}
|
|
172
|
+
throw new Error("LINE outbound media currently requires a public HTTPS URL");
|
|
173
|
+
}
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region extensions/line/src/quick-reply-fallback.ts
|
|
176
|
+
function buildLineQuickReplyFallbackText(labels) {
|
|
177
|
+
const normalized = (labels ?? []).map((label) => label.trim()).filter(Boolean).slice(0, 13);
|
|
178
|
+
if (normalized.length === 0) return "Choose an option.";
|
|
179
|
+
return `Options:\n${normalized.map((label) => `- ${label}`).join("\n")}`;
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region extensions/line/src/send-receipt.ts
|
|
183
|
+
function createLineSendReceipt(params) {
|
|
184
|
+
const messageId = params.messageId.trim();
|
|
185
|
+
const chatId = params.chatId.trim();
|
|
186
|
+
return createMessageReceiptFromOutboundResults({
|
|
187
|
+
results: messageId ? [{
|
|
188
|
+
channel: "line",
|
|
189
|
+
messageId,
|
|
190
|
+
chatId,
|
|
191
|
+
conversationId: chatId,
|
|
192
|
+
meta: { messageCount: params.messageCount ?? 1 }
|
|
193
|
+
}] : [],
|
|
194
|
+
...chatId ? { threadId: chatId } : {},
|
|
195
|
+
kind: params.kind ?? "unknown"
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
74
199
|
//#region extensions/line/src/flex-templates/media-control-cards.ts
|
|
75
200
|
/**
|
|
76
201
|
* Create a media player card for Sonos, Spotify, Apple Music, etc.
|
|
@@ -727,4 +852,4 @@ function hasLineDirectives(text) {
|
|
|
727
852
|
return /\[\[(quick_replies|location|confirm|buttons|media_player|event|agenda|device|appletv_remote):/i.test(text);
|
|
728
853
|
}
|
|
729
854
|
//#endregion
|
|
730
|
-
export { createMediaPlayerCard as a, createDeviceControlCard as i, parseLineDirectives as n,
|
|
855
|
+
export { resolveLineGroupsConfig as _, createMediaPlayerCard as a, resolveLineOutboundMedia as c, setLineRuntime as d, LineChannelConfigSchema as f, resolveLineGroupLookupIds as g, resolveLineGroupConfigEntry as h, createDeviceControlCard as i, validateLineMediaUrl as l, resolveExactLineGroupConfigKey as m, parseLineDirectives as n, createLineSendReceipt as o, LineConfigSchema as p, createAppleTvRemoteCard as r, buildLineQuickReplyFallbackText as s, hasLineDirectives as t, getLineRuntime as u };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-UXAvdBo_.js";
|
|
2
|
-
import { a as resolveLineGroupConfigEntry, i as resolveExactLineGroupConfigKey,
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
5
|
-
import { a as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as probeLineBot } from "./probe-Cla0gZ0b.js";
|
|
2
|
+
import { _ as resolveLineGroupsConfig, a as createMediaPlayerCard, d as setLineRuntime, f as LineChannelConfigSchema, g as resolveLineGroupLookupIds, h as resolveLineGroupConfigEntry, i as createDeviceControlCard, m as resolveExactLineGroupConfigKey, n as parseLineDirectives, p as LineConfigSchema, r as createAppleTvRemoteCard, t as hasLineDirectives } from "./reply-payload-transform-D2yrTDIV.js";
|
|
3
|
+
import { n as createEventCard, r as createReceiptCard, t as createAgendaCard } from "./schedule-cards-D-yZMHDE.js";
|
|
4
|
+
import { a as createListCard, i as createInfoCard, n as createCarousel, o as createNotificationBubble, r as createImageCard, t as createActionCard } from "./basic-cards-BISytiSa.js";
|
|
5
|
+
import { A as buildTemplateMessageFromPayload, B as createYesNoConfirm, C as pushMessagesLine, D as sendMessageLine, E as replyMessageLine, F as createImageCarousel, G as toFlexMessage, H as messageAction, I as createImageCarouselColumn, L as createLinkMenu, M as createButtonTemplate, N as createCarouselColumn, O as showLoadingAnimation, P as createConfirmTemplate, R as createProductCarousel, S as pushMessageLine, T as pushTextMessageWithQuickReplies, U as postbackAction, V as datetimePickerAction, W as uriAction, _ as getUserDisplayName, a as extractLinks, b as pushImageMessage, c as processLineMessage, d as createFlexMessage, f as createImageMessage, g as createVideoMessage, h as createTextMessageWithQuickReplies, i as extractCodeBlocks, j as createButtonMenu, k as resolveLineChannelAccessToken, l as stripMarkdown, m as createQuickReplyItems, n as convertLinksToFlexBubble, o as extractMarkdownTables, p as createLocationMessage, r as convertTableToFlexBubble, s as hasMarkdownToConvert, t as convertCodeBlockToFlexBubble, u as createAudioMessage, v as getUserProfile, w as pushTemplateMessage, x as pushLocationMessage, y as pushFlexMessage, z as createTemplateCarousel } from "./markdown-to-line-Bh4K93vo.js";
|
|
6
|
+
import { a as validateLineSignature, c as normalizeAllowFrom, i as parseLineWebhookBody, n as createLineNodeWebhookHandler, o as downloadLineMedia, r as readLineWebhookRequestBody, s as firstDefined, t as monitorLineProvider } from "./monitor--x8R-hee.js";
|
|
7
|
+
import { t as probeLineBot } from "./probe-CiPafR4R.js";
|
|
9
8
|
import { clearAccountEntryFields } from "openclaw/plugin-sdk/core";
|
|
10
9
|
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
11
10
|
import { createMessageReceiveContext } from "openclaw/plugin-sdk/channel-message";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/line",
|
|
3
|
-
"version": "2026.5.
|
|
3
|
+
"version": "2026.5.14-beta.2",
|
|
4
4
|
"description": "OpenClaw LINE channel plugin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"openclaw": "workspace:*"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"openclaw": ">=2026.5.
|
|
19
|
+
"openclaw": ">=2026.5.14-beta.2"
|
|
20
20
|
},
|
|
21
21
|
"peerDependenciesMeta": {
|
|
22
22
|
"openclaw": {
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"minHostVersion": ">=2026.4.10"
|
|
47
47
|
},
|
|
48
48
|
"compat": {
|
|
49
|
-
"pluginApi": ">=2026.5.
|
|
49
|
+
"pluginApi": ">=2026.5.14-beta.2"
|
|
50
50
|
},
|
|
51
51
|
"build": {
|
|
52
|
-
"openclawVersion": "2026.5.
|
|
52
|
+
"openclawVersion": "2026.5.14-beta.2"
|
|
53
53
|
},
|
|
54
54
|
"release": {
|
|
55
55
|
"publishToClawHub": true,
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
2
|
-
import { resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
|
|
3
|
-
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
4
|
-
//#region extensions/line/src/group-keys.ts
|
|
5
|
-
function resolveLineGroupLookupIds(groupId) {
|
|
6
|
-
const normalized = groupId?.trim();
|
|
7
|
-
if (!normalized) return [];
|
|
8
|
-
if (normalized.startsWith("group:") || normalized.startsWith("room:")) {
|
|
9
|
-
const rawId = normalized.split(":").slice(1).join(":");
|
|
10
|
-
return rawId ? [rawId, normalized] : [normalized];
|
|
11
|
-
}
|
|
12
|
-
return [
|
|
13
|
-
normalized,
|
|
14
|
-
`group:${normalized}`,
|
|
15
|
-
`room:${normalized}`
|
|
16
|
-
];
|
|
17
|
-
}
|
|
18
|
-
function resolveLineGroupConfigEntry(groups, params) {
|
|
19
|
-
if (!groups) return;
|
|
20
|
-
for (const candidate of resolveLineGroupLookupIds(params.groupId)) {
|
|
21
|
-
const hit = groups[candidate];
|
|
22
|
-
if (hit) return hit;
|
|
23
|
-
}
|
|
24
|
-
for (const candidate of resolveLineGroupLookupIds(params.roomId)) {
|
|
25
|
-
const hit = groups[candidate];
|
|
26
|
-
if (hit) return hit;
|
|
27
|
-
}
|
|
28
|
-
return groups["*"];
|
|
29
|
-
}
|
|
30
|
-
function resolveLineGroupsConfig(cfg, accountId) {
|
|
31
|
-
const lineConfig = cfg.channels?.line;
|
|
32
|
-
if (!lineConfig) return;
|
|
33
|
-
const normalizedAccountId = normalizeAccountId(accountId);
|
|
34
|
-
return resolveAccountEntry(lineConfig.accounts, normalizedAccountId)?.groups ?? lineConfig.groups;
|
|
35
|
-
}
|
|
36
|
-
function resolveExactLineGroupConfigKey(params) {
|
|
37
|
-
const groups = resolveLineGroupsConfig(params.cfg, params.accountId);
|
|
38
|
-
if (!groups) return;
|
|
39
|
-
return resolveLineGroupLookupIds(params.groupId).find((candidate) => Object.hasOwn(groups, candidate));
|
|
40
|
-
}
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region extensions/line/src/runtime.ts
|
|
43
|
-
const { setRuntime: setLineRuntime, clearRuntime: clearLineRuntime, getRuntime: getLineRuntime } = createPluginRuntimeStore({
|
|
44
|
-
pluginId: "line",
|
|
45
|
-
errorMessage: "LINE runtime not initialized - plugin not registered"
|
|
46
|
-
});
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region extensions/line/src/quick-reply-fallback.ts
|
|
49
|
-
function buildLineQuickReplyFallbackText(labels) {
|
|
50
|
-
const normalized = (labels ?? []).map((label) => label.trim()).filter(Boolean).slice(0, 13);
|
|
51
|
-
if (normalized.length === 0) return "Choose an option.";
|
|
52
|
-
return `Options:\n${normalized.map((label) => `- ${label}`).join("\n")}`;
|
|
53
|
-
}
|
|
54
|
-
//#endregion
|
|
55
|
-
export { resolveLineGroupConfigEntry as a, resolveExactLineGroupConfigKey as i, getLineRuntime as n, resolveLineGroupLookupIds as o, setLineRuntime as r, resolveLineGroupsConfig as s, buildLineQuickReplyFallbackText as t };
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-message";
|
|
2
|
-
import { resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
3
|
-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
|
-
//#region extensions/line/src/outbound-media.ts
|
|
5
|
-
const LINE_OUTBOUND_MEDIA_SSRF_POLICY = { allowPrivateNetwork: false };
|
|
6
|
-
async function validateLineMediaUrl(url) {
|
|
7
|
-
let parsed;
|
|
8
|
-
try {
|
|
9
|
-
parsed = new URL(url);
|
|
10
|
-
} catch {
|
|
11
|
-
throw new Error(`LINE outbound media URL must be a valid URL: ${url}`);
|
|
12
|
-
}
|
|
13
|
-
if (parsed.protocol !== "https:") throw new Error(`LINE outbound media URL must use HTTPS: ${url}`);
|
|
14
|
-
if (url.length > 2e3) throw new Error(`LINE outbound media URL must be 2000 chars or less (got ${url.length})`);
|
|
15
|
-
await resolvePinnedHostnameWithPolicy(parsed.hostname, { policy: LINE_OUTBOUND_MEDIA_SSRF_POLICY });
|
|
16
|
-
}
|
|
17
|
-
function isHttpsUrl(url) {
|
|
18
|
-
try {
|
|
19
|
-
return new URL(url).protocol === "https:";
|
|
20
|
-
} catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function detectLineMediaKindFromUrl(url) {
|
|
25
|
-
try {
|
|
26
|
-
const pathname = normalizeLowercaseStringOrEmpty(new URL(url).pathname);
|
|
27
|
-
if (/\.(png|jpe?g|gif|webp|bmp|heic|heif|avif)$/i.test(pathname)) return "image";
|
|
28
|
-
if (/\.(mp4|mov|m4v|webm)$/i.test(pathname)) return "video";
|
|
29
|
-
if (/\.(mp3|m4a|aac|wav|ogg|oga)$/i.test(pathname)) return "audio";
|
|
30
|
-
} catch {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
async function resolveLineOutboundMedia(mediaUrl, opts = {}) {
|
|
35
|
-
const trimmedUrl = mediaUrl.trim();
|
|
36
|
-
if (isHttpsUrl(trimmedUrl)) {
|
|
37
|
-
await validateLineMediaUrl(trimmedUrl);
|
|
38
|
-
const previewImageUrl = opts.previewImageUrl?.trim();
|
|
39
|
-
if (previewImageUrl) await validateLineMediaUrl(previewImageUrl);
|
|
40
|
-
return {
|
|
41
|
-
mediaUrl: trimmedUrl,
|
|
42
|
-
mediaKind: opts.mediaKind ?? (typeof opts.durationMs === "number" ? "audio" : void 0) ?? (opts.trackingId?.trim() ? "video" : void 0) ?? detectLineMediaKindFromUrl(trimmedUrl) ?? "image",
|
|
43
|
-
...previewImageUrl ? { previewImageUrl } : {},
|
|
44
|
-
...typeof opts.durationMs === "number" ? { durationMs: opts.durationMs } : {},
|
|
45
|
-
...opts.trackingId ? { trackingId: opts.trackingId } : {}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
if (new URL(trimmedUrl).protocol !== "https:") throw new Error(`LINE outbound media URL must use HTTPS: ${trimmedUrl}`);
|
|
50
|
-
} catch (e) {
|
|
51
|
-
if (e instanceof Error && e.message.startsWith("LINE outbound")) throw e;
|
|
52
|
-
}
|
|
53
|
-
throw new Error("LINE outbound media currently requires a public HTTPS URL");
|
|
54
|
-
}
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region extensions/line/src/send-receipt.ts
|
|
57
|
-
function createLineSendReceipt(params) {
|
|
58
|
-
const messageId = params.messageId.trim();
|
|
59
|
-
const chatId = params.chatId.trim();
|
|
60
|
-
return createMessageReceiptFromOutboundResults({
|
|
61
|
-
results: messageId ? [{
|
|
62
|
-
channel: "line",
|
|
63
|
-
messageId,
|
|
64
|
-
chatId,
|
|
65
|
-
conversationId: chatId,
|
|
66
|
-
meta: { messageCount: params.messageCount ?? 1 }
|
|
67
|
-
}] : [],
|
|
68
|
-
...chatId ? { threadId: chatId } : {},
|
|
69
|
-
kind: params.kind ?? "unknown"
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
//#endregion
|
|
73
|
-
export { resolveLineOutboundMedia as n, validateLineMediaUrl as r, createLineSendReceipt as t };
|
|
File without changes
|
|
File without changes
|