@openclaw/line 2026.8.1 → 2026.8.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/{accounts-BqEVsDoB.js → accounts-BBEFMYbY.js} +2 -1
- package/dist/api.js +2 -2
- package/dist/{card-command-BywtX77U.js → card-command-DS6A5V6o.js} +102 -111
- package/dist/{channel-DpMgRaxl.js → channel-CLCy4jAa.js} +51 -14
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel.runtime-Ih7sq1GN.js +4 -0
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/index.js +5 -17
- package/dist/{markdown-to-line-CG9Jy22s.js → markdown-to-line--jytmFan.js} +7 -4
- package/dist/{monitor-Ch6TIatG.js → monitor-CSpwQCBI.js} +54 -51
- package/dist/monitor.runtime-CV8EjkIT.js +2 -0
- package/dist/{outbound.runtime-CyleVzFR.js → outbound.runtime-DLqcz_BQ.js} +2 -2
- package/dist/{rich-messages-t_zRL24p.js → rich-messages-CIP7xn5E.js} +10 -9
- package/dist/runtime-api.js +6 -6
- package/dist/{send-B-K2B6au.js → send-wVUV00WS.js} +13 -6
- package/dist/setup-api.js +1 -1
- package/dist/{setup-surface-DSJ92oJ5.js → setup-surface-CDlgkTKi.js} +23 -22
- package/dist/{webhook-spool-contract-CNe2h1I2.js → webhook-spool-contract-1rY8OJw8.js} +2 -1
- package/node_modules/typebox/build/format/email.mjs +1 -1
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
- package/node_modules/typebox/package.json +1 -1
- package/package.json +5 -5
- package/dist/channel.runtime-Bty5U_1N.js +0 -4
- package/dist/monitor.runtime-Czc3NxNV.js +0 -2
|
@@ -16,7 +16,8 @@ function resolveLineCredential(params) {
|
|
|
16
16
|
};
|
|
17
17
|
const file = config?.[fileKey];
|
|
18
18
|
if (file?.trim()) {
|
|
19
|
-
const
|
|
19
|
+
const scope = index === 0 ? `accounts.${accountId}.` : "";
|
|
20
|
+
const result = tryReadSecretFileSync(file, "LINE credential file", { rejectSymlink: true }, { configPath: `channels.line.${scope}${fileKey}` });
|
|
20
21
|
return result.status === "available" ? {
|
|
21
22
|
value: result.value,
|
|
22
23
|
source: "file",
|
package/dist/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-
|
|
2
|
-
import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-
|
|
1
|
+
import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-CLCy4jAa.js";
|
|
2
|
+
import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-CDlgkTKi.js";
|
|
3
3
|
//#region extensions/line/src/channel.setup.ts
|
|
4
4
|
const lineSetupPlugin = {
|
|
5
5
|
id: "line",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as createActionCard, d as createListCard, l as createImageCard, s as createReceiptCard, u as createInfoCard } from "./send-retry-CUvrarfE.js";
|
|
2
|
-
import { t as createFlexMessage } from "./send-
|
|
2
|
+
import { t as createFlexMessage } from "./send-wVUV00WS.js";
|
|
3
3
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
5
5
|
//#region extensions/line/src/card-command.ts
|
|
@@ -145,117 +145,108 @@ function parseCardArgs(argsStrInput) {
|
|
|
145
145
|
}
|
|
146
146
|
return result;
|
|
147
147
|
}
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (ctx.channel !== "line") return { text: `[${type} card] ${args.join(" - ")}`.trim() };
|
|
160
|
-
try {
|
|
161
|
-
switch (type) {
|
|
162
|
-
case "info": {
|
|
163
|
-
const [title = "Info", body = "", footer] = args;
|
|
164
|
-
const bubble = createInfoCard(title, body, footer);
|
|
165
|
-
return buildLineFlexReply(body ? `${title}: ${body}` : title, bubble);
|
|
166
|
-
}
|
|
167
|
-
case "image": {
|
|
168
|
-
const [title = "Image", caption = ""] = args;
|
|
169
|
-
const imageUrl = flags.url || flags.image;
|
|
170
|
-
if (!imageUrl) return { text: "Error: Image card requires --url <image-url>" };
|
|
171
|
-
const bubble = createImageCard(imageUrl, title, caption);
|
|
172
|
-
return buildLineFlexReply(`${title}: ${caption}`, bubble);
|
|
173
|
-
}
|
|
174
|
-
case "action": {
|
|
175
|
-
const [title = "Actions", body = ""] = args;
|
|
176
|
-
const actions = parseActions(flags.actions);
|
|
177
|
-
if (actions.length === 0) return { text: "Error: Action card requires --actions \"Label1|data1,Label2|data2\"" };
|
|
178
|
-
const bubble = createActionCard(title, body, actions, { imageUrl: flags.url || flags.image });
|
|
179
|
-
return buildLineFlexReply(body ? `${title}: ${body}` : title, bubble);
|
|
180
|
-
}
|
|
181
|
-
case "list": {
|
|
182
|
-
const [title = "List", itemsStr = ""] = args;
|
|
183
|
-
const items = parseListItems(itemsStr || flags.items || "");
|
|
184
|
-
if (items.length === 0) return { text: "Error: List card requires items. Usage: /card list \"Title\" \"Item1|Desc1,Item2|Desc2\"" };
|
|
185
|
-
const bubble = createListCard(title, items);
|
|
186
|
-
return buildLineFlexReply(`${title}: ${items.map((item) => item.title).join(", ")}`, bubble);
|
|
187
|
-
}
|
|
188
|
-
case "receipt": {
|
|
189
|
-
const [title = "Receipt", itemsStr = ""] = args;
|
|
190
|
-
const items = parseReceiptItems(itemsStr || flags.items || "");
|
|
191
|
-
const total = flags.total ? {
|
|
192
|
-
label: "Total",
|
|
193
|
-
value: flags.total
|
|
194
|
-
} : void 0;
|
|
195
|
-
const footer = flags.footer;
|
|
196
|
-
if (items.length === 0) return { text: "Error: Receipt card requires items. Usage: /card receipt \"Title\" \"Item1:$10,Item2:$20\" --total \"$30\"" };
|
|
197
|
-
const bubble = createReceiptCard({
|
|
198
|
-
title,
|
|
199
|
-
items,
|
|
200
|
-
total,
|
|
201
|
-
footer
|
|
202
|
-
});
|
|
203
|
-
return buildLineFlexReply(`${title}: ${items.map((item) => `${item.name} ${item.value}`).join(", ")}`, bubble);
|
|
204
|
-
}
|
|
205
|
-
case "confirm": {
|
|
206
|
-
const [question = "Confirm?"] = args;
|
|
207
|
-
const yesStr = flags.yes || "Yes|yes";
|
|
208
|
-
const noStr = flags.no || "No|no";
|
|
209
|
-
const [yesLabel, yesData] = splitCardPair(yesStr);
|
|
210
|
-
const [noLabel, noData] = splitCardPair(noStr);
|
|
211
|
-
return buildLineReply({ templateMessage: {
|
|
212
|
-
type: "confirm",
|
|
213
|
-
text: question,
|
|
214
|
-
confirmLabel: yesLabel || "Yes",
|
|
215
|
-
confirmData: yesData || "yes",
|
|
216
|
-
cancelLabel: noLabel || "No",
|
|
217
|
-
cancelData: noData || "no",
|
|
218
|
-
altText: question
|
|
219
|
-
} });
|
|
220
|
-
}
|
|
221
|
-
case "buttons": {
|
|
222
|
-
const [title = "Menu", text = "Choose an option"] = args;
|
|
223
|
-
const actionParts = parseActions(flags.actions || "");
|
|
224
|
-
if (actionParts.length === 0) return { text: "Error: Buttons card requires --actions \"Label1|data1,Label2|data2\"" };
|
|
225
|
-
const templateActions = actionParts.map((a) => {
|
|
226
|
-
const action = a.action;
|
|
227
|
-
const label = action.label ?? a.label;
|
|
228
|
-
if (action.type === "uri") return {
|
|
229
|
-
type: "uri",
|
|
230
|
-
label,
|
|
231
|
-
uri: action.uri
|
|
232
|
-
};
|
|
233
|
-
if (action.type === "postback") return {
|
|
234
|
-
type: "postback",
|
|
235
|
-
label,
|
|
236
|
-
data: action.data
|
|
237
|
-
};
|
|
238
|
-
return {
|
|
239
|
-
type: "message",
|
|
240
|
-
label,
|
|
241
|
-
data: action.text
|
|
242
|
-
};
|
|
243
|
-
});
|
|
244
|
-
return buildLineReply({ templateMessage: {
|
|
245
|
-
type: "buttons",
|
|
246
|
-
title,
|
|
247
|
-
text,
|
|
248
|
-
thumbnailImageUrl: flags.url || flags.image,
|
|
249
|
-
actions: templateActions
|
|
250
|
-
} });
|
|
251
|
-
}
|
|
252
|
-
default: return { text: `Unknown card type: "${type}". Available types: info, image, action, list, receipt, confirm, buttons` };
|
|
253
|
-
}
|
|
254
|
-
} catch (err) {
|
|
255
|
-
return { text: `Error creating card: ${String(err)}` };
|
|
148
|
+
async function handleLineCardCommand(argsInput) {
|
|
149
|
+
const argsStr = argsInput?.trim() ?? "";
|
|
150
|
+
if (!argsStr) return { text: CARD_USAGE };
|
|
151
|
+
const { type, args, flags } = parseCardArgs(argsStr);
|
|
152
|
+
if (!type) return { text: CARD_USAGE };
|
|
153
|
+
try {
|
|
154
|
+
switch (type) {
|
|
155
|
+
case "info": {
|
|
156
|
+
const [title = "Info", body = "", footer] = args;
|
|
157
|
+
const bubble = createInfoCard(title, body, footer);
|
|
158
|
+
return buildLineFlexReply(body ? `${title}: ${body}` : title, bubble);
|
|
256
159
|
}
|
|
160
|
+
case "image": {
|
|
161
|
+
const [title = "Image", caption = ""] = args;
|
|
162
|
+
const imageUrl = flags.url || flags.image;
|
|
163
|
+
if (!imageUrl) return { text: "Error: Image card requires --url <image-url>" };
|
|
164
|
+
const bubble = createImageCard(imageUrl, title, caption);
|
|
165
|
+
return buildLineFlexReply(`${title}: ${caption}`, bubble);
|
|
166
|
+
}
|
|
167
|
+
case "action": {
|
|
168
|
+
const [title = "Actions", body = ""] = args;
|
|
169
|
+
const actions = parseActions(flags.actions);
|
|
170
|
+
if (actions.length === 0) return { text: "Error: Action card requires --actions \"Label1|data1,Label2|data2\"" };
|
|
171
|
+
const bubble = createActionCard(title, body, actions, { imageUrl: flags.url || flags.image });
|
|
172
|
+
return buildLineFlexReply(body ? `${title}: ${body}` : title, bubble);
|
|
173
|
+
}
|
|
174
|
+
case "list": {
|
|
175
|
+
const [title = "List", itemsStr = ""] = args;
|
|
176
|
+
const items = parseListItems(itemsStr || flags.items || "");
|
|
177
|
+
if (items.length === 0) return { text: "Error: List card requires items. Usage: /card list \"Title\" \"Item1|Desc1,Item2|Desc2\"" };
|
|
178
|
+
const bubble = createListCard(title, items);
|
|
179
|
+
return buildLineFlexReply(`${title}: ${items.map((item) => item.title).join(", ")}`, bubble);
|
|
180
|
+
}
|
|
181
|
+
case "receipt": {
|
|
182
|
+
const [title = "Receipt", itemsStr = ""] = args;
|
|
183
|
+
const items = parseReceiptItems(itemsStr || flags.items || "");
|
|
184
|
+
const total = flags.total ? {
|
|
185
|
+
label: "Total",
|
|
186
|
+
value: flags.total
|
|
187
|
+
} : void 0;
|
|
188
|
+
const footer = flags.footer;
|
|
189
|
+
if (items.length === 0) return { text: "Error: Receipt card requires items. Usage: /card receipt \"Title\" \"Item1:$10,Item2:$20\" --total \"$30\"" };
|
|
190
|
+
const bubble = createReceiptCard({
|
|
191
|
+
title,
|
|
192
|
+
items,
|
|
193
|
+
total,
|
|
194
|
+
footer
|
|
195
|
+
});
|
|
196
|
+
return buildLineFlexReply(`${title}: ${items.map((item) => `${item.name} ${item.value}`).join(", ")}`, bubble);
|
|
197
|
+
}
|
|
198
|
+
case "confirm": {
|
|
199
|
+
const [question = "Confirm?"] = args;
|
|
200
|
+
const yesStr = flags.yes || "Yes|yes";
|
|
201
|
+
const noStr = flags.no || "No|no";
|
|
202
|
+
const [yesLabel, yesData] = splitCardPair(yesStr);
|
|
203
|
+
const [noLabel, noData] = splitCardPair(noStr);
|
|
204
|
+
return buildLineReply({ templateMessage: {
|
|
205
|
+
type: "confirm",
|
|
206
|
+
text: question,
|
|
207
|
+
confirmLabel: yesLabel || "Yes",
|
|
208
|
+
confirmData: yesData || "yes",
|
|
209
|
+
cancelLabel: noLabel || "No",
|
|
210
|
+
cancelData: noData || "no",
|
|
211
|
+
altText: question
|
|
212
|
+
} });
|
|
213
|
+
}
|
|
214
|
+
case "buttons": {
|
|
215
|
+
const [title = "Menu", text = "Choose an option"] = args;
|
|
216
|
+
const actionParts = parseActions(flags.actions || "");
|
|
217
|
+
if (actionParts.length === 0) return { text: "Error: Buttons card requires --actions \"Label1|data1,Label2|data2\"" };
|
|
218
|
+
const templateActions = actionParts.map((a) => {
|
|
219
|
+
const action = a.action;
|
|
220
|
+
const label = action.label ?? a.label;
|
|
221
|
+
if (action.type === "uri") return {
|
|
222
|
+
type: "uri",
|
|
223
|
+
label,
|
|
224
|
+
uri: action.uri
|
|
225
|
+
};
|
|
226
|
+
if (action.type === "postback") return {
|
|
227
|
+
type: "postback",
|
|
228
|
+
label,
|
|
229
|
+
data: action.data
|
|
230
|
+
};
|
|
231
|
+
return {
|
|
232
|
+
type: "message",
|
|
233
|
+
label,
|
|
234
|
+
data: action.text
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
return buildLineReply({ templateMessage: {
|
|
238
|
+
type: "buttons",
|
|
239
|
+
title,
|
|
240
|
+
text,
|
|
241
|
+
thumbnailImageUrl: flags.url || flags.image,
|
|
242
|
+
actions: templateActions
|
|
243
|
+
} });
|
|
244
|
+
}
|
|
245
|
+
default: return { text: `Unknown card type: "${type}". Available types: info, image, action, list, receipt, confirm, buttons` };
|
|
257
246
|
}
|
|
258
|
-
})
|
|
247
|
+
} catch (err) {
|
|
248
|
+
return { text: `Error creating card: ${String(err)}` };
|
|
249
|
+
}
|
|
259
250
|
}
|
|
260
251
|
//#endregion
|
|
261
|
-
export {
|
|
252
|
+
export { handleLineCardCommand };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-
|
|
1
|
+
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.js";
|
|
2
2
|
import { t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
|
|
3
|
-
import { _ as LineChannelConfigSchema, a as renderLineCard, d as resolveExactLineGroupConfigKey, h as getLineRuntime, n as createLineQuickReply, o as renderLinePresentation, r as lineMessageActions, t as LINE_PRESENTATION_CAPABILITIES, u as buildLineQuickReplyFallbackText } from "./rich-messages-
|
|
3
|
+
import { _ as LineChannelConfigSchema, a as renderLineCard, d as resolveExactLineGroupConfigKey, h as getLineRuntime, n as createLineQuickReply, o as renderLinePresentation, p as resolveLineGroupLookupIds, r as lineMessageActions, t as LINE_PRESENTATION_CAPABILITIES, u as buildLineQuickReplyFallbackText } from "./rich-messages-CIP7xn5E.js";
|
|
4
4
|
import { i as createLineSendReceipt, n as resolveLineNonDispatchRetryable, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.js";
|
|
5
|
-
import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-
|
|
5
|
+
import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-CDlgkTKi.js";
|
|
6
6
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
7
7
|
import { buildDmGroupAccountAllowlistAdapter, createFlatAllowlistOverrideResolver } from "openclaw/plugin-sdk/allowlist-config-edit";
|
|
8
8
|
import { buildChannelOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
9
9
|
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
10
10
|
import { buildChannelGroupsScopeTree, createRestrictSendersChannelSecurity, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
11
|
-
import {
|
|
11
|
+
import { createChannelDirectoryAdapter, createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-runtime";
|
|
12
12
|
import { describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
13
13
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
14
14
|
import { clearAccountFieldsFromConfigSection, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
@@ -120,7 +120,7 @@ const lineChannelPluginCommon = {
|
|
|
120
120
|
//#endregion
|
|
121
121
|
//#region extensions/line/src/gateway.ts
|
|
122
122
|
const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-DTxBWvKz.js"));
|
|
123
|
-
const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-
|
|
123
|
+
const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-CV8EjkIT.js"));
|
|
124
124
|
const lineGatewayAdapter = {
|
|
125
125
|
startAccount: async (ctx) => {
|
|
126
126
|
const account = ctx.account;
|
|
@@ -211,7 +211,7 @@ function inferLineTargetChatType(target) {
|
|
|
211
211
|
}
|
|
212
212
|
//#endregion
|
|
213
213
|
//#region extensions/line/src/outbound.ts
|
|
214
|
-
const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-
|
|
214
|
+
const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-DLqcz_BQ.js"));
|
|
215
215
|
const lineOutboundAdapter = {
|
|
216
216
|
deliveryMode: "direct",
|
|
217
217
|
chunker: (text, limit) => getLineRuntime().channel.text.chunkMarkdownText(text, limit),
|
|
@@ -334,12 +334,13 @@ const lineOutboundAdapter = {
|
|
|
334
334
|
if (mediaUrls.length > 0 && !shouldSendQuickRepliesInline && !sendMediaAfterText) await sendMediaMessages();
|
|
335
335
|
if (orderedMessages && !shouldSendQuickRepliesInline) for (const [index, message] of orderedMessages.entries()) {
|
|
336
336
|
const isLast = index === orderedMessages.length - 1;
|
|
337
|
-
if (message.type === "flex")
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
337
|
+
if (message.type === "flex") {
|
|
338
|
+
if (isLast && quickReply) await sendMessageBatch([{
|
|
339
|
+
...message,
|
|
340
|
+
quickReply
|
|
341
|
+
}]);
|
|
342
|
+
else await recordResult(sendFlex(to, message.altText, message.contents, sendOptions));
|
|
343
|
+
} else if (isLast && hasQuickReplies) await sendTextWithQuickReply(message.text);
|
|
343
344
|
else await recordResult(sendText(to, message.text, sendOptions));
|
|
344
345
|
}
|
|
345
346
|
else if (chunks.length > 0) for (const [i, chunk] of chunks.entries()) if (i === chunks.length - 1 && hasQuickReplies) await sendTextWithQuickReply(chunk);
|
|
@@ -471,7 +472,7 @@ const lineStatusAdapter = createComputedAccountStatusAdapter({
|
|
|
471
472
|
});
|
|
472
473
|
//#endregion
|
|
473
474
|
//#region extensions/line/src/channel.ts
|
|
474
|
-
const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
475
|
+
const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-Ih7sq1GN.js"));
|
|
475
476
|
const lineSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
476
477
|
channelKey: "line",
|
|
477
478
|
resolveDmPolicy: (account) => account.config.dmPolicy,
|
|
@@ -487,6 +488,10 @@ const lineSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
|
487
488
|
approveHint: "openclaw pairing approve line <code>",
|
|
488
489
|
normalizeDmEntry: (raw) => raw.replace(/^line:(?:user:)?/i, "")
|
|
489
490
|
});
|
|
491
|
+
function normalizeLineDirectoryId(entry, kind) {
|
|
492
|
+
const id = normalizeLineMessagingTarget(entry);
|
|
493
|
+
return id && inferLineTargetChatType(id) === kind ? id : null;
|
|
494
|
+
}
|
|
490
495
|
const linePlugin = createChatChannelPlugin({
|
|
491
496
|
base: {
|
|
492
497
|
id: "line",
|
|
@@ -548,10 +553,42 @@ const linePlugin = createChatChannelPlugin({
|
|
|
548
553
|
hint: "<userId|groupId|roomId>"
|
|
549
554
|
}
|
|
550
555
|
},
|
|
551
|
-
directory:
|
|
556
|
+
directory: createChannelDirectoryAdapter({
|
|
557
|
+
listPeers: createResolvedDirectoryEntriesLister({
|
|
558
|
+
kind: "user",
|
|
559
|
+
resolveAccount: (cfg, accountId) => resolveLineAccount({
|
|
560
|
+
cfg,
|
|
561
|
+
accountId: accountId ?? void 0
|
|
562
|
+
}),
|
|
563
|
+
resolveSources: ({ config }) => [
|
|
564
|
+
config.allowFrom ?? [],
|
|
565
|
+
config.groupAllowFrom ?? [],
|
|
566
|
+
...Object.values(config.groups ?? {}).map((group) => group?.allowFrom ?? [])
|
|
567
|
+
],
|
|
568
|
+
normalizeId: (entry) => normalizeLineDirectoryId(entry, "direct")
|
|
569
|
+
}),
|
|
570
|
+
listGroups: createResolvedDirectoryEntriesLister({
|
|
571
|
+
kind: "group",
|
|
572
|
+
resolveAccount: (cfg, accountId) => resolveLineAccount({
|
|
573
|
+
cfg,
|
|
574
|
+
accountId: accountId ?? void 0
|
|
575
|
+
}),
|
|
576
|
+
resolveSources: ({ config }) => [Object.keys(config.groups ?? {})],
|
|
577
|
+
normalizeId: (entry) => normalizeLineDirectoryId(resolveLineGroupLookupIds(entry)[0] ?? "", "group")
|
|
578
|
+
})
|
|
579
|
+
}),
|
|
552
580
|
setupContract: lineSetupContract,
|
|
553
581
|
status: lineStatusAdapter,
|
|
554
582
|
gateway: lineGatewayAdapter,
|
|
583
|
+
heartbeat: { sendTyping: async ({ cfg, to, accountId }) => {
|
|
584
|
+
const chatId = normalizeLineMessagingTarget(to);
|
|
585
|
+
if (!chatId || inferLineTargetChatType(chatId) !== "direct") return;
|
|
586
|
+
const { showLoadingAnimation } = await loadLineChannelRuntime();
|
|
587
|
+
await showLoadingAnimation(chatId, {
|
|
588
|
+
cfg,
|
|
589
|
+
accountId: accountId ?? void 0
|
|
590
|
+
});
|
|
591
|
+
} },
|
|
555
592
|
message: lineMessageAdapter,
|
|
556
593
|
actions: lineMessageActions,
|
|
557
594
|
bindings: lineBindingsAdapter,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as linePlugin } from "./channel-
|
|
1
|
+
import { t as linePlugin } from "./channel-CLCy4jAa.js";
|
|
2
2
|
export { linePlugin };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { t as monitorLineProvider } from "./monitor-CSpwQCBI.js";
|
|
2
|
+
import { t as probeLineBot } from "./probe-4gc_YQ2L.js";
|
|
3
|
+
import { _ as showLoadingAnimation, d as pushMessageLine } from "./send-wVUV00WS.js";
|
|
4
|
+
export { monitorLineProvider, probeLineBot, pushMessageLine, showLoadingAnimation };
|
package/dist/contract-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-
|
|
1
|
+
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.js";
|
|
2
2
|
export { listLineAccountIds, resolveDefaultLineAccountId, resolveLineAccount };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as eventIdFor, i as errorText, o as laneKeyFor, r as LineWebhookPayloadError, s as legacyEventIdFor, t as LINE_WEBHOOK_SPOOL_INVALID_EVENT_REASON } from "./webhook-spool-contract-
|
|
1
|
+
import { a as eventIdFor, i as errorText, o as laneKeyFor, r as LineWebhookPayloadError, s as legacyEventIdFor, t as LINE_WEBHOOK_SPOOL_INVALID_EVENT_REASON } from "./webhook-spool-contract-1rY8OJw8.js";
|
|
2
2
|
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
//#region extensions/line/src/webhook-spool-migration.ts
|
|
4
4
|
/** Pre-drain (#109655) rows stored the event object under `event` instead of the
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
2
2
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
3
3
|
//#region extensions/line/index.ts
|
|
4
|
-
|
|
5
|
-
return createLazyRuntimeModule(async () => {
|
|
6
|
-
let registered = null;
|
|
7
|
-
const { registerLineCardCommand } = await import("./card-command-BywtX77U.js");
|
|
8
|
-
registerLineCardCommand({
|
|
9
|
-
...api,
|
|
10
|
-
registerCommand(command) {
|
|
11
|
-
registered = command;
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
if (!registered) throw new Error("LINE card command registration unavailable");
|
|
15
|
-
return registered;
|
|
16
|
-
});
|
|
17
|
-
}
|
|
4
|
+
const loadLineCardCommand = createLazyRuntimeModule(() => import("./card-command-DS6A5V6o.js"));
|
|
18
5
|
var line_default = defineBundledChannelEntry({
|
|
19
6
|
id: "line",
|
|
20
7
|
name: "LINE",
|
|
@@ -29,14 +16,15 @@ var line_default = defineBundledChannelEntry({
|
|
|
29
16
|
exportName: "setLineRuntime"
|
|
30
17
|
},
|
|
31
18
|
registerFull(api) {
|
|
32
|
-
const loadLineCardCommand = createLineCardCommandLoader(api);
|
|
33
19
|
api.registerCommand({
|
|
34
20
|
name: "card",
|
|
35
|
-
description: "Send a rich card message
|
|
21
|
+
description: "Send a rich card message.",
|
|
22
|
+
channels: ["line"],
|
|
36
23
|
acceptsArgs: true,
|
|
37
24
|
requireAuth: false,
|
|
38
25
|
async handler(ctx) {
|
|
39
|
-
|
|
26
|
+
const { handleLineCardCommand } = await loadLineCardCommand();
|
|
27
|
+
return await handleLineCardCommand(ctx.args);
|
|
40
28
|
}
|
|
41
29
|
});
|
|
42
30
|
}
|
|
@@ -213,10 +213,13 @@ function projectPlainText(ir, omitted = [], additionalInsertions = [], onSegment
|
|
|
213
213
|
text: TRANSCRIPT_ROLE_PREFIX
|
|
214
214
|
});
|
|
215
215
|
const inlineCodeSpans = ir.styles.filter((span) => span.style === "code" && !omitted.some((range) => rangesOverlap(range, span)));
|
|
216
|
-
for (const span of inlineCodeSpans)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
for (const span of inlineCodeSpans) {
|
|
217
|
+
const code = ir.text.slice(span.start, span.end);
|
|
218
|
+
if (stripMarkdown(code, { assistantTranscriptRoleHeaders: true }).startsWith(TRANSCRIPT_ROLE_PREFIX)) insertions.push({
|
|
219
|
+
position: span.start,
|
|
220
|
+
text: TRANSCRIPT_ROLE_PREFIX
|
|
221
|
+
});
|
|
222
|
+
}
|
|
220
223
|
insertions.sort((left, right) => left.position - right.position);
|
|
221
224
|
const underlineTags = [...ir.text.matchAll(/<\/?u>/gi)].map((match) => ({
|
|
222
225
|
start: match.index,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i as resolveLineAccount, r as resolveDefaultLineAccountId } from "./accounts-
|
|
2
|
-
import { f as resolveLineGroupConfigEntry, h as getLineRuntime, i as prepareLineReplyPayload, n as createLineQuickReply, u as buildLineQuickReplyFallbackText } from "./rich-messages-
|
|
1
|
+
import { i as resolveLineAccount, r as resolveDefaultLineAccountId } from "./accounts-BBEFMYbY.js";
|
|
2
|
+
import { f as resolveLineGroupConfigEntry, h as getLineRuntime, i as prepareLineReplyPayload, n as createLineQuickReply, u as buildLineQuickReplyFallbackText } from "./rich-messages-CIP7xn5E.js";
|
|
3
3
|
import { n as resolveLineNonDispatchRetryable, t as findLineHttpError, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.js";
|
|
4
|
-
import { a as eventIdFor, n as LINE_WEBHOOK_SPOOL_INVALID_PAYLOAD_MESSAGE, o as laneKeyFor, r as LineWebhookPayloadError, t as LINE_WEBHOOK_SPOOL_INVALID_EVENT_REASON } from "./webhook-spool-contract-
|
|
5
|
-
import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line
|
|
6
|
-
import { _ as showLoadingAnimation, a as getLineGroupName, d as pushMessageLine, f as pushMessagesLine, h as replyMessageLine, n as createLocationMessage, o as getUserDisplayName, s as getUserProfile, t as createFlexMessage, v as quotesLineBotMessage } from "./send-
|
|
4
|
+
import { a as eventIdFor, n as LINE_WEBHOOK_SPOOL_INVALID_PAYLOAD_MESSAGE, o as laneKeyFor, r as LineWebhookPayloadError, t as LINE_WEBHOOK_SPOOL_INVALID_EVENT_REASON } from "./webhook-spool-contract-1rY8OJw8.js";
|
|
5
|
+
import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line--jytmFan.js";
|
|
6
|
+
import { _ as showLoadingAnimation, a as getLineGroupName, d as pushMessageLine, f as pushMessagesLine, h as replyMessageLine, n as createLocationMessage, o as getUserDisplayName, s as getUserProfile, t as createFlexMessage, v as quotesLineBotMessage } from "./send-wVUV00WS.js";
|
|
7
7
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
8
8
|
import { normalizeOptionalString, normalizeStringEntries, readNonEmptyStringPreservingWhitespace } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
9
|
import { DEFAULT_INGRESS_ADOPTION_STALL_MS, DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS, bindIngressLifecycleToReplyOptions, createChannelIngressMonitor } from "openclaw/plugin-sdk/channel-outbound";
|
|
@@ -21,6 +21,7 @@ import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, waitForA
|
|
|
21
21
|
import { fetchWithRuntimeDispatcherOrMockedGlobal } from "openclaw/plugin-sdk/runtime-fetch";
|
|
22
22
|
import crypto from "node:crypto";
|
|
23
23
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
24
|
+
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
24
25
|
import { channelReadyPatch, channelStoppedPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
25
26
|
import { chunkMarkdownText } from "openclaw/plugin-sdk/reply-runtime";
|
|
26
27
|
import { canonicalizeWebhookRouteKey, isRequestBodyLimitError, normalizePluginHttpPath, normalizeWebhookPath, registerWebhookTargetWithPluginRoute, requestBodyErrorToText, resolveSingleWebhookTarget } from "openclaw/plugin-sdk/webhook-ingress";
|
|
@@ -28,7 +29,7 @@ import { beginWebhookRequestPipelineOrReject, createWebhookInFlightLimiter, isRe
|
|
|
28
29
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
29
30
|
import { DEFAULT_GROUP_HISTORY_LIMIT, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
30
31
|
import { getRuntimeConfig, getRuntimeConfigSnapshot, getRuntimeConfigSourceSnapshot, selectApplicableRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
31
|
-
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
32
|
+
import { resolveChannelImplicitMentions, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
32
33
|
import { reportChannelRoomJoin } from "openclaw/plugin-sdk/channel-join-intro-runtime";
|
|
33
34
|
import { hasControlCommand } from "openclaw/plugin-sdk/command-auth-native";
|
|
34
35
|
import { ensureConfiguredBindingRouteReady, readChannelAllowFromStore, resolveConfiguredBindingRoute, resolvePairingIdLabel, resolvePinnedMainDmOwnerFromAllowlist, resolveRuntimeConversationBindingRoute, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
|
|
@@ -111,7 +112,7 @@ async function fetchLineContentWhenReady(messageId, channelAccessToken, signal)
|
|
|
111
112
|
}
|
|
112
113
|
await response.body?.cancel().catch(() => void 0);
|
|
113
114
|
if (response.status !== 202) throw new MediaFetchError("http_error", `LINE media download failed for message ${messageId} (HTTP ${response.status})`, { status: response.status });
|
|
114
|
-
if (attempt <
|
|
115
|
+
if (attempt < 5) await setTimeout$1(contentBackoffDelayMs(attempt), void 0, { signal });
|
|
115
116
|
}
|
|
116
117
|
} catch (err) {
|
|
117
118
|
if (signal.aborted) throw signal.reason;
|
|
@@ -126,7 +127,7 @@ function isRetryableLineInboundMediaError(err) {
|
|
|
126
127
|
if (err.code === "http_error") return err.status === 202 || err.status === 408 || err.status === 429 || typeof err.status === "number" && err.status >= 500;
|
|
127
128
|
return false;
|
|
128
129
|
}
|
|
129
|
-
async function downloadLineMedia(messageId, channelAccessToken, maxBytes =
|
|
130
|
+
async function downloadLineMedia(messageId, channelAccessToken, maxBytes = 10485760, options) {
|
|
130
131
|
options?.signal?.throwIfAborted();
|
|
131
132
|
const deadlineAbort = new AbortController();
|
|
132
133
|
const signal = options?.signal ? AbortSignal.any([options.signal, deadlineAbort.signal]) : deadlineAbort.signal;
|
|
@@ -479,8 +480,13 @@ function describeLineSticker(sticker) {
|
|
|
479
480
|
const description = readNonEmptyStringPreservingWhitespace(sticker.text) ?? normalizeStringEntries(sticker.keywords ?? []).slice(0, 3).join(", ");
|
|
480
481
|
return description ? `[Sent a sticker: ${description}]` : "[Sent a sticker]";
|
|
481
482
|
}
|
|
483
|
+
function readLineTextMessageBody(message) {
|
|
484
|
+
let text = message.text;
|
|
485
|
+
for (const { index, length } of (message.emojis ?? []).toSorted((a, b) => b.index - a.index)) if (index >= 0 && length === 2 && text.slice(index, index + length) === "()") text = `${text.slice(0, index)}[emoji]${text.slice(index + length)}`;
|
|
486
|
+
return text;
|
|
487
|
+
}
|
|
482
488
|
function extractMessageText(message) {
|
|
483
|
-
if (message.type === "text") return message
|
|
489
|
+
if (message.type === "text") return readLineTextMessageBody(message);
|
|
484
490
|
if (message.type === "location") {
|
|
485
491
|
const loc = message;
|
|
486
492
|
return formatLocationText({
|
|
@@ -594,7 +600,8 @@ async function finalizeLineInboundContext(params) {
|
|
|
594
600
|
if (shouldLogVerbose()) {
|
|
595
601
|
const preview = truncateUtf16Safe(body, 200).replace(/\n/g, "\\n");
|
|
596
602
|
const mediaInfo = params.verboseLog.kind === "inbound" && (params.verboseLog.mediaCount ?? 0) > 1 ? ` mediaCount=${params.verboseLog.mediaCount}` : "";
|
|
597
|
-
|
|
603
|
+
const label = params.verboseLog.kind === "inbound" ? "line inbound" : "line postback";
|
|
604
|
+
logVerbose(`${label}: from=${ctxPayload.From} len=${body.length}${mediaInfo} preview="${preview}"`);
|
|
598
605
|
}
|
|
599
606
|
return {
|
|
600
607
|
ctxPayload,
|
|
@@ -816,19 +823,6 @@ function isDownloadableLineMessageType(messageType) {
|
|
|
816
823
|
function normalizeLineIngressEntry(value) {
|
|
817
824
|
return normalizeLineAllowEntry(value) || null;
|
|
818
825
|
}
|
|
819
|
-
function resolveLineGroupConfig(params) {
|
|
820
|
-
return resolveLineGroupConfigEntry(params.config.groups, {
|
|
821
|
-
groupId: params.groupId,
|
|
822
|
-
roomId: params.roomId
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
function resolveLineRuntimeGroupPolicy({ cfg, account }) {
|
|
826
|
-
return resolveAllowlistProviderRuntimeGroupPolicy({
|
|
827
|
-
providerConfigPresent: cfg.channels?.line !== void 0,
|
|
828
|
-
groupPolicy: account.config.groupPolicy,
|
|
829
|
-
defaultGroupPolicy: resolveDefaultGroupPolicy(cfg)
|
|
830
|
-
});
|
|
831
|
-
}
|
|
832
826
|
async function sendLinePairingReply(params) {
|
|
833
827
|
const { senderId, replyToken, context } = params;
|
|
834
828
|
const idLabel = (() => {
|
|
@@ -880,19 +874,22 @@ async function sendLinePairingReply(params) {
|
|
|
880
874
|
}
|
|
881
875
|
});
|
|
882
876
|
}
|
|
883
|
-
async function
|
|
877
|
+
async function resolveLineEventAdmission(event, context) {
|
|
884
878
|
const { cfg, account } = context;
|
|
885
879
|
const { userId, groupId, roomId, isGroup } = getLineSourceInfo(event.source);
|
|
886
880
|
const senderId = userId ?? "";
|
|
887
|
-
const groupConfig =
|
|
888
|
-
config: account.config,
|
|
881
|
+
const groupConfig = resolveLineGroupConfigEntry(account.config.groups, {
|
|
889
882
|
groupId,
|
|
890
883
|
roomId
|
|
891
884
|
});
|
|
892
885
|
const rawText = resolveEventRawText(event);
|
|
893
886
|
const requireMention = isGroup ? groupConfig?.requireMention !== false : false;
|
|
894
887
|
const dmPolicy = account.config.dmPolicy ?? "pairing";
|
|
895
|
-
const { groupPolicy: runtimeGroupPolicy, providerMissingFallbackApplied } =
|
|
888
|
+
const { groupPolicy: runtimeGroupPolicy, providerMissingFallbackApplied } = resolveAllowlistProviderRuntimeGroupPolicy({
|
|
889
|
+
providerConfigPresent: cfg.channels?.line !== void 0,
|
|
890
|
+
groupPolicy: account.config.groupPolicy,
|
|
891
|
+
defaultGroupPolicy: resolveDefaultGroupPolicy(cfg)
|
|
892
|
+
});
|
|
896
893
|
const groupPolicy = runtimeGroupPolicy === "disabled" ? "disabled" : groupConfig?.allowFrom !== void 0 ? "allowlist" : runtimeGroupPolicy;
|
|
897
894
|
const groupAllowFrom = normalizeStringEntries(firstDefined(groupConfig?.allowFrom, account.config.groupAllowFrom));
|
|
898
895
|
const mentionFacts = (() => {
|
|
@@ -933,7 +930,7 @@ async function shouldProcessLineEvent(event, context) {
|
|
|
933
930
|
},
|
|
934
931
|
cfg,
|
|
935
932
|
readStoreAllowFrom: async () => await readChannelAllowFromStore("line", void 0, account.accountId),
|
|
936
|
-
subject: { stableId: senderId },
|
|
933
|
+
subject: event.type === "join" ? {} : { stableId: senderId },
|
|
937
934
|
conversation: {
|
|
938
935
|
kind: isGroup ? "group" : "direct",
|
|
939
936
|
id: (groupId ?? roomId ?? senderId) || "unknown"
|
|
@@ -949,14 +946,19 @@ async function shouldProcessLineEvent(event, context) {
|
|
|
949
946
|
hasAnyMention: mentionFacts.hasAnyMention,
|
|
950
947
|
implicitMentionKinds: mentionFacts.implicitMentionKinds
|
|
951
948
|
} : void 0,
|
|
952
|
-
event: { kind: event.type === "
|
|
949
|
+
event: { kind: event.type === "join" ? "system" : event.type },
|
|
953
950
|
dmPolicy,
|
|
954
951
|
groupPolicy,
|
|
955
952
|
policy: {
|
|
956
953
|
groupAllowFromFallbackToAllowFrom: false,
|
|
957
954
|
activation: {
|
|
958
955
|
requireMention: isGroup && event.type === "message" && requireMention,
|
|
959
|
-
allowTextCommands: true
|
|
956
|
+
allowTextCommands: true,
|
|
957
|
+
implicitMentions: resolveChannelImplicitMentions({
|
|
958
|
+
cfg,
|
|
959
|
+
channel: "line",
|
|
960
|
+
accountId: account.accountId
|
|
961
|
+
})
|
|
960
962
|
}
|
|
961
963
|
},
|
|
962
964
|
allowFrom: normalizeStringEntries(account.config.allowFrom),
|
|
@@ -973,6 +975,10 @@ async function shouldProcessLineEvent(event, context) {
|
|
|
973
975
|
accountId: account.accountId,
|
|
974
976
|
log: (message) => logVerbose(message)
|
|
975
977
|
});
|
|
978
|
+
if (event.type === "join") return groupConfig?.enabled !== false && groupPolicy !== "disabled" && (groupPolicy !== "allowlist" || access.state.allowlists.group.hasMatchableEntries) ? {
|
|
979
|
+
access,
|
|
980
|
+
resolveBoundAccess: resolveAccess
|
|
981
|
+
} : null;
|
|
976
982
|
if (access.senderAccess.decision === "allow" && (access.ingress.admission === "dispatch" || access.ingress.admission === "observe" || access.ingress.admission === "skip")) return {
|
|
977
983
|
access,
|
|
978
984
|
resolveBoundAccess: resolveAccess
|
|
@@ -1027,7 +1033,7 @@ function resolveLineQuotedMessageId(message) {
|
|
|
1027
1033
|
function resolveEventRawText(event) {
|
|
1028
1034
|
if (event.type === "message") {
|
|
1029
1035
|
const msg = event.message;
|
|
1030
|
-
if (msg.type === "text") return msg
|
|
1036
|
+
if (msg.type === "text") return readLineTextMessageBody(msg);
|
|
1031
1037
|
return "";
|
|
1032
1038
|
}
|
|
1033
1039
|
if (event.type === "postback") return event.postback?.data?.trim() ?? "";
|
|
@@ -1036,11 +1042,11 @@ function resolveEventRawText(event) {
|
|
|
1036
1042
|
async function handleMessageEvent(event, context) {
|
|
1037
1043
|
const { cfg, account, runtime, mediaMaxBytes, processMessage } = context;
|
|
1038
1044
|
const message = event.message;
|
|
1039
|
-
const decision = await
|
|
1045
|
+
const decision = await resolveLineEventAdmission(event, context);
|
|
1040
1046
|
if (!decision) return;
|
|
1041
1047
|
const { isGroup, groupId, roomId } = getLineSourceInfo(event.source);
|
|
1042
1048
|
if (isGroup && decision.access.activationAccess.shouldSkip) {
|
|
1043
|
-
const rawText = message.type === "text" ? message
|
|
1049
|
+
const rawText = message.type === "text" ? readLineTextMessageBody(message) : "";
|
|
1044
1050
|
const sourceInfo = getLineSourceInfo(event.source);
|
|
1045
1051
|
logVerbose(`line: skipping group message (requireMention, not mentioned)`);
|
|
1046
1052
|
const historyKey = groupId ?? roomId;
|
|
@@ -1132,12 +1138,7 @@ async function handleJoinEvent(event, context) {
|
|
|
1132
1138
|
if (!isGroup || !conversationId) return;
|
|
1133
1139
|
logVerbose(`line: bot joined ${groupId ? `group ${groupId}` : `room ${roomId}`}`);
|
|
1134
1140
|
const { cfg, account } = context;
|
|
1135
|
-
const
|
|
1136
|
-
config: account.config,
|
|
1137
|
-
groupId,
|
|
1138
|
-
roomId
|
|
1139
|
-
});
|
|
1140
|
-
const roomAllowed = resolveLineRuntimeGroupPolicy(context).groupPolicy !== "disabled" && groupConfig?.enabled !== false;
|
|
1141
|
+
const roomAllowed = Boolean(await resolveLineEventAdmission(event, context));
|
|
1141
1142
|
await reportChannelRoomJoin({
|
|
1142
1143
|
cfg,
|
|
1143
1144
|
channel: "line",
|
|
@@ -1175,7 +1176,7 @@ async function handleLeaveEvent(event, _context) {
|
|
|
1175
1176
|
async function handlePostbackEvent(event, context) {
|
|
1176
1177
|
const data = event.postback.data;
|
|
1177
1178
|
logVerbose(`line: received postback: ${data}`);
|
|
1178
|
-
const decision = await
|
|
1179
|
+
const decision = await resolveLineEventAdmission(event, context);
|
|
1179
1180
|
if (!decision) return;
|
|
1180
1181
|
const postbackContext = await buildLinePostbackContext({
|
|
1181
1182
|
event,
|
|
@@ -1381,12 +1382,12 @@ function createLineWebhookSpool(options) {
|
|
|
1381
1382
|
let stopTask;
|
|
1382
1383
|
return {
|
|
1383
1384
|
accept: async (body) => {
|
|
1384
|
-
const events = body.events ?? [];
|
|
1385
|
-
if (events.length === 0) return;
|
|
1386
|
-
await monitor.admitBatch(events.map((event) => ({
|
|
1385
|
+
const events = (body.events ?? []).filter((event) => event.mode !== "standby");
|
|
1386
|
+
if (events.length === 0) return "ignored";
|
|
1387
|
+
return (await monitor.admitBatch(events.map((event) => ({
|
|
1387
1388
|
event,
|
|
1388
1389
|
destination: body.destination ?? ""
|
|
1389
|
-
})), { receivedAt: Date.now() });
|
|
1390
|
+
})), { receivedAt: Date.now() })).some((admission) => admission.kind === "durable") ? "durable" : "ignored";
|
|
1390
1391
|
},
|
|
1391
1392
|
start: () => {
|
|
1392
1393
|
if (!stopTask) monitor.start();
|
|
@@ -1473,7 +1474,8 @@ function resolveLineDurableReplyOptions(params) {
|
|
|
1473
1474
|
//#endregion
|
|
1474
1475
|
//#region extensions/line/src/signature.ts
|
|
1475
1476
|
function validateLineSignature(body, signature, channelSecret) {
|
|
1476
|
-
|
|
1477
|
+
const hash = crypto.createHmac("SHA256", channelSecret).update(body).digest("base64");
|
|
1478
|
+
return safeEqualSecret(signature, hash);
|
|
1477
1479
|
}
|
|
1478
1480
|
//#endregion
|
|
1479
1481
|
//#region extensions/line/src/webhook-utils.ts
|
|
@@ -1486,8 +1488,8 @@ function parseLineWebhookBody(rawBody) {
|
|
|
1486
1488
|
}
|
|
1487
1489
|
//#endregion
|
|
1488
1490
|
//#region extensions/line/src/webhook-node.ts
|
|
1489
|
-
const LINE_WEBHOOK_MAX_BODY_BYTES =
|
|
1490
|
-
const LINE_WEBHOOK_PREAUTH_MAX_BODY_BYTES$1 =
|
|
1491
|
+
const LINE_WEBHOOK_MAX_BODY_BYTES = 1048576;
|
|
1492
|
+
const LINE_WEBHOOK_PREAUTH_MAX_BODY_BYTES$1 = 65536;
|
|
1491
1493
|
const LINE_WEBHOOK_PREAUTH_BODY_TIMEOUT_MS$1 = 5e3;
|
|
1492
1494
|
async function readLineWebhookRequestBody(req, maxBytes = LINE_WEBHOOK_MAX_BODY_BYTES, timeoutMs = LINE_WEBHOOK_PREAUTH_BODY_TIMEOUT_MS$1) {
|
|
1493
1495
|
return await readRequestBodyWithLimit(req, {
|
|
@@ -1575,7 +1577,7 @@ function createLineNodeWebhookHandler(params) {
|
|
|
1575
1577
|
//#endregion
|
|
1576
1578
|
//#region extensions/line/src/monitor.ts
|
|
1577
1579
|
const lineWebhookInFlightLimiter = createWebhookInFlightLimiter();
|
|
1578
|
-
const LINE_WEBHOOK_PREAUTH_MAX_BODY_BYTES =
|
|
1580
|
+
const LINE_WEBHOOK_PREAUTH_MAX_BODY_BYTES = 65536;
|
|
1579
1581
|
const LINE_WEBHOOK_PREAUTH_BODY_TIMEOUT_MS = 5e3;
|
|
1580
1582
|
async function registerLineWebhookTarget(params, bot) {
|
|
1581
1583
|
try {
|
|
@@ -1669,6 +1671,7 @@ async function monitorLineProvider(opts) {
|
|
|
1669
1671
|
ctxPayload,
|
|
1670
1672
|
record: ctx.turn.record,
|
|
1671
1673
|
replyPipeline: {},
|
|
1674
|
+
dispatcherOptions: { humanDelay: resolveHumanDelayConfig(turnConfig, route.agentId) },
|
|
1672
1675
|
...replyOptions ? { replyOptions } : {},
|
|
1673
1676
|
delivery: {
|
|
1674
1677
|
preparePayload: prepareLineReplyPayload,
|
|
@@ -1719,7 +1722,8 @@ async function monitorLineProvider(opts) {
|
|
|
1719
1722
|
})
|
|
1720
1723
|
}
|
|
1721
1724
|
});
|
|
1722
|
-
|
|
1725
|
+
const dispatchResult = turnResult.dispatched ? turnResult.dispatchResult : void 0;
|
|
1726
|
+
if (!hasFinalInboundReplyDispatch(dispatchResult)) logVerbose(`line: no response generated for message from ${ctxPayload.From}`);
|
|
1723
1727
|
} catch (err) {
|
|
1724
1728
|
runtime.error?.(danger(`line: auto-reply failed: ${String(err)}`));
|
|
1725
1729
|
if (turnAdopted || replyTokenUsed) throw new LineWebhookTerminalDeliveryError("LINE delivery failed after consuming the event reply token.", { cause: err });
|
|
@@ -1806,8 +1810,7 @@ async function monitorLineProvider(opts) {
|
|
|
1806
1810
|
}
|
|
1807
1811
|
if (body.events && body.events.length > 0) {
|
|
1808
1812
|
logVerbose(`line: received ${body.events.length} webhook events`);
|
|
1809
|
-
await match.target.bot.handleWebhook(body);
|
|
1810
|
-
res.setHeader("x-openclaw-delivery-accepted", "durable");
|
|
1813
|
+
if (await match.target.bot.handleWebhook(body) === "durable") res.setHeader("x-openclaw-delivery-accepted", "durable");
|
|
1811
1814
|
}
|
|
1812
1815
|
res.statusCode = 200;
|
|
1813
1816
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line
|
|
2
|
-
import { c as pushFlexMessage, d as pushMessageLine, f as pushMessagesLine, g as sendMessageLine, m as pushTextMessageWithQuickReplies, n as createLocationMessage, p as pushTemplateMessage, r as createQuickReplyItems, t as createFlexMessage, u as pushLocationMessage } from "./send-
|
|
1
|
+
import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line--jytmFan.js";
|
|
2
|
+
import { c as pushFlexMessage, d as pushMessageLine, f as pushMessagesLine, g as sendMessageLine, m as pushTextMessageWithQuickReplies, n as createLocationMessage, p as pushTemplateMessage, r as createQuickReplyItems, t as createFlexMessage, u as pushLocationMessage } from "./send-wVUV00WS.js";
|
|
3
3
|
export { buildTemplateMessageFromPayload, createFlexMessage, createLocationMessage, createQuickReplyItems, processLineMessage, pushFlexMessage, pushLocationMessage, pushMessageLine, pushMessagesLine, pushTemplateMessage, pushTextMessageWithQuickReplies, sendMessageLine };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as resolveLineAccount } from "./accounts-
|
|
1
|
+
import { i as resolveLineAccount } from "./accounts-BBEFMYbY.js";
|
|
2
2
|
import { t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
|
|
3
3
|
import { _ as truncateLineActionLabel, a as createAgendaCard, c as createActionCard, g as postbackAction, o as createEventCard, p as messageAction } from "./send-retry-CUvrarfE.js";
|
|
4
4
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
@@ -41,7 +41,8 @@ const LineGroupConfigSchema = buildGroupEntrySchema().omit({
|
|
|
41
41
|
tools: true,
|
|
42
42
|
toolsBySender: true
|
|
43
43
|
});
|
|
44
|
-
const
|
|
44
|
+
const LineAccountConfigSchema = LineCommonConfigSchemaBase.extend({ groups: z.record(z.string(), LineGroupConfigSchema.optional()).optional() }).strict();
|
|
45
|
+
const LineConfigSchema = buildMultiAccountChannelSchema(LineAccountConfigSchema, {
|
|
45
46
|
optionalAccount: true,
|
|
46
47
|
refine: (value, ctx) => {
|
|
47
48
|
requireChannelOpenAllowFrom({
|
|
@@ -80,15 +81,15 @@ function resolveLineGroupLookupIds(groupId) {
|
|
|
80
81
|
}
|
|
81
82
|
function resolveLineGroupConfigEntry(groups, params) {
|
|
82
83
|
if (!groups) return;
|
|
83
|
-
|
|
84
|
+
const defaults = groups["*"];
|
|
85
|
+
for (const candidate of [...resolveLineGroupLookupIds(params.groupId), ...resolveLineGroupLookupIds(params.roomId)]) {
|
|
84
86
|
const hit = groups[candidate];
|
|
85
|
-
if (hit) return hit
|
|
87
|
+
if (hit) return defaults && defaults !== hit ? {
|
|
88
|
+
...defaults,
|
|
89
|
+
...hit
|
|
90
|
+
} : hit;
|
|
86
91
|
}
|
|
87
|
-
|
|
88
|
-
const hit = groups[candidate];
|
|
89
|
-
if (hit) return hit;
|
|
90
|
-
}
|
|
91
|
-
return groups["*"];
|
|
92
|
+
return defaults;
|
|
92
93
|
}
|
|
93
94
|
function resolveLineGroupsConfig(cfg, accountId) {
|
|
94
95
|
const lineConfig = cfg.channels?.line;
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-
|
|
2
|
-
import { _ as LineChannelConfigSchema, c as createDeviceControlCard, d as resolveExactLineGroupConfigKey, f as resolveLineGroupConfigEntry, g as setLineRuntime, l as createMediaPlayerCard, m as resolveLineGroupsConfig, p as resolveLineGroupLookupIds, s as createAppleTvRemoteCard, v as LineConfigSchema } from "./rich-messages-
|
|
1
|
+
import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.js";
|
|
2
|
+
import { _ as LineChannelConfigSchema, c as createDeviceControlCard, d as resolveExactLineGroupConfigKey, f as resolveLineGroupConfigEntry, g as setLineRuntime, l as createMediaPlayerCard, m as resolveLineGroupsConfig, p as resolveLineGroupLookupIds, s as createAppleTvRemoteCard, v as LineConfigSchema } from "./rich-messages-CIP7xn5E.js";
|
|
3
3
|
import { S as createVideoMessage, a as createAgendaCard, b as createAudioMessage, c as createActionCard, d as createListCard, f as datetimePickerAction, g as postbackAction, l as createImageCard, o as createEventCard, p as messageAction, s as createReceiptCard, u as createInfoCard, v as uriAction, x as createImageMessage } from "./send-retry-CUvrarfE.js";
|
|
4
|
-
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-
|
|
4
|
+
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-CSpwQCBI.js";
|
|
5
5
|
import { t as probeLineBot } from "./probe-4gc_YQ2L.js";
|
|
6
|
-
import { a as stripMarkdown, c as createButtonTemplate, d as createTemplateCarousel, i as processLineMessage, l as createCarouselColumn, n as convertTableToFlexBubble, o as toFlexMessage, r as hasMarkdownToConvert, s as buildTemplateMessageFromPayload, t as convertCodeBlockToFlexBubble, u as createConfirmTemplate } from "./markdown-to-line
|
|
7
|
-
import { _ as showLoadingAnimation, c as pushFlexMessage, d as pushMessageLine, f as pushMessagesLine, g as sendMessageLine, h as replyMessageLine, i as createTextMessageWithQuickReplies, l as pushImageMessage, m as pushTextMessageWithQuickReplies, n as createLocationMessage, o as getUserDisplayName, p as pushTemplateMessage, r as createQuickReplyItems, s as getUserProfile, t as createFlexMessage, u as pushLocationMessage, y as resolveLineChannelAccessToken } from "./send-
|
|
6
|
+
import { a as stripMarkdown, c as createButtonTemplate, d as createTemplateCarousel, i as processLineMessage, l as createCarouselColumn, n as convertTableToFlexBubble, o as toFlexMessage, r as hasMarkdownToConvert, s as buildTemplateMessageFromPayload, t as convertCodeBlockToFlexBubble, u as createConfirmTemplate } from "./markdown-to-line--jytmFan.js";
|
|
7
|
+
import { _ as showLoadingAnimation, c as pushFlexMessage, d as pushMessageLine, f as pushMessagesLine, g as sendMessageLine, h as replyMessageLine, i as createTextMessageWithQuickReplies, l as pushImageMessage, m as pushTextMessageWithQuickReplies, n as createLocationMessage, o as getUserDisplayName, p as pushTemplateMessage, r as createQuickReplyItems, s as getUserProfile, t as createFlexMessage, u as pushLocationMessage, y as resolveLineChannelAccessToken } from "./send-wVUV00WS.js";
|
|
8
8
|
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
9
9
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
10
10
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
@@ -16,7 +16,7 @@ import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
|
16
16
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
|
|
17
17
|
import { loadWebMediaRaw } from "openclaw/plugin-sdk/web-media";
|
|
18
18
|
//#region extensions/line/src/webhook.ts
|
|
19
|
-
const LINE_WEBHOOK_MAX_RAW_BODY_BYTES =
|
|
19
|
+
const LINE_WEBHOOK_MAX_RAW_BODY_BYTES = 65536;
|
|
20
20
|
function readRawBody(req) {
|
|
21
21
|
const rawBody = req.rawBody ?? (typeof req.body === "string" || Buffer.isBuffer(req.body) ? req.body : null);
|
|
22
22
|
if (!rawBody) return null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as resolveLineAccount } from "./accounts-
|
|
1
|
+
import { i as resolveLineAccount } from "./accounts-BBEFMYbY.js";
|
|
2
2
|
import { h as normalizeLineMessageActions, i as createLineSendReceipt, p as messageAction, r as runLinePushWithRetries, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.js";
|
|
3
3
|
import { createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
4
4
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
@@ -50,11 +50,11 @@ const groupNameCache = {
|
|
|
50
50
|
values: /* @__PURE__ */ new Map(),
|
|
51
51
|
pending: /* @__PURE__ */ new Map()
|
|
52
52
|
};
|
|
53
|
-
const PROFILE_CACHE_TTL_MS =
|
|
53
|
+
const PROFILE_CACHE_TTL_MS = 3e5;
|
|
54
54
|
const PROFILE_CACHE_MAX_ENTRIES = 1e3;
|
|
55
55
|
const LINE_FLEX_ALT_TEXT_LIMIT = 1500;
|
|
56
56
|
const LINE_LOCATION_LABEL_LIMIT = 100;
|
|
57
|
-
const LINE_PROVIDER_RESPONSE_MAX_BYTES =
|
|
57
|
+
const LINE_PROVIDER_RESPONSE_MAX_BYTES = 16384;
|
|
58
58
|
function rememberLineIdentity(cache, key, value) {
|
|
59
59
|
const entry = {
|
|
60
60
|
value,
|
|
@@ -109,8 +109,9 @@ function normalizeTarget(to) {
|
|
|
109
109
|
return normalized;
|
|
110
110
|
}
|
|
111
111
|
function resolveLineMessagingAccount(opts) {
|
|
112
|
+
const cfg = requireRuntimeConfig(opts.cfg, "LINE send");
|
|
112
113
|
const account = resolveLineAccount({
|
|
113
|
-
cfg
|
|
114
|
+
cfg,
|
|
114
115
|
accountId: opts.accountId
|
|
115
116
|
});
|
|
116
117
|
return {
|
|
@@ -191,7 +192,10 @@ function createLocationMessage(location) {
|
|
|
191
192
|
function logLineHttpError(err, context) {
|
|
192
193
|
if (!err || typeof err !== "object") return;
|
|
193
194
|
const { status, statusText, body } = err;
|
|
194
|
-
if (typeof body === "string")
|
|
195
|
+
if (typeof body === "string") {
|
|
196
|
+
const summary = status ? `${status} ${statusText ?? ""}`.trim() : "unknown status";
|
|
197
|
+
logVerbose(`line: ${context} failed (${summary}): ${body}`);
|
|
198
|
+
}
|
|
195
199
|
}
|
|
196
200
|
function recordLineOutboundActivity(accountId, delivery) {
|
|
197
201
|
recordLineSentMessages(accountId, delivery.messageIds);
|
|
@@ -248,7 +252,10 @@ async function pushLineMessages(to, messages, opts, behavior = {}) {
|
|
|
248
252
|
messageIds,
|
|
249
253
|
receipt: result.receipt
|
|
250
254
|
});
|
|
251
|
-
if (opts.verbose)
|
|
255
|
+
if (opts.verbose) {
|
|
256
|
+
const logMessage = behavior.verboseMessage?.(chatId, messages.length) ?? `line: pushed ${messages.length} messages to ${chatId}`;
|
|
257
|
+
logVerbose(logMessage);
|
|
258
|
+
}
|
|
252
259
|
return result;
|
|
253
260
|
}
|
|
254
261
|
async function replyLineMessages(replyToken, messages, opts) {
|
package/dist/setup-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as lineSetupAdapter, t as lineSetupWizard } from "./setup-surface-
|
|
1
|
+
import { n as lineSetupAdapter, t as lineSetupWizard } from "./setup-surface-CDlgkTKi.js";
|
|
2
2
|
export { lineSetupAdapter, lineSetupWizard };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-
|
|
1
|
+
import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.js";
|
|
2
2
|
import { n as parseLineAllowFromId, t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
|
|
3
3
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
@@ -159,6 +159,27 @@ const LINE_ALLOW_FROM_HELP_LINES = [
|
|
|
159
159
|
t("wizard.line.multipleEntries"),
|
|
160
160
|
t("wizard.channels.docs", { link: formatDocsLink("/channels/line", "channels/line") })
|
|
161
161
|
];
|
|
162
|
+
const promptLineAllowFrom = createPromptParsedAllowFromForAccount({
|
|
163
|
+
defaultAccountId: resolveDefaultLineAccountId,
|
|
164
|
+
noteTitle: t("wizard.line.allowlistTitle"),
|
|
165
|
+
noteLines: LINE_ALLOW_FROM_HELP_LINES,
|
|
166
|
+
message: t("wizard.line.allowFromPrompt"),
|
|
167
|
+
placeholder: "U1234567890abcdef1234567890abcdef",
|
|
168
|
+
parseEntries: (raw) => parseSetupEntriesWithParser(raw, (entry) => {
|
|
169
|
+
const id = parseLineAllowFromId(entry);
|
|
170
|
+
return id ? { value: id } : { error: t("wizard.line.allowFromInvalid") };
|
|
171
|
+
}),
|
|
172
|
+
getExistingAllowFrom: ({ cfg, accountId }) => resolveLineAccount({
|
|
173
|
+
cfg,
|
|
174
|
+
accountId
|
|
175
|
+
}).config.allowFrom ?? [],
|
|
176
|
+
applyAllowFrom: ({ cfg, accountId, allowFrom }) => patchLineAccountConfig({
|
|
177
|
+
cfg,
|
|
178
|
+
accountId,
|
|
179
|
+
enabled: true,
|
|
180
|
+
patch: { allowFrom }
|
|
181
|
+
})
|
|
182
|
+
});
|
|
162
183
|
const lineDmPolicy = createChannelDmPolicy({
|
|
163
184
|
label: "LINE",
|
|
164
185
|
channel,
|
|
@@ -173,27 +194,7 @@ const lineDmPolicy = createChannelDmPolicy({
|
|
|
173
194
|
patch,
|
|
174
195
|
clearFields: patch.dmPolicy === "pairing" || patch.dmPolicy === "disabled" ? ["allowFrom"] : void 0
|
|
175
196
|
}),
|
|
176
|
-
promptAllowFrom:
|
|
177
|
-
defaultAccountId: resolveDefaultLineAccountId,
|
|
178
|
-
noteTitle: t("wizard.line.allowlistTitle"),
|
|
179
|
-
noteLines: LINE_ALLOW_FROM_HELP_LINES,
|
|
180
|
-
message: t("wizard.line.allowFromPrompt"),
|
|
181
|
-
placeholder: "U1234567890abcdef1234567890abcdef",
|
|
182
|
-
parseEntries: (raw) => parseSetupEntriesWithParser(raw, (entry) => {
|
|
183
|
-
const id = parseLineAllowFromId(entry);
|
|
184
|
-
return id ? { value: id } : { error: t("wizard.line.allowFromInvalid") };
|
|
185
|
-
}),
|
|
186
|
-
getExistingAllowFrom: ({ cfg, accountId }) => resolveLineAccount({
|
|
187
|
-
cfg,
|
|
188
|
-
accountId
|
|
189
|
-
}).config.allowFrom ?? [],
|
|
190
|
-
applyAllowFrom: ({ cfg, accountId, allowFrom }) => patchLineAccountConfig({
|
|
191
|
-
cfg,
|
|
192
|
-
accountId,
|
|
193
|
-
enabled: true,
|
|
194
|
-
patch: { allowFrom }
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
+
promptAllowFrom: promptLineAllowFrom
|
|
197
198
|
});
|
|
198
199
|
function createLineTokenCredential(params) {
|
|
199
200
|
return defineTokenCredential({
|
|
@@ -20,7 +20,8 @@ var LineWebhookPayloadError = class extends Error {
|
|
|
20
20
|
function eventIdFor(event) {
|
|
21
21
|
if (!isRecord(event)) throw new LineWebhookPayloadError("LINE webhook event must be an object.");
|
|
22
22
|
if (event.type === "message") {
|
|
23
|
-
const
|
|
23
|
+
const message = isRecord(event.message) ? event.message : void 0;
|
|
24
|
+
const messageId = normalizeNullableString(message?.id);
|
|
24
25
|
if (messageId) return `message:${messageId}`;
|
|
25
26
|
}
|
|
26
27
|
const webhookEventId = normalizeNullableString(event.webhookEventId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]
|
|
1
|
+
const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\[\x20-\x7e])*")@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*|\[(?:IPv6:[a-f0-9:]+|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})\])$/i;
|
|
2
2
|
/**
|
|
3
3
|
* Returns true if the value is an Email
|
|
4
4
|
* @specification https://datatracker.ietf.org/doc/html/rfc5322
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as FormatBidi from './format/bidi.mjs';
|
|
2
2
|
import * as LabelUnicode from './label/unicode.mjs';
|
|
3
3
|
import * as LabelPuny from './label/puny.mjs';
|
|
4
|
+
// ------------------------------------------------------------------
|
|
5
|
+
// IsLabel
|
|
6
|
+
// ------------------------------------------------------------------
|
|
4
7
|
function IsValidLabelLength(value) {
|
|
5
8
|
return value.length > 0 && value.length <= 63;
|
|
6
9
|
}
|
|
@@ -8,9 +11,24 @@ function IsLabel(value) {
|
|
|
8
11
|
return IsValidLabelLength(value) && (LabelPuny.IsPunyLabel(value) ||
|
|
9
12
|
LabelUnicode.IsUnicodeLabel(value));
|
|
10
13
|
}
|
|
14
|
+
// ------------------------------------------------------------------
|
|
15
|
+
// NormalizeHostname
|
|
16
|
+
//
|
|
17
|
+
// Normalizes a hostname for label validation. Normalizes for NFC
|
|
18
|
+
// such that equivalent codepoint sequences can be uniformly
|
|
19
|
+
// compared. It also removes codepoints that IDNA mapping ignores,
|
|
20
|
+
// and converts full stop variants to ASCII '.' so the hostname can
|
|
21
|
+
// be split into labels.
|
|
22
|
+
// ------------------------------------------------------------------
|
|
11
23
|
function NormalizeHostname(value) {
|
|
12
|
-
return value
|
|
24
|
+
return value
|
|
25
|
+
.normalize('NFC')
|
|
26
|
+
.replace(/[\u00ad\u034f\u180b-\u180d\u200b\ufe00-\ufe0f\u{e0100}-\u{e01ef}]/gu, '') // RE_IGNORED_MAPPING
|
|
27
|
+
.replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.'); // RE_FULL_STOP_MAPPING
|
|
13
28
|
}
|
|
29
|
+
// ------------------------------------------------------------------
|
|
30
|
+
// IsIdnHostname
|
|
31
|
+
// ------------------------------------------------------------------
|
|
14
32
|
export function IsIdnHostname(value) {
|
|
15
33
|
if (value.length === 0 || value.includes(' '))
|
|
16
34
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/line",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.2",
|
|
4
4
|
"description": "OpenClaw LINE channel plugin for LINE Bot API chats.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"type": "module",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@line/bot-sdk": "11.2.0",
|
|
12
|
-
"typebox": "1.3.
|
|
12
|
+
"typebox": "1.3.17",
|
|
13
13
|
"zod": "4.4.3"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.8.
|
|
16
|
+
"openclaw": ">=2026.8.2"
|
|
17
17
|
},
|
|
18
18
|
"peerDependenciesMeta": {
|
|
19
19
|
"openclaw": {
|
|
@@ -112,10 +112,10 @@
|
|
|
112
112
|
"minHostVersion": ">=2026.4.10"
|
|
113
113
|
},
|
|
114
114
|
"compat": {
|
|
115
|
-
"pluginApi": ">=2026.8.
|
|
115
|
+
"pluginApi": ">=2026.8.2"
|
|
116
116
|
},
|
|
117
117
|
"build": {
|
|
118
|
-
"openclawVersion": "2026.8.
|
|
118
|
+
"openclawVersion": "2026.8.2"
|
|
119
119
|
},
|
|
120
120
|
"release": {
|
|
121
121
|
"publishToClawHub": true,
|