openzca 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/cli.js +110 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -206,7 +206,10 @@ It also includes stable routing fields for downstream tools:
|
|
|
206
206
|
|
|
207
207
|
- `threadId`, `targetId`, `conversationId`
|
|
208
208
|
- `senderId`, `toId`, `chatType`, `msgType`, `timestamp`
|
|
209
|
+
- `mentions` (normalized mention entities: `uid`, `pos`, `len`, `type`, optional `text`)
|
|
210
|
+
- `mentionIds` (flattened mention user IDs)
|
|
209
211
|
- `metadata.threadId`, `metadata.targetId`, `metadata.senderId`, `metadata.toId`
|
|
212
|
+
- `metadata.mentions`, `metadata.mentionIds`, `metadata.mentionCount`
|
|
210
213
|
- `quote` and `metadata.quote` when the inbound message is a reply to a previous message
|
|
211
214
|
- Includes parsed `quote.attach` and extracted `quote.mediaUrls` when attachment URLs are present.
|
|
212
215
|
- `quoteMediaPath`, `quoteMediaPaths`, `quoteMediaUrl`, `quoteMediaUrls`, `quoteMediaType`, `quoteMediaTypes`
|
package/dist/cli.js
CHANGED
|
@@ -1459,6 +1459,98 @@ function buildReplyMediaAttachedText(params) {
|
|
|
1459
1459
|
}
|
|
1460
1460
|
return lines.join("\n");
|
|
1461
1461
|
}
|
|
1462
|
+
function parseOptionalInt(value) {
|
|
1463
|
+
const numeric = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
|
|
1464
|
+
if (!Number.isFinite(numeric)) return void 0;
|
|
1465
|
+
return Math.trunc(numeric);
|
|
1466
|
+
}
|
|
1467
|
+
function buildInboundMention(record, rawText) {
|
|
1468
|
+
const uid = getStringCandidate(record, ["uid", "userId", "user_id", "id"]);
|
|
1469
|
+
if (!uid) return null;
|
|
1470
|
+
const pos = parseOptionalInt(record.pos ?? record.offset ?? record.start ?? record.index);
|
|
1471
|
+
const len = parseOptionalInt(record.len ?? record.length);
|
|
1472
|
+
const type = parseOptionalInt(record.type ?? record.kind);
|
|
1473
|
+
let text = getStringCandidate(record, ["text", "label", "name"]) || (typeof pos === "number" && typeof len === "number" && len > 0 && pos >= 0 && pos < rawText.length ? rawText.slice(pos, Math.min(rawText.length, pos + len)) : "");
|
|
1474
|
+
if (!text.trim()) {
|
|
1475
|
+
text = "";
|
|
1476
|
+
}
|
|
1477
|
+
return {
|
|
1478
|
+
uid,
|
|
1479
|
+
...typeof pos === "number" ? { pos } : {},
|
|
1480
|
+
...typeof len === "number" ? { len } : {},
|
|
1481
|
+
...typeof type === "number" ? { type } : {},
|
|
1482
|
+
...text ? { text } : {}
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
function collectInboundMentions(value, sink, rawText, depth = 0) {
|
|
1486
|
+
if (depth > 6 || sink.size >= 64 || value === null || value === void 0) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
if (typeof value === "string") {
|
|
1490
|
+
if (!looksLikeStructuredJsonString(value)) return;
|
|
1491
|
+
try {
|
|
1492
|
+
const parsed = JSON.parse(value);
|
|
1493
|
+
collectInboundMentions(parsed, sink, rawText, depth + 1);
|
|
1494
|
+
} catch {
|
|
1495
|
+
}
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
if (Array.isArray(value)) {
|
|
1499
|
+
for (const item of value) {
|
|
1500
|
+
const mention = asObject(item) ? buildInboundMention(item, rawText) : null;
|
|
1501
|
+
if (mention) {
|
|
1502
|
+
const key = `${mention.uid}|${mention.pos ?? ""}|${mention.len ?? ""}|${mention.type ?? ""}`;
|
|
1503
|
+
sink.set(key, mention);
|
|
1504
|
+
continue;
|
|
1505
|
+
}
|
|
1506
|
+
collectInboundMentions(item, sink, rawText, depth + 1);
|
|
1507
|
+
if (sink.size >= 64) return;
|
|
1508
|
+
}
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
const record = asObject(value);
|
|
1512
|
+
if (!record) return;
|
|
1513
|
+
const direct = buildInboundMention(record, rawText);
|
|
1514
|
+
if (direct) {
|
|
1515
|
+
const key = `${direct.uid}|${direct.pos ?? ""}|${direct.len ?? ""}|${direct.type ?? ""}`;
|
|
1516
|
+
sink.set(key, direct);
|
|
1517
|
+
}
|
|
1518
|
+
const mentionKeys = [
|
|
1519
|
+
"mentions",
|
|
1520
|
+
"mentionInfo",
|
|
1521
|
+
"mention_info",
|
|
1522
|
+
"mentionList",
|
|
1523
|
+
"mention_list",
|
|
1524
|
+
"mention"
|
|
1525
|
+
];
|
|
1526
|
+
for (const key of mentionKeys) {
|
|
1527
|
+
if (!(key in record)) continue;
|
|
1528
|
+
collectInboundMentions(record[key], sink, rawText, depth + 1);
|
|
1529
|
+
if (sink.size >= 64) return;
|
|
1530
|
+
}
|
|
1531
|
+
for (const nested of Object.values(record)) {
|
|
1532
|
+
collectInboundMentions(nested, sink, rawText, depth + 1);
|
|
1533
|
+
if (sink.size >= 64) return;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
function extractInboundMentions(params) {
|
|
1537
|
+
const sink = /* @__PURE__ */ new Map();
|
|
1538
|
+
const candidates = [
|
|
1539
|
+
params.messageData.mentions,
|
|
1540
|
+
params.messageData.mentionInfo,
|
|
1541
|
+
params.messageData.mention_info,
|
|
1542
|
+
params.messageData.mentionList,
|
|
1543
|
+
params.messageData.mention_list,
|
|
1544
|
+
params.messageData.mention,
|
|
1545
|
+
params.messageData.content,
|
|
1546
|
+
params.parsedContent
|
|
1547
|
+
];
|
|
1548
|
+
for (const candidate of candidates) {
|
|
1549
|
+
collectInboundMentions(candidate, sink, params.rawText);
|
|
1550
|
+
if (sink.size >= 64) break;
|
|
1551
|
+
}
|
|
1552
|
+
return [...sink.values()];
|
|
1553
|
+
}
|
|
1462
1554
|
function normalizeFriendLookupRows(value) {
|
|
1463
1555
|
const queue = [value];
|
|
1464
1556
|
const rows = [];
|
|
@@ -2781,11 +2873,22 @@ ${replyContextText}` : replyContextText;
|
|
|
2781
2873
|
}
|
|
2782
2874
|
const chatType = message.type === ThreadType.Group ? "group" : "user";
|
|
2783
2875
|
const senderId = getStringCandidate(messageData, ["uidFrom"]) || message.data.uidFrom;
|
|
2784
|
-
const senderDisplayNameRaw = getStringCandidate(messageData, [
|
|
2876
|
+
const senderDisplayNameRaw = getStringCandidate(messageData, [
|
|
2877
|
+
"dName",
|
|
2878
|
+
"fromD",
|
|
2879
|
+
"senderName",
|
|
2880
|
+
"displayName"
|
|
2881
|
+
]);
|
|
2785
2882
|
const senderDisplayName = senderDisplayNameRaw || void 0;
|
|
2786
2883
|
const senderNameForMetadata = message.type === ThreadType.Group ? senderDisplayName : void 0;
|
|
2787
2884
|
const toId = getStringCandidate(messageData, ["idTo"]) || void 0;
|
|
2788
2885
|
const threadName = typeof messageData.threadName === "string" ? messageData.threadName : typeof messageData.tName === "string" ? messageData.tName : void 0;
|
|
2886
|
+
const mentions = extractInboundMentions({
|
|
2887
|
+
messageData,
|
|
2888
|
+
parsedContent,
|
|
2889
|
+
rawText
|
|
2890
|
+
});
|
|
2891
|
+
const mentionIds = mentions.map((item) => item.uid);
|
|
2789
2892
|
const timestamp = toEpochSeconds(message.data.ts);
|
|
2790
2893
|
const payload = {
|
|
2791
2894
|
threadId: message.threadId,
|
|
@@ -2811,6 +2914,8 @@ ${replyContextText}` : replyContextText;
|
|
|
2811
2914
|
mediaType,
|
|
2812
2915
|
mediaTypes: mediaTypes.length > 0 ? mediaTypes : void 0,
|
|
2813
2916
|
mediaKind: mediaKind ?? void 0,
|
|
2917
|
+
mentions: mentions.length > 0 ? mentions : void 0,
|
|
2918
|
+
mentionIds: mentionIds.length > 0 ? mentionIds : void 0,
|
|
2814
2919
|
metadata: {
|
|
2815
2920
|
isGroup: message.type === ThreadType.Group,
|
|
2816
2921
|
chatType,
|
|
@@ -2837,7 +2942,10 @@ ${replyContextText}` : replyContextText;
|
|
|
2837
2942
|
mediaUrls: mediaUrls.length > 0 ? mediaUrls : void 0,
|
|
2838
2943
|
mediaType,
|
|
2839
2944
|
mediaTypes: mediaTypes.length > 0 ? mediaTypes : void 0,
|
|
2840
|
-
mediaKind: mediaKind ?? void 0
|
|
2945
|
+
mediaKind: mediaKind ?? void 0,
|
|
2946
|
+
mentions: mentions.length > 0 ? mentions : void 0,
|
|
2947
|
+
mentionIds: mentionIds.length > 0 ? mentionIds : void 0,
|
|
2948
|
+
mentionCount: mentions.length > 0 ? mentions.length : void 0
|
|
2841
2949
|
},
|
|
2842
2950
|
// Backward-compatible convenience fields.
|
|
2843
2951
|
chatType,
|