@openclaw/line 2026.8.1-beta.3 → 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/account-helpers-BSUyZwLm.js +12 -0
- package/dist/{accounts-BqEVsDoB.js → accounts-BBEFMYbY.js} +2 -1
- package/dist/api.js +2 -2
- package/dist/card-command-DS6A5V6o.js +252 -0
- package/dist/{channel-DmoKZXmG.js → channel-CLCy4jAa.js} +97 -357
- 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 +141 -0
- package/dist/index.js +5 -17
- package/dist/{markdown-to-line-rEaras_0.js → markdown-to-line--jytmFan.js} +36 -29
- package/dist/{monitor-BYXS_B6r.js → monitor-CSpwQCBI.js} +292 -194
- package/dist/monitor.runtime-CV8EjkIT.js +2 -0
- package/dist/outbound.runtime-DLqcz_BQ.js +3 -0
- package/dist/probe.runtime-DTxBWvKz.js +2 -0
- package/dist/rich-messages-CIP7xn5E.js +761 -0
- package/dist/runtime-api.js +12 -13
- package/dist/{send-receipt-DKZzgHMO.js → send-retry-CUvrarfE.js} +137 -413
- package/dist/{send-BJCeiiOB.js → send-wVUV00WS.js} +150 -109
- package/dist/setup-api.js +1 -1
- package/dist/{setup-surface-W0Dbgu58.js → setup-surface-CDlgkTKi.js} +47 -39
- package/dist/webhook-spool-contract-1rY8OJw8.js +59 -0
- package/node_modules/typebox/build/format/date.d.mts +1 -1
- package/node_modules/typebox/build/format/date.mjs +1 -1
- package/node_modules/typebox/build/format/date_time.d.mts +2 -2
- package/node_modules/typebox/build/format/date_time.mjs +3 -3
- package/node_modules/typebox/build/format/email.d.mts +1 -1
- package/node_modules/typebox/build/format/email.mjs +2 -2
- package/node_modules/typebox/build/format/hostname.mjs +2 -10
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_email.mjs +3 -3
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
- package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
- package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
- package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +41 -0
- package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
- package/node_modules/typebox/build/format/idna/index.mjs +2 -0
- package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
- package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
- package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
- package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
- package/node_modules/typebox/build/format/ipv4.mjs +2 -32
- package/node_modules/typebox/build/format/ipv6.mjs +2 -61
- package/node_modules/typebox/build/format/iri.d.mts +2 -2
- package/node_modules/typebox/build/format/iri.mjs +26 -8
- package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
- package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
- package/node_modules/typebox/build/format/regex.d.mts +1 -2
- package/node_modules/typebox/build/format/regex.mjs +2 -6
- package/node_modules/typebox/build/format/time.d.mts +2 -2
- package/node_modules/typebox/build/format/time.mjs +19 -14
- package/node_modules/typebox/build/format/uri.d.mts +1 -1
- package/node_modules/typebox/build/format/uri.mjs +3 -130
- package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
- package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
- package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
- package/node_modules/typebox/build/format/uri_template.mjs +4 -5
- package/node_modules/typebox/build/format/url.d.mts +3 -3
- package/node_modules/typebox/build/format/url.mjs +4 -5
- package/node_modules/typebox/build/guard/emit.d.mts +3 -1
- package/node_modules/typebox/build/guard/emit.mjs +12 -5
- package/node_modules/typebox/build/guard/guard.d.mts +8 -2
- package/node_modules/typebox/build/guard/guard.mjs +25 -4
- package/node_modules/typebox/build/guard/string.d.mts +2 -2
- package/node_modules/typebox/build/guard/string.mjs +7 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
- package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
- package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
- package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
- package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
- package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
- package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
- package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
- package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
- package/node_modules/typebox/build/schema/types/index.mjs +0 -2
- package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
- package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
- package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
- package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
- package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
- package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
- package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
- package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
- package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
- package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
- package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
- package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
- package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
- package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
- package/node_modules/typebox/build/type/script/parser.mjs +27 -23
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
- package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
- package/node_modules/typebox/package.json +27 -27
- package/node_modules/typebox/readme.md +79 -82
- package/openclaw.plugin.json +26 -2
- package/package.json +6 -6
- package/dist/card-command-CyDSm-OU.js +0 -224
- package/dist/channel.runtime-qrUV6wPE.js +0 -4
- package/dist/config-schema-Be3azjB_.js +0 -47
- package/dist/monitor.runtime-B2z_5ugU.js +0 -2
- package/dist/outbound.runtime-DDTeqaBW.js +0 -3
- package/dist/probe.runtime-D13ZtXsd.js +0 -2
- package/dist/quick-reply-fallback-D86FwAfr.js +0 -56
- package/node_modules/typebox/build/format/_idna.d.mts +0 -2
- package/node_modules/typebox/build/format/_idna.mjs +0 -246
- package/node_modules/typebox/build/format/_puny.d.mts +0 -1
- package/node_modules/typebox/build/format/_puny.mjs +0 -77
- package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
- package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
- package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
- package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
- package/dist/{probe-CM03wo6r.js → probe-4gc_YQ2L.js} +1 -1
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { i as resolveLineAccount } from "./accounts-
|
|
2
|
-
import { h as normalizeLineMessageActions, p as messageAction,
|
|
1
|
+
import { i as resolveLineAccount } from "./accounts-BBEFMYbY.js";
|
|
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";
|
|
5
|
+
import { HTTPFetchError, messagingApi } from "@line/bot-sdk";
|
|
5
6
|
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
6
7
|
import { fetchWithRuntimeDispatcherOrMockedGlobal } from "openclaw/plugin-sdk/runtime-fetch";
|
|
7
|
-
import { HTTPFetchError, messagingApi } from "@line/bot-sdk";
|
|
8
|
-
import { collectErrorGraphCandidates, extractErrorCode } from "openclaw/plugin-sdk/error-runtime";
|
|
9
8
|
import { randomUUID } from "node:crypto";
|
|
10
9
|
import lineBotSdkPackage from "@line/bot-sdk/package.json" with { type: "json" };
|
|
11
10
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
12
11
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
13
12
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
14
|
-
import {
|
|
13
|
+
import { readProviderJsonResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
14
|
+
import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
|
|
15
15
|
//#region extensions/line/src/channel-access-token.ts
|
|
16
16
|
function resolveLineChannelAccessToken(explicit, params) {
|
|
17
17
|
if (explicit?.trim()) return explicit.trim();
|
|
@@ -19,35 +19,69 @@ function resolveLineChannelAccessToken(explicit, params) {
|
|
|
19
19
|
return params.channelAccessToken.trim();
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
|
-
//#region extensions/line/src/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
//#region extensions/line/src/outbound-message-log.ts
|
|
23
|
+
const RECENT_SENT_LIMIT = 500;
|
|
24
|
+
const recentSentByAccount = /* @__PURE__ */ new Map();
|
|
25
|
+
function recentSentFor(accountId) {
|
|
26
|
+
const existing = recentSentByAccount.get(accountId);
|
|
27
|
+
if (existing) return existing;
|
|
28
|
+
const created = createDedupeCache({
|
|
29
|
+
ttlMs: 0,
|
|
30
|
+
maxSize: RECENT_SENT_LIMIT
|
|
31
|
+
});
|
|
32
|
+
recentSentByAccount.set(accountId, created);
|
|
33
|
+
return created;
|
|
34
|
+
}
|
|
35
|
+
function recordLineSentMessages(accountId, messageIds) {
|
|
36
|
+
if (messageIds.length === 0) return;
|
|
37
|
+
const recentSent = recentSentFor(accountId);
|
|
38
|
+
for (const messageId of messageIds) recentSent.check(messageId);
|
|
39
|
+
}
|
|
40
|
+
function quotesLineBotMessage(accountId, quotedMessageId) {
|
|
41
|
+
return recentSentByAccount.get(accountId)?.peek(quotedMessageId) ?? false;
|
|
42
|
+
}
|
|
38
43
|
//#endregion
|
|
39
44
|
//#region extensions/line/src/send.ts
|
|
40
|
-
const
|
|
41
|
-
|
|
45
|
+
const profileCache = {
|
|
46
|
+
values: /* @__PURE__ */ new Map(),
|
|
47
|
+
pending: /* @__PURE__ */ new Map()
|
|
48
|
+
};
|
|
49
|
+
const groupNameCache = {
|
|
50
|
+
values: /* @__PURE__ */ new Map(),
|
|
51
|
+
pending: /* @__PURE__ */ new Map()
|
|
52
|
+
};
|
|
53
|
+
const PROFILE_CACHE_TTL_MS = 3e5;
|
|
42
54
|
const PROFILE_CACHE_MAX_ENTRIES = 1e3;
|
|
43
55
|
const LINE_FLEX_ALT_TEXT_LIMIT = 1500;
|
|
44
56
|
const LINE_LOCATION_LABEL_LIMIT = 100;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
const LINE_PROVIDER_RESPONSE_MAX_BYTES = 16384;
|
|
58
|
+
function rememberLineIdentity(cache, key, value) {
|
|
59
|
+
const entry = {
|
|
60
|
+
value,
|
|
61
|
+
fetchedAt: Date.now()
|
|
62
|
+
};
|
|
63
|
+
cache.values.delete(key);
|
|
64
|
+
cache.values.set(key, entry);
|
|
65
|
+
if (cache.values.size <= PROFILE_CACHE_MAX_ENTRIES) return;
|
|
66
|
+
for (const [cachedKey, cached] of cache.values) if (entry.fetchedAt - cached.fetchedAt >= PROFILE_CACHE_TTL_MS) cache.values.delete(cachedKey);
|
|
67
|
+
pruneMapToMaxSize(cache.values, PROFILE_CACHE_MAX_ENTRIES);
|
|
68
|
+
}
|
|
69
|
+
async function loadLineIdentity(cache, key, load) {
|
|
70
|
+
const cached = cache.values.get(key);
|
|
71
|
+
if (cached && Date.now() - cached.fetchedAt < PROFILE_CACHE_TTL_MS) return cached.value;
|
|
72
|
+
const pending = cache.pending.get(key);
|
|
73
|
+
if (pending) return await pending;
|
|
74
|
+
const lookup = load().then((value) => {
|
|
75
|
+
rememberLineIdentity(cache, key, value);
|
|
76
|
+
return value;
|
|
77
|
+
});
|
|
78
|
+
cache.pending.set(key, lookup);
|
|
79
|
+
pruneMapToMaxSize(cache.pending, PROFILE_CACHE_MAX_ENTRIES);
|
|
80
|
+
try {
|
|
81
|
+
return await lookup;
|
|
82
|
+
} finally {
|
|
83
|
+
if (cache.pending.get(key) === lookup) cache.pending.delete(key);
|
|
84
|
+
}
|
|
51
85
|
}
|
|
52
86
|
function resolveLineProviderMessageIds(response, operation) {
|
|
53
87
|
const sentMessages = Array.isArray(response?.sentMessages) ? response.sentMessages : [];
|
|
@@ -74,12 +108,10 @@ function normalizeTarget(to) {
|
|
|
74
108
|
if (normalized.length >= 33 && !/^[CUR]/.test(normalized)) throw new Error(`Recipient is not a valid LINE id (case-sensitive; expected leading capital C/U/R): ${truncateUtf16Safe(normalized, 4)}…`);
|
|
75
109
|
return normalized;
|
|
76
110
|
}
|
|
77
|
-
function isLineUserChatId(chatId) {
|
|
78
|
-
return /^U/i.test(chatId);
|
|
79
|
-
}
|
|
80
111
|
function resolveLineMessagingAccount(opts) {
|
|
112
|
+
const cfg = requireRuntimeConfig(opts.cfg, "LINE send");
|
|
81
113
|
const account = resolveLineAccount({
|
|
82
|
-
cfg
|
|
114
|
+
cfg,
|
|
83
115
|
accountId: opts.accountId
|
|
84
116
|
});
|
|
85
117
|
return {
|
|
@@ -114,15 +146,17 @@ async function sendLineProviderMessages(operation, token, request, retryKey) {
|
|
|
114
146
|
body: JSON.stringify(request)
|
|
115
147
|
});
|
|
116
148
|
const acceptedRetryConflict = retryKey !== void 0 && response.status === 409;
|
|
117
|
-
if (!response.ok && !acceptedRetryConflict)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
149
|
+
if (!response.ok && !acceptedRetryConflict) {
|
|
150
|
+
const body = await readResponseTextLimited(response, LINE_PROVIDER_RESPONSE_MAX_BYTES).catch(() => "");
|
|
151
|
+
throw new HTTPFetchError(`${response.status} - ${response.statusText}`, {
|
|
152
|
+
status: response.status,
|
|
153
|
+
statusText: response.statusText,
|
|
154
|
+
headers: response.headers,
|
|
155
|
+
body
|
|
156
|
+
});
|
|
157
|
+
}
|
|
123
158
|
try {
|
|
124
|
-
|
|
125
|
-
return text ? JSON.parse(text) : null;
|
|
159
|
+
return await readProviderJsonResponse(response, `LINE ${operation} response`, { maxBytes: LINE_PROVIDER_RESPONSE_MAX_BYTES });
|
|
126
160
|
} catch (error) {
|
|
127
161
|
throw createChannelPartialDeliveryError(error, {
|
|
128
162
|
messageIds: [],
|
|
@@ -136,28 +170,6 @@ function createTextMessage(text) {
|
|
|
136
170
|
text
|
|
137
171
|
};
|
|
138
172
|
}
|
|
139
|
-
function createImageMessage(originalContentUrl, previewImageUrl) {
|
|
140
|
-
return {
|
|
141
|
-
type: "image",
|
|
142
|
-
originalContentUrl,
|
|
143
|
-
previewImageUrl: previewImageUrl ?? originalContentUrl
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
function createVideoMessage(originalContentUrl, previewImageUrl, trackingId) {
|
|
147
|
-
return {
|
|
148
|
-
type: "video",
|
|
149
|
-
originalContentUrl,
|
|
150
|
-
previewImageUrl,
|
|
151
|
-
...trackingId ? { trackingId } : {}
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
function createAudioMessage(originalContentUrl, durationMs) {
|
|
155
|
-
return {
|
|
156
|
-
type: "audio",
|
|
157
|
-
originalContentUrl,
|
|
158
|
-
duration: durationMs
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
173
|
function isValidLineLocation(location) {
|
|
162
174
|
return location.title.trim().length > 0 && location.address.trim().length > 0;
|
|
163
175
|
}
|
|
@@ -180,9 +192,13 @@ function createLocationMessage(location) {
|
|
|
180
192
|
function logLineHttpError(err, context) {
|
|
181
193
|
if (!err || typeof err !== "object") return;
|
|
182
194
|
const { status, statusText, body } = err;
|
|
183
|
-
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
|
+
}
|
|
184
199
|
}
|
|
185
200
|
function recordLineOutboundActivity(accountId, delivery) {
|
|
201
|
+
recordLineSentMessages(accountId, delivery.messageIds);
|
|
186
202
|
try {
|
|
187
203
|
recordChannelActivity({
|
|
188
204
|
channel: "line",
|
|
@@ -236,7 +252,10 @@ async function pushLineMessages(to, messages, opts, behavior = {}) {
|
|
|
236
252
|
messageIds,
|
|
237
253
|
receipt: result.receipt
|
|
238
254
|
});
|
|
239
|
-
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
|
+
}
|
|
240
259
|
return result;
|
|
241
260
|
}
|
|
242
261
|
async function replyLineMessages(replyToken, messages, opts) {
|
|
@@ -253,29 +272,12 @@ async function sendMessageLine(to, text, opts) {
|
|
|
253
272
|
const chatId = normalizeTarget(to);
|
|
254
273
|
const messages = [];
|
|
255
274
|
const mediaUrl = opts.mediaUrl?.trim();
|
|
256
|
-
if (mediaUrl) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
await validateLineMediaUrl(previewImageUrl);
|
|
263
|
-
const trackingId = isLineUserChatId(chatId) ? opts.trackingId : void 0;
|
|
264
|
-
messages.push(createVideoMessage(mediaUrl, previewImageUrl, trackingId));
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
case "audio":
|
|
268
|
-
messages.push(createAudioMessage(mediaUrl, opts.durationMs ?? 6e4));
|
|
269
|
-
break;
|
|
270
|
-
default:
|
|
271
|
-
{
|
|
272
|
-
const previewImageUrl = opts.previewImageUrl?.trim() || mediaUrl;
|
|
273
|
-
await validateLineMediaUrl(previewImageUrl);
|
|
274
|
-
messages.push(createImageMessage(mediaUrl, previewImageUrl));
|
|
275
|
-
}
|
|
276
|
-
break;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
275
|
+
if (mediaUrl) messages.push(await buildLineMediaMessage(mediaUrl, {
|
|
276
|
+
mediaKind: opts.mediaKind,
|
|
277
|
+
previewImageUrl: opts.previewImageUrl,
|
|
278
|
+
durationMs: opts.durationMs,
|
|
279
|
+
trackingId: opts.trackingId
|
|
280
|
+
}, chatId));
|
|
279
281
|
if (text?.trim()) messages.push(createTextMessage(text.trim()));
|
|
280
282
|
if (messages.length === 0) throw new Error("Message must be non-empty for LINE sends");
|
|
281
283
|
if (opts.replyToken) {
|
|
@@ -322,9 +324,10 @@ function createFlexMessage(altText, contents) {
|
|
|
322
324
|
};
|
|
323
325
|
}
|
|
324
326
|
async function pushImageMessage(to, originalContentUrl, previewImageUrl, opts) {
|
|
325
|
-
await
|
|
326
|
-
|
|
327
|
-
|
|
327
|
+
return pushLineMessages(to, [await buildLineMediaMessage(originalContentUrl, {
|
|
328
|
+
mediaKind: "image",
|
|
329
|
+
previewImageUrl
|
|
330
|
+
}, to)], opts, { verboseMessage: (chatId) => `line: pushed image to ${chatId}` });
|
|
328
331
|
}
|
|
329
332
|
async function pushLocationMessage(to, location, opts) {
|
|
330
333
|
return pushLineMessages(to, [createLocationMessage(location)], opts, { verboseMessage: (chatId) => `line: pushed location to ${chatId}` });
|
|
@@ -366,26 +369,43 @@ async function showLoadingAnimation(chatId, opts) {
|
|
|
366
369
|
logVerbose(`line: loading animation failed (non-fatal): ${String(err)}`);
|
|
367
370
|
}
|
|
368
371
|
}
|
|
372
|
+
function lineProfileCacheKey(accountId, userId, scope) {
|
|
373
|
+
const conversation = scope.groupId ? ["group", scope.groupId] : scope.roomId ? ["room", scope.roomId] : ["direct"];
|
|
374
|
+
return JSON.stringify([
|
|
375
|
+
accountId,
|
|
376
|
+
"profile",
|
|
377
|
+
...conversation,
|
|
378
|
+
userId
|
|
379
|
+
]);
|
|
380
|
+
}
|
|
381
|
+
function fetchLineMemberProfile(client, userId, scope) {
|
|
382
|
+
if (scope.groupId) return client.getGroupMemberProfile(scope.groupId, userId);
|
|
383
|
+
if (scope.roomId) return client.getRoomMemberProfile(scope.roomId, userId);
|
|
384
|
+
return client.getProfile(userId);
|
|
385
|
+
}
|
|
369
386
|
async function getUserProfile(userId, opts) {
|
|
370
|
-
|
|
371
|
-
const cached = userProfileCache.get(userId);
|
|
372
|
-
if (cached && Date.now() - cached.fetchedAt < PROFILE_CACHE_TTL_MS) return {
|
|
373
|
-
displayName: cached.displayName,
|
|
374
|
-
pictureUrl: cached.pictureUrl
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
const { client } = createLineMessagingClient(opts);
|
|
387
|
+
const useCache = opts.useCache ?? true;
|
|
378
388
|
try {
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
389
|
+
const { account, token } = resolveLineMessagingAccount(opts);
|
|
390
|
+
const cacheKey = lineProfileCacheKey(account.accountId, userId, opts);
|
|
391
|
+
const load = async () => {
|
|
392
|
+
try {
|
|
393
|
+
const profile = await fetchLineMemberProfile(new messagingApi.MessagingApiClient({ channelAccessToken: token }), userId, opts);
|
|
394
|
+
return {
|
|
395
|
+
displayName: profile.displayName,
|
|
396
|
+
pictureUrl: profile.pictureUrl
|
|
397
|
+
};
|
|
398
|
+
} catch (err) {
|
|
399
|
+
logVerbose(`line: failed to fetch profile for ${userId}: ${String(err)}`);
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
383
402
|
};
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
403
|
+
if (!useCache) {
|
|
404
|
+
const profile = await load();
|
|
405
|
+
rememberLineIdentity(profileCache, cacheKey, profile);
|
|
406
|
+
return profile;
|
|
407
|
+
}
|
|
408
|
+
return await loadLineIdentity(profileCache, cacheKey, load);
|
|
389
409
|
} catch (err) {
|
|
390
410
|
logVerbose(`line: failed to fetch profile for ${userId}: ${String(err)}`);
|
|
391
411
|
return null;
|
|
@@ -394,5 +414,26 @@ async function getUserProfile(userId, opts) {
|
|
|
394
414
|
async function getUserDisplayName(userId, opts) {
|
|
395
415
|
return (await getUserProfile(userId, opts))?.displayName ?? userId;
|
|
396
416
|
}
|
|
417
|
+
async function getLineGroupName(groupId, opts) {
|
|
418
|
+
try {
|
|
419
|
+
const { account, token } = resolveLineMessagingAccount(opts);
|
|
420
|
+
const cacheKey = JSON.stringify([
|
|
421
|
+
account.accountId,
|
|
422
|
+
"group",
|
|
423
|
+
groupId
|
|
424
|
+
]);
|
|
425
|
+
return await loadLineIdentity(groupNameCache, cacheKey, async () => {
|
|
426
|
+
try {
|
|
427
|
+
return (await new messagingApi.MessagingApiClient({ channelAccessToken: token }).getGroupSummary(groupId)).groupName.trim() || void 0;
|
|
428
|
+
} catch (err) {
|
|
429
|
+
logVerbose(`line: failed to fetch group summary for ${groupId}: ${String(err)}`);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
} catch (err) {
|
|
434
|
+
logVerbose(`line: failed to fetch group summary for ${groupId}: ${String(err)}`);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
397
438
|
//#endregion
|
|
398
|
-
export {
|
|
439
|
+
export { showLoadingAnimation as _, getLineGroupName as a, pushFlexMessage as c, pushMessageLine as d, pushMessagesLine as f, sendMessageLine as g, replyMessageLine as h, createTextMessageWithQuickReplies as i, pushImageMessage as l, pushTextMessageWithQuickReplies as m, createLocationMessage as n, getUserDisplayName as o, pushTemplateMessage as p, createQuickReplyItems as r, getUserProfile as s, createFlexMessage as t, pushLocationMessage as u, quotesLineBotMessage as v, resolveLineChannelAccessToken as y };
|
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,19 +1,9 @@
|
|
|
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
|
+
import { n as parseLineAllowFromId, t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
|
|
2
3
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
4
|
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
4
5
|
import { DEFAULT_ACCOUNT_ID, createAllowFromSection, createPromptParsedAllowFromForAccount, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, parseSetupEntriesWithParser, patchScopedAccountConfig, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
|
|
5
6
|
import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
|
|
6
|
-
//#region extensions/line/src/account-helpers.ts
|
|
7
|
-
function hasLineCredentials(account) {
|
|
8
|
-
if (account.tokenStatus && account.signingSecretStatus) return account.tokenStatus !== "missing" && account.signingSecretStatus !== "missing";
|
|
9
|
-
return Boolean(account.channelAccessToken?.trim() && account.channelSecret?.trim());
|
|
10
|
-
}
|
|
11
|
-
function parseLineAllowFromId(raw) {
|
|
12
|
-
const trimmed = raw.trim().replace(/^line:(?:user:)?/i, "");
|
|
13
|
-
if (!/^U[a-f0-9]{32}$/i.test(trimmed)) return null;
|
|
14
|
-
return trimmed;
|
|
15
|
-
}
|
|
16
|
-
//#endregion
|
|
17
7
|
//#region extensions/line/src/setup-core.ts
|
|
18
8
|
function patchLineAccountConfig(params) {
|
|
19
9
|
return patchScopedAccountConfig({
|
|
@@ -62,6 +52,26 @@ const lineSetupAdapter = {
|
|
|
62
52
|
const accessToken = typedInput.channelAccessToken ?? typedInput.token;
|
|
63
53
|
const normalizedAccountId = normalizeAccountId(accountId);
|
|
64
54
|
const useEnv = normalizedAccountId === DEFAULT_ACCOUNT_ID && Boolean(typedInput.useEnv);
|
|
55
|
+
const credentials = [{
|
|
56
|
+
fileKey: "tokenFile",
|
|
57
|
+
file: typedInput.tokenFile,
|
|
58
|
+
inlineKey: "channelAccessToken",
|
|
59
|
+
inline: accessToken
|
|
60
|
+
}, {
|
|
61
|
+
fileKey: "secretFile",
|
|
62
|
+
file: typedInput.secretFile,
|
|
63
|
+
inlineKey: "channelSecret",
|
|
64
|
+
inline: typedInput.channelSecret
|
|
65
|
+
}];
|
|
66
|
+
const patch = {};
|
|
67
|
+
const retired = [];
|
|
68
|
+
for (const credential of credentials) if (credential.file) {
|
|
69
|
+
patch[credential.fileKey] = credential.file;
|
|
70
|
+
retired.push(credential.inlineKey);
|
|
71
|
+
} else if (credential.inline) {
|
|
72
|
+
patch[credential.inlineKey] = credential.inline;
|
|
73
|
+
retired.push(credential.fileKey);
|
|
74
|
+
}
|
|
65
75
|
return patchLineAccountConfig({
|
|
66
76
|
cfg,
|
|
67
77
|
accountId: normalizedAccountId,
|
|
@@ -71,11 +81,8 @@ const lineSetupAdapter = {
|
|
|
71
81
|
"channelSecret",
|
|
72
82
|
"tokenFile",
|
|
73
83
|
"secretFile"
|
|
74
|
-
] : void 0,
|
|
75
|
-
patch: useEnv ? {} :
|
|
76
|
-
...typedInput.tokenFile ? { tokenFile: typedInput.tokenFile } : accessToken ? { channelAccessToken: accessToken } : {},
|
|
77
|
-
...typedInput.secretFile ? { secretFile: typedInput.secretFile } : typedInput.channelSecret ? { channelSecret: typedInput.channelSecret } : {}
|
|
78
|
-
}
|
|
84
|
+
] : retired.length > 0 ? retired : void 0,
|
|
85
|
+
patch: useEnv ? {} : patch
|
|
79
86
|
});
|
|
80
87
|
}
|
|
81
88
|
};
|
|
@@ -152,6 +159,27 @@ const LINE_ALLOW_FROM_HELP_LINES = [
|
|
|
152
159
|
t("wizard.line.multipleEntries"),
|
|
153
160
|
t("wizard.channels.docs", { link: formatDocsLink("/channels/line", "channels/line") })
|
|
154
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
|
+
});
|
|
155
183
|
const lineDmPolicy = createChannelDmPolicy({
|
|
156
184
|
label: "LINE",
|
|
157
185
|
channel,
|
|
@@ -166,27 +194,7 @@ const lineDmPolicy = createChannelDmPolicy({
|
|
|
166
194
|
patch,
|
|
167
195
|
clearFields: patch.dmPolicy === "pairing" || patch.dmPolicy === "disabled" ? ["allowFrom"] : void 0
|
|
168
196
|
}),
|
|
169
|
-
promptAllowFrom:
|
|
170
|
-
defaultAccountId: resolveDefaultLineAccountId,
|
|
171
|
-
noteTitle: t("wizard.line.allowlistTitle"),
|
|
172
|
-
noteLines: LINE_ALLOW_FROM_HELP_LINES,
|
|
173
|
-
message: t("wizard.line.allowFromPrompt"),
|
|
174
|
-
placeholder: "U1234567890abcdef1234567890abcdef",
|
|
175
|
-
parseEntries: (raw) => parseSetupEntriesWithParser(raw, (entry) => {
|
|
176
|
-
const id = parseLineAllowFromId(entry);
|
|
177
|
-
return id ? { value: id } : { error: t("wizard.line.allowFromInvalid") };
|
|
178
|
-
}),
|
|
179
|
-
getExistingAllowFrom: ({ cfg, accountId }) => resolveLineAccount({
|
|
180
|
-
cfg,
|
|
181
|
-
accountId
|
|
182
|
-
}).config.allowFrom ?? [],
|
|
183
|
-
applyAllowFrom: ({ cfg, accountId, allowFrom }) => patchLineAccountConfig({
|
|
184
|
-
cfg,
|
|
185
|
-
accountId,
|
|
186
|
-
enabled: true,
|
|
187
|
-
patch: { allowFrom }
|
|
188
|
-
})
|
|
189
|
-
})
|
|
197
|
+
promptAllowFrom: promptLineAllowFrom
|
|
190
198
|
});
|
|
191
199
|
function createLineTokenCredential(params) {
|
|
192
200
|
return defineTokenCredential({
|
|
@@ -295,4 +303,4 @@ const lineSetupWizard = {
|
|
|
295
303
|
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
|
|
296
304
|
};
|
|
297
305
|
//#endregion
|
|
298
|
-
export {
|
|
306
|
+
export { lineSetupAdapter as n, lineSetupContract as r, lineSetupWizard as t };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { isRecord, normalizeNullableString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
+
//#region extensions/line/src/webhook-spool-contract.ts
|
|
3
|
+
/** Message the canonical decoder attaches when it rejects a spool payload. The
|
|
4
|
+
* upgrade migration matches this signature to recover rows the pre-fix decoder
|
|
5
|
+
* dead-lettered; the identity fence writes a different message on purpose. */
|
|
6
|
+
const LINE_WEBHOOK_SPOOL_INVALID_PAYLOAD_MESSAGE = "LINE webhook spool payload is invalid.";
|
|
7
|
+
/** Dead-letter reason for undecodable events; shared so the migration's
|
|
8
|
+
* recovery signature can never drift from what the spool writes. */
|
|
9
|
+
const LINE_WEBHOOK_SPOOL_INVALID_EVENT_REASON = "invalid-event";
|
|
10
|
+
/** Defined locally (not via createChannelIngressError) because this module sits
|
|
11
|
+
* in the doctor contract closure, which must stay off the channel-outbound
|
|
12
|
+
* runtime barrel; the spool's permanent-failure classifier matches by class. */
|
|
13
|
+
var LineWebhookPayloadError = class extends Error {
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(message, options);
|
|
16
|
+
this.name = "LineWebhookPayloadError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** Message ids preserve the shipped replay-guard keyspace; other events use LINE's delivery id. */
|
|
20
|
+
function eventIdFor(event) {
|
|
21
|
+
if (!isRecord(event)) throw new LineWebhookPayloadError("LINE webhook event must be an object.");
|
|
22
|
+
if (event.type === "message") {
|
|
23
|
+
const message = isRecord(event.message) ? event.message : void 0;
|
|
24
|
+
const messageId = normalizeNullableString(message?.id);
|
|
25
|
+
if (messageId) return `message:${messageId}`;
|
|
26
|
+
}
|
|
27
|
+
const webhookEventId = normalizeNullableString(event.webhookEventId);
|
|
28
|
+
if (webhookEventId) return `event:${webhookEventId}`;
|
|
29
|
+
throw new LineWebhookPayloadError("LINE webhook event is missing a stable delivery id.");
|
|
30
|
+
}
|
|
31
|
+
/** Pre-drain (#109655) rows were keyed by the raw webhookEventId, before the
|
|
32
|
+
* message:/event: keyspace. The upgrade migration uses this prior derivation as its
|
|
33
|
+
* identity fence so a genuinely changed event still dead-letters. */
|
|
34
|
+
function legacyEventIdFor(event) {
|
|
35
|
+
if (!isRecord(event)) return null;
|
|
36
|
+
return normalizeNullableString(event.webhookEventId);
|
|
37
|
+
}
|
|
38
|
+
function laneKeyFor(event, eventId) {
|
|
39
|
+
if (!isRecord(event)) return eventId;
|
|
40
|
+
const source = isRecord(event.source) ? event.source : void 0;
|
|
41
|
+
if (source?.type === "group") {
|
|
42
|
+
const groupId = normalizeNullableString(source.groupId);
|
|
43
|
+
if (groupId) return `group:${groupId}`;
|
|
44
|
+
}
|
|
45
|
+
if (source?.type === "room") {
|
|
46
|
+
const roomId = normalizeNullableString(source.roomId);
|
|
47
|
+
if (roomId) return `room:${roomId}`;
|
|
48
|
+
}
|
|
49
|
+
if (source?.type === "user") {
|
|
50
|
+
const userId = normalizeNullableString(source.userId);
|
|
51
|
+
if (userId) return `user:${userId}`;
|
|
52
|
+
}
|
|
53
|
+
return eventId;
|
|
54
|
+
}
|
|
55
|
+
function errorText(error) {
|
|
56
|
+
return error instanceof Error ? error.message : String(error);
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { eventIdFor as a, errorText as i, LINE_WEBHOOK_SPOOL_INVALID_PAYLOAD_MESSAGE as n, laneKeyFor as o, LineWebhookPayloadError as r, legacyEventIdFor as s, LINE_WEBHOOK_SPOOL_INVALID_EVENT_REASON as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Returns true if the value is a ISO8601 DateTime string
|
|
3
|
-
* @
|
|
3
|
+
* @specification https://datatracker.ietf.org/doc/html/rfc3339
|
|
4
4
|
* @example `2020-12-12T20:20:40+00:00`
|
|
5
5
|
*/
|
|
6
|
-
export declare function IsDateTime(value: string
|
|
6
|
+
export declare function IsDateTime(value: string): boolean;
|
|
@@ -2,10 +2,10 @@ import { IsDate } from './date.mjs';
|
|
|
2
2
|
import { IsTime } from './time.mjs';
|
|
3
3
|
/**
|
|
4
4
|
* Returns true if the value is a ISO8601 DateTime string
|
|
5
|
-
* @
|
|
5
|
+
* @specification https://datatracker.ietf.org/doc/html/rfc3339
|
|
6
6
|
* @example `2020-12-12T20:20:40+00:00`
|
|
7
7
|
*/
|
|
8
|
-
export function IsDateTime(value
|
|
8
|
+
export function IsDateTime(value) {
|
|
9
9
|
const dateTime = value.split(/T/i);
|
|
10
|
-
return dateTime.length === 2 && IsDate(dateTime[0]) && IsTime(dateTime[1]
|
|
10
|
+
return dateTime.length === 2 && IsDate(dateTime[0]) && IsTime(dateTime[1]);
|
|
11
11
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const Email = /^(
|
|
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
|
-
* @specification
|
|
4
|
+
* @specification https://datatracker.ietf.org/doc/html/rfc5322
|
|
5
5
|
*/
|
|
6
6
|
export function IsEmail(value) {
|
|
7
7
|
return Email.test(value);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as Idna from './
|
|
1
|
+
import * as Idna from './idna/index.mjs';
|
|
2
2
|
/**
|
|
3
3
|
* Returns true if the value is a valid hostname.
|
|
4
4
|
* @specification https://tools.ietf.org/html/rfc1123
|
|
@@ -6,13 +6,5 @@ import * as Idna from './_idna.mjs';
|
|
|
6
6
|
* @specification https://tools.ietf.org/html/rfc5892
|
|
7
7
|
*/
|
|
8
8
|
export function IsHostname(value) {
|
|
9
|
-
|
|
10
|
-
return false;
|
|
11
|
-
if (value.charCodeAt(value.length - 1) === 46)
|
|
12
|
-
return false;
|
|
13
|
-
for (const label of value.split('.')) {
|
|
14
|
-
if (!Idna.IsLabel(label))
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
return true;
|
|
9
|
+
return Idna.IsHostname(value);
|
|
18
10
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const IdnEmail = /^(
|
|
1
|
+
const IdnEmail = /^(?:[A-Za-z0-9!#$%&'*+\/=?^_`{|}~\u{0080}-\u{10FFFF}-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?^_`{|}~\u{0080}-\u{10FFFF}-]+)*|"(?:[^"\\]|\\.)*")@[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,62})(?<!-)(?:\.[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,62})(?<!-))*$/iu;
|
|
2
2
|
/**
|
|
3
3
|
* Returns true if the value is an IdnEmail
|
|
4
|
-
* @specification
|
|
4
|
+
* @specification https://datatracker.ietf.org/doc/html/rfc4952
|
|
5
5
|
*/
|
|
6
6
|
export function IsIdnEmail(value) {
|
|
7
|
-
return IdnEmail.test(value);
|
|
7
|
+
return IdnEmail.test(value.normalize('NFC'));
|
|
8
8
|
}
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
* @specification https://tools.ietf.org/html/rfc3490
|
|
4
4
|
* @specification https://tools.ietf.org/html/rfc5891
|
|
5
5
|
* @specification https://tools.ietf.org/html/rfc5892
|
|
6
|
+
* @specification https://tools.ietf.org/html/rfc5893
|
|
6
7
|
*/
|
|
7
8
|
export declare function IsIdnHostname(value: string): boolean;
|