@openclaw/line 2026.8.1 → 2026.8.33

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.
Files changed (33) hide show
  1. package/dist/{accounts-BqEVsDoB.js → .setup/accounts-BBEFMYbY.mjs} +2 -1
  2. package/dist/.setup/api-BSkzlbXG.mjs +3 -0
  3. package/dist/.setup/api-sY4YpHPY.mjs +11 -0
  4. package/dist/{card-command-BywtX77U.js → .setup/card-command-D8Tk5ZVZ.mjs} +103 -112
  5. package/dist/{channel-DpMgRaxl.js → .setup/channel-B4UViAY8.mjs} +55 -18
  6. package/dist/.setup/channel.runtime-B3mRBEeG.mjs +4 -0
  7. package/dist/{markdown-to-line-CG9Jy22s.js → .setup/markdown-to-line-4woxCGve.mjs} +8 -5
  8. package/dist/{monitor-Ch6TIatG.js → .setup/monitor-Cr0TljbL.mjs} +55 -52
  9. package/dist/.setup/monitor.runtime-L3ye-95N.mjs +2 -0
  10. package/dist/{outbound.runtime-CyleVzFR.js → .setup/outbound.runtime-M1AFzG-x.mjs} +2 -2
  11. package/dist/.setup/probe.runtime-B-gCwsDV.mjs +2 -0
  12. package/dist/{rich-messages-t_zRL24p.js → .setup/rich-messages-DyRwBXzw.mjs} +12 -11
  13. package/dist/{send-B-K2B6au.js → .setup/send-BzPbMOdN.mjs} +14 -7
  14. package/dist/{setup-surface-DSJ92oJ5.js → .setup/setup-surface-BYhOmp4v.mjs} +24 -23
  15. package/dist/{webhook-spool-contract-CNe2h1I2.js → .setup/webhook-spool-contract-1rY8OJw8.mjs} +2 -1
  16. package/dist/api.js +2 -10
  17. package/dist/channel-plugin-api.js +1 -1
  18. package/dist/contract-api.js +1 -1
  19. package/dist/doctor-contract-api.js +1 -1
  20. package/dist/index.js +5 -17
  21. package/dist/runtime-api.js +8 -8
  22. package/dist/setup-api.js +1 -1
  23. package/dist/setup-entry.js +2 -1
  24. package/node_modules/typebox/build/format/email.mjs +1 -1
  25. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  26. package/node_modules/typebox/package.json +1 -1
  27. package/package.json +5 -5
  28. package/dist/channel.runtime-Bty5U_1N.js +0 -4
  29. package/dist/monitor.runtime-Czc3NxNV.js +0 -2
  30. package/dist/probe.runtime-DTxBWvKz.js +0 -2
  31. /package/dist/{account-helpers-BSUyZwLm.js → .setup/account-helpers-BSUyZwLm.mjs} +0 -0
  32. /package/dist/{probe-4gc_YQ2L.js → .setup/probe-4gc_YQ2L.mjs} +0 -0
  33. /package/dist/{send-retry-CUvrarfE.js → .setup/send-retry-CUvrarfE.mjs} +0 -0
@@ -16,7 +16,8 @@ function resolveLineCredential(params) {
16
16
  };
17
17
  const file = config?.[fileKey];
18
18
  if (file?.trim()) {
19
- const result = tryReadSecretFileSync(file, "LINE credential file", { rejectSymlink: true }, { configPath: `channels.line.${index === 0 ? `accounts.${accountId}.` : ""}${fileKey}` });
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",
@@ -0,0 +1,3 @@
1
+ import { t as linePlugin } from "./channel-B4UViAY8.mjs";
2
+ import { t as lineSetupPlugin } from "./api-sY4YpHPY.mjs";
3
+ export { linePlugin, lineSetupPlugin };
@@ -0,0 +1,11 @@
1
+ import { n as lineChannelPluginCommon } from "./channel-B4UViAY8.mjs";
2
+ import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-BYhOmp4v.mjs";
3
+ //#region extensions/line/src/channel.setup.ts
4
+ const lineSetupPlugin = {
5
+ id: "line",
6
+ ...lineChannelPluginCommon,
7
+ setupWizard: lineSetupWizard,
8
+ setupContract: lineSetupContract
9
+ };
10
+ //#endregion
11
+ export { lineSetupPlugin as t };
@@ -1,5 +1,5 @@
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-B-K2B6au.js";
1
+ import { c as createActionCard, d as createListCard, l as createImageCard, s as createReceiptCard, u as createInfoCard } from "./send-retry-CUvrarfE.mjs";
2
+ import { t as createFlexMessage } from "./send-BzPbMOdN.mjs";
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 registerLineCardCommand(api) {
149
- api.registerCommand({
150
- name: "card",
151
- description: "Send a rich card message (LINE).",
152
- acceptsArgs: true,
153
- requireAuth: false,
154
- handler: async (ctx) => {
155
- const argsStr = ctx.args?.trim() ?? "";
156
- if (!argsStr) return { text: CARD_USAGE };
157
- const { type, args, flags } = parseCardArgs(argsStr);
158
- if (!type) return { text: CARD_USAGE };
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 { registerLineCardCommand };
252
+ export { handleLineCardCommand };
@@ -1,14 +1,14 @@
1
- import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BqEVsDoB.js";
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-t_zRL24p.js";
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-DSJ92oJ5.js";
1
+ import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.mjs";
2
+ import { t as hasLineCredentials } from "./account-helpers-BSUyZwLm.mjs";
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-DyRwBXzw.mjs";
4
+ import { i as createLineSendReceipt, n as resolveLineNonDispatchRetryable, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.mjs";
5
+ import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-BYhOmp4v.mjs";
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 { createEmptyChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
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";
@@ -119,8 +119,8 @@ const lineChannelPluginCommon = {
119
119
  };
120
120
  //#endregion
121
121
  //#region extensions/line/src/gateway.ts
122
- const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-DTxBWvKz.js"));
123
- const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-Czc3NxNV.js"));
122
+ const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-B-gCwsDV.mjs"));
123
+ const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-L3ye-95N.mjs"));
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-CyleVzFR.js"));
214
+ const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-M1AFzG-x.mjs"));
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") if (isLast && quickReply) await sendMessageBatch([{
338
- ...message,
339
- quickReply
340
- }]);
341
- else await recordResult(sendFlex(to, message.altText, message.contents, sendOptions));
342
- else if (isLast && hasQuickReplies) await sendTextWithQuickReply(message.text);
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);
@@ -443,7 +444,7 @@ const lineMessageAdapter = defineChannelMessageAdapter({
443
444
  });
444
445
  //#endregion
445
446
  //#region extensions/line/src/status.ts
446
- const loadLineProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-DTxBWvKz.js"));
447
+ const loadLineProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-B-gCwsDV.mjs"));
447
448
  const collectLineStatusIssues = createDependentCredentialStatusIssueCollector({
448
449
  channel: "line",
449
450
  dependencySourceKey: "tokenSource",
@@ -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-Bty5U_1N.js"));
475
+ const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-B3mRBEeG.mjs"));
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: createEmptyChannelDirectoryAdapter(),
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,
@@ -0,0 +1,4 @@
1
+ import { t as monitorLineProvider } from "./monitor-Cr0TljbL.mjs";
2
+ import { t as probeLineBot } from "./probe-4gc_YQ2L.mjs";
3
+ import { _ as showLoadingAnimation, d as pushMessageLine } from "./send-BzPbMOdN.mjs";
4
+ export { monitorLineProvider, probeLineBot, pushMessageLine, showLoadingAnimation };
@@ -1,4 +1,4 @@
1
- import { g as postbackAction, m as normalizeLineAction, p as messageAction, s as createReceiptCard, v as uriAction } from "./send-retry-CUvrarfE.js";
1
+ import { g as postbackAction, m as normalizeLineAction, p as messageAction, s as createReceiptCard, v as uriAction } from "./send-retry-CUvrarfE.mjs";
2
2
  import { markdownToIRWithMeta, stripMarkdown, stripMarkdown as stripMarkdown$1 } from "openclaw/plugin-sdk/text-chunking";
3
3
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
4
4
  //#region extensions/line/src/template-messages.ts
@@ -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) if (stripMarkdown(ir.text.slice(span.start, span.end), { assistantTranscriptRoleHeaders: true }).startsWith(TRANSCRIPT_ROLE_PREFIX)) insertions.push({
217
- position: span.start,
218
- text: TRANSCRIPT_ROLE_PREFIX
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-BqEVsDoB.js";
2
- import { f as resolveLineGroupConfigEntry, h as getLineRuntime, i as prepareLineReplyPayload, n as createLineQuickReply, u as buildLineQuickReplyFallbackText } from "./rich-messages-t_zRL24p.js";
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-CNe2h1I2.js";
5
- import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line-CG9Jy22s.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-B-K2B6au.js";
1
+ import { i as resolveLineAccount, r as resolveDefaultLineAccountId } from "./accounts-BBEFMYbY.mjs";
2
+ import { f as resolveLineGroupConfigEntry, h as getLineRuntime, i as prepareLineReplyPayload, n as createLineQuickReply, u as buildLineQuickReplyFallbackText } from "./rich-messages-DyRwBXzw.mjs";
3
+ import { n as resolveLineNonDispatchRetryable, t as findLineHttpError, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.mjs";
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.mjs";
5
+ import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line-4woxCGve.mjs";
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-BzPbMOdN.mjs";
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 < CONTENT_READY_MAX_ATTEMPTS - 1) await setTimeout$1(contentBackoffDelayMs(attempt), void 0, { signal });
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 = 10 * 1024 * 1024, options) {
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.text;
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
- logVerbose(`${params.verboseLog.kind === "inbound" ? "line inbound" : "line postback"}: from=${ctxPayload.From} len=${body.length}${mediaInfo} preview="${preview}"`);
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 shouldProcessLineEvent(event, context) {
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 = resolveLineGroupConfig({
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 } = resolveLineRuntimeGroupPolicy(context);
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 === "postback" ? "postback" : "message" },
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.text;
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 shouldProcessLineEvent(event, context);
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.text : "";
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 groupConfig = resolveLineGroupConfig({
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 shouldProcessLineEvent(event, context);
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
- return safeEqualSecret(signature, crypto.createHmac("SHA256", channelSecret).update(body).digest("base64"));
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 = 1024 * 1024;
1490
- const LINE_WEBHOOK_PREAUTH_MAX_BODY_BYTES$1 = 64 * 1024;
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 = 64 * 1024;
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
- if (!hasFinalInboundReplyDispatch(turnResult.dispatched ? turnResult.dispatchResult : void 0)) logVerbose(`line: no response generated for message from ${ctxPayload.From}`);
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");
@@ -0,0 +1,2 @@
1
+ import { t as monitorLineProvider } from "./monitor-Cr0TljbL.mjs";
2
+ export { monitorLineProvider };
@@ -1,3 +1,3 @@
1
- import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line-CG9Jy22s.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-B-K2B6au.js";
1
+ import { i as processLineMessage, s as buildTemplateMessageFromPayload } from "./markdown-to-line-4woxCGve.mjs";
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-BzPbMOdN.mjs";
3
3
  export { buildTemplateMessageFromPayload, createFlexMessage, createLocationMessage, createQuickReplyItems, processLineMessage, pushFlexMessage, pushLocationMessage, pushMessageLine, pushMessagesLine, pushTemplateMessage, pushTextMessageWithQuickReplies, sendMessageLine };
@@ -0,0 +1,2 @@
1
+ import { t as probeLineBot } from "./probe-4gc_YQ2L.mjs";
2
+ export { probeLineBot };
@@ -1,6 +1,6 @@
1
- import { i as resolveLineAccount } from "./accounts-BqEVsDoB.js";
2
- import { t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
3
- import { _ as truncateLineActionLabel, a as createAgendaCard, c as createActionCard, g as postbackAction, o as createEventCard, p as messageAction } from "./send-retry-CUvrarfE.js";
1
+ import { i as resolveLineAccount } from "./accounts-BBEFMYbY.mjs";
2
+ import { t as hasLineCredentials } from "./account-helpers-BSUyZwLm.mjs";
3
+ import { _ as truncateLineActionLabel, a as createAgendaCard, c as createActionCard, g as postbackAction, o as createEventCard, p as messageAction } from "./send-retry-CUvrarfE.mjs";
4
4
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
5
5
  import { resolveAccountEntry } from "openclaw/plugin-sdk/account-resolution";
6
6
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -41,7 +41,8 @@ const LineGroupConfigSchema = buildGroupEntrySchema().omit({
41
41
  tools: true,
42
42
  toolsBySender: true
43
43
  });
44
- const LineConfigSchema = buildMultiAccountChannelSchema(LineCommonConfigSchemaBase.extend({ groups: z.record(z.string(), LineGroupConfigSchema.optional()).optional() }).strict(), {
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
- for (const candidate of resolveLineGroupLookupIds(params.groupId)) {
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
- for (const candidate of resolveLineGroupLookupIds(params.roomId)) {
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;
@@ -1,5 +1,5 @@
1
- import { i as resolveLineAccount } from "./accounts-BqEVsDoB.js";
2
- import { h as normalizeLineMessageActions, i as createLineSendReceipt, p as messageAction, r as runLinePushWithRetries, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.js";
1
+ import { i as resolveLineAccount } from "./accounts-BBEFMYbY.mjs";
2
+ import { h as normalizeLineMessageActions, i as createLineSendReceipt, p as messageAction, r as runLinePushWithRetries, y as buildLineMediaMessage } from "./send-retry-CUvrarfE.mjs";
3
3
  import { createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
4
4
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
5
5
  import { HTTPFetchError, messagingApi } from "@line/bot-sdk";
@@ -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 = 300 * 1e3;
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 = 16 * 1024;
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: requireRuntimeConfig(opts.cfg, "LINE send"),
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") logVerbose(`line: ${context} failed (${status ? `${status} ${statusText ?? ""}`.trim() : "unknown status"}): ${body}`);
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) logVerbose(behavior.verboseMessage?.(chatId, messages.length) ?? `line: pushed ${messages.length} messages to ${chatId}`);
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) {
@@ -1,5 +1,5 @@
1
- import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BqEVsDoB.js";
2
- import { n as parseLineAllowFromId, t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
1
+ import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.mjs";
2
+ import { n as parseLineAllowFromId, t as hasLineCredentials } from "./account-helpers-BSUyZwLm.mjs";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
5
5
  import { DEFAULT_ACCOUNT_ID, createAllowFromSection, createPromptParsedAllowFromForAccount, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, parseSetupEntriesWithParser, patchScopedAccountConfig, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/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: createPromptParsedAllowFromForAccount({
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 messageId = normalizeNullableString((isRecord(event.message) ? event.message : void 0)?.id);
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);
package/dist/api.js CHANGED
@@ -1,11 +1,3 @@
1
- import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-DpMgRaxl.js";
2
- import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-DSJ92oJ5.js";
3
- //#region extensions/line/src/channel.setup.ts
4
- const lineSetupPlugin = {
5
- id: "line",
6
- ...lineChannelPluginCommon,
7
- setupWizard: lineSetupWizard,
8
- setupContract: lineSetupContract
9
- };
10
- //#endregion
1
+ import { t as linePlugin } from "./.setup/channel-B4UViAY8.mjs";
2
+ import { t as lineSetupPlugin } from "./.setup/api-sY4YpHPY.mjs";
11
3
  export { linePlugin, lineSetupPlugin };
@@ -1,2 +1,2 @@
1
- import { t as linePlugin } from "./channel-DpMgRaxl.js";
1
+ import { t as linePlugin } from "./.setup/channel-B4UViAY8.mjs";
2
2
  export { linePlugin };
@@ -1,2 +1,2 @@
1
- import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BqEVsDoB.js";
1
+ import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./.setup/accounts-BBEFMYbY.mjs";
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-CNe2h1I2.js";
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 "./.setup/webhook-spool-contract-1rY8OJw8.mjs";
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
- function createLineCardCommandLoader(api) {
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("./.setup/card-command-D8Tk5ZVZ.mjs"));
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 (LINE).",
21
+ description: "Send a rich card message.",
22
+ channels: ["line"],
36
23
  acceptsArgs: true,
37
24
  requireAuth: false,
38
25
  async handler(ctx) {
39
- return await (await loadLineCardCommand()).handler(ctx);
26
+ const { handleLineCardCommand } = await loadLineCardCommand();
27
+ return await handleLineCardCommand(ctx.args);
40
28
  }
41
29
  });
42
30
  }
@@ -1,10 +1,10 @@
1
- import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BqEVsDoB.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-t_zRL24p.js";
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-Ch6TIatG.js";
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-CG9Jy22s.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-B-K2B6au.js";
1
+ import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./.setup/accounts-BBEFMYbY.mjs";
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 "./.setup/rich-messages-DyRwBXzw.mjs";
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 "./.setup/send-retry-CUvrarfE.mjs";
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 "./.setup/monitor-Cr0TljbL.mjs";
5
+ import { t as probeLineBot } from "./.setup/probe-4gc_YQ2L.mjs";
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 "./.setup/markdown-to-line-4woxCGve.mjs";
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 "./.setup/send-BzPbMOdN.mjs";
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 = 64 * 1024;
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;
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as lineSetupAdapter, t as lineSetupWizard } from "./setup-surface-DSJ92oJ5.js";
1
+ import { n as lineSetupAdapter, t as lineSetupWizard } from "./.setup/setup-surface-BYhOmp4v.mjs";
2
2
  export { lineSetupAdapter, lineSetupWizard };
@@ -1,9 +1,10 @@
1
1
  import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
+ import { fileURLToPath } from "node:url";
2
3
  //#region extensions/line/setup-entry.ts
3
4
  var setup_entry_default = defineBundledChannelSetupEntry({
4
5
  importMetaUrl: import.meta.url,
5
6
  plugin: {
6
- specifier: "./api.js",
7
+ specifier: fileURLToPath(new URL(".setup/api-BSkzlbXG.mjs", import.meta.url).href),
7
8
  exportName: "lineSetupPlugin"
8
9
  }
9
10
  });
@@ -1,4 +1,4 @@
1
- const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\.)*")@(?:[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;
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.normalize('NFC').replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.');
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;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.3.16",
4
+ "version": "1.3.17",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/line",
3
- "version": "2026.8.1",
3
+ "version": "2026.8.33",
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.16",
12
+ "typebox": "1.3.17",
13
13
  "zod": "4.4.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.8.1"
16
+ "openclaw": ">=2026.8.33"
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.1"
115
+ "pluginApi": ">=2026.8.33"
116
116
  },
117
117
  "build": {
118
- "openclawVersion": "2026.8.1"
118
+ "openclawVersion": "2026.8.33"
119
119
  },
120
120
  "release": {
121
121
  "publishToClawHub": true,
@@ -1,4 +0,0 @@
1
- import { t as monitorLineProvider } from "./monitor-Ch6TIatG.js";
2
- import { t as probeLineBot } from "./probe-4gc_YQ2L.js";
3
- import { d as pushMessageLine } from "./send-B-K2B6au.js";
4
- export { monitorLineProvider, probeLineBot, pushMessageLine };
@@ -1,2 +0,0 @@
1
- import { t as monitorLineProvider } from "./monitor-Ch6TIatG.js";
2
- export { monitorLineProvider };
@@ -1,2 +0,0 @@
1
- import { t as probeLineBot } from "./probe-4gc_YQ2L.js";
2
- export { probeLineBot };