@wirecat/whatsapp-cli 0.0.0-stage → 0.1.0
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/LICENSE +204 -0
- package/README.md +282 -2
- package/dist/adapter/adapter.d.ts +9 -0
- package/dist/adapter/adapter.d.ts.map +1 -0
- package/dist/adapter/adapter.js +326 -0
- package/dist/adapter/adapter.js.map +1 -0
- package/dist/adapter/checks.d.ts +7 -0
- package/dist/adapter/checks.d.ts.map +1 -0
- package/dist/adapter/checks.js +3 -0
- package/dist/adapter/checks.js.map +1 -0
- package/dist/adapter/errors.d.ts +18 -0
- package/dist/adapter/errors.d.ts.map +1 -0
- package/dist/adapter/errors.js +40 -0
- package/dist/adapter/errors.js.map +1 -0
- package/dist/adapter/format-markdown.d.ts +8 -0
- package/dist/adapter/format-markdown.d.ts.map +1 -0
- package/dist/adapter/format-markdown.js +80 -0
- package/dist/adapter/format-markdown.js.map +1 -0
- package/dist/adapter/groups.d.ts +21 -0
- package/dist/adapter/groups.d.ts.map +1 -0
- package/dist/adapter/groups.js +210 -0
- package/dist/adapter/groups.js.map +1 -0
- package/dist/adapter/map.d.ts +9 -0
- package/dist/adapter/map.d.ts.map +1 -0
- package/dist/adapter/map.js +72 -0
- package/dist/adapter/map.js.map +1 -0
- package/dist/adapter/polls.d.ts +21 -0
- package/dist/adapter/polls.d.ts.map +1 -0
- package/dist/adapter/polls.js +103 -0
- package/dist/adapter/polls.js.map +1 -0
- package/dist/app.d.ts +6 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +16 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/wa.d.ts +3 -0
- package/dist/bin/wa.d.ts.map +1 -0
- package/dist/bin/wa.js +27 -0
- package/dist/bin/wa.js.map +1 -0
- package/dist/commands/answer.d.ts +7 -0
- package/dist/commands/answer.d.ts.map +1 -0
- package/dist/commands/answer.js +11 -0
- package/dist/commands/answer.js.map +1 -0
- package/dist/commands/session.d.ts +37 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +202 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +192 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +36 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/diagnose.d.ts +77 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +84 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/engine/contract.d.ts +617 -0
- package/dist/engine/contract.d.ts.map +1 -0
- package/dist/engine/contract.js +186 -0
- package/dist/engine/contract.js.map +1 -0
- package/dist/engine/events.d.ts +9 -0
- package/dist/engine/events.d.ts.map +1 -0
- package/dist/engine/events.js +23 -0
- package/dist/engine/events.js.map +1 -0
- package/dist/engine/go-engine.d.ts +23 -0
- package/dist/engine/go-engine.d.ts.map +1 -0
- package/dist/engine/go-engine.js +238 -0
- package/dist/engine/go-engine.js.map +1 -0
- package/dist/engine/groups.d.ts +159 -0
- package/dist/engine/groups.d.ts.map +1 -0
- package/dist/engine/groups.js +64 -0
- package/dist/engine/groups.js.map +1 -0
- package/dist/engine-binary.d.ts +5 -0
- package/dist/engine-binary.d.ts.map +1 -0
- package/dist/engine-binary.js +18 -0
- package/dist/engine-binary.js.map +1 -0
- package/dist/install/postinstall.d.ts +8 -0
- package/dist/install/postinstall.d.ts.map +1 -0
- package/dist/install/postinstall.js +62 -0
- package/dist/install/postinstall.js.map +1 -0
- package/dist/messenger.d.ts +64 -0
- package/dist/messenger.d.ts.map +1 -0
- package/dist/messenger.js +171 -0
- package/dist/messenger.js.map +1 -0
- package/dist/paths.d.ts +5 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +7 -0
- package/dist/paths.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +114 -0
- package/dist/program.js.map +1 -0
- package/dist/reasons.d.ts +4 -0
- package/dist/reasons.d.ts.map +1 -0
- package/dist/reasons.js +13 -0
- package/dist/reasons.js.map +1 -0
- package/dist/update.d.ts +8 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +26 -0
- package/dist/update.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install/postinstall.mjs +3 -0
- package/install/windows.ps1 +161 -0
- package/package.json +89 -4
- package/skills/whatsapp-cli/SKILL.md +290 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
import { toChat, toMember } from "./map.js";
|
|
3
|
+
/** What a WhatsApp admin may do. WhatsApp has one kind of admin, with all of these at once. */
|
|
4
|
+
export const ADMIN_RIGHTS = [
|
|
5
|
+
"members",
|
|
6
|
+
"admins",
|
|
7
|
+
"info",
|
|
8
|
+
"pin",
|
|
9
|
+
"link",
|
|
10
|
+
"post",
|
|
11
|
+
"delete",
|
|
12
|
+
];
|
|
13
|
+
/** The switches of cli-core's `chats update` that WhatsApp has. */
|
|
14
|
+
export const GROUP_SETTINGS = [
|
|
15
|
+
"onlyAdminsAdd",
|
|
16
|
+
"joinApproval",
|
|
17
|
+
"onlyAdminsSend",
|
|
18
|
+
"onlyAdminsEditInfo",
|
|
19
|
+
"disappearingSeconds",
|
|
20
|
+
];
|
|
21
|
+
/** The timers WhatsApp's apps offer, in seconds; its server refuses any other in a group. */
|
|
22
|
+
const DISAPPEARING_SECONDS = [0, 86_400, 604_800, 7_776_000];
|
|
23
|
+
const isPerson = (id) => id.endsWith("@lid") || id.endsWith("@s.whatsapp.net");
|
|
24
|
+
/** A group as `chats update` and `chats create` answer it. */
|
|
25
|
+
export const toGroupCard = (group) => {
|
|
26
|
+
const chat = toChat(group.chat);
|
|
27
|
+
return {
|
|
28
|
+
...chat,
|
|
29
|
+
description: group.description,
|
|
30
|
+
link: group.link,
|
|
31
|
+
settings: {
|
|
32
|
+
allCanPin: null,
|
|
33
|
+
onlyAdminsAdd: group.addMode === "" ? null : group.addMode === "admin_add",
|
|
34
|
+
onlyAdminsCall: null,
|
|
35
|
+
onlyOwnerEditsInfo: null,
|
|
36
|
+
membersSeeLink: null,
|
|
37
|
+
joinApproval: group.approval,
|
|
38
|
+
onlyAdminsSend: group.announce,
|
|
39
|
+
onlyAdminsEditInfo: group.locked,
|
|
40
|
+
disappearingSeconds: group.ephemeral,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const toGroupMember = ({ jid, name, role }) => ({
|
|
45
|
+
id: jid,
|
|
46
|
+
name,
|
|
47
|
+
username: null,
|
|
48
|
+
role,
|
|
49
|
+
});
|
|
50
|
+
export const groupAdapter = ({ engine, resolve, translated, wroteTo }) => {
|
|
51
|
+
const groupId = async (reference) => {
|
|
52
|
+
const { id } = await resolve(reference);
|
|
53
|
+
if (!id.endsWith("@g.us"))
|
|
54
|
+
throw new CliError("validation_error", "that chat is not a WhatsApp group");
|
|
55
|
+
return id;
|
|
56
|
+
};
|
|
57
|
+
const personId = async (reference) => {
|
|
58
|
+
const { id } = await resolve(reference);
|
|
59
|
+
if (!isPerson(id))
|
|
60
|
+
throw new CliError("validation_error", "that is a chat, not a person");
|
|
61
|
+
return id;
|
|
62
|
+
};
|
|
63
|
+
// WhatsApp bans accounts that add strangers to groups, so only someone in the address book or written to before.
|
|
64
|
+
const refuseStrangers = async (people) => {
|
|
65
|
+
const book = new Set((await translated(engine.contacts())).map((contact) => contact.jid));
|
|
66
|
+
for (const person of people) {
|
|
67
|
+
if (book.has(person) || (await wroteTo(person)))
|
|
68
|
+
continue;
|
|
69
|
+
throw new CliError("permission_error", "wa adds only people in your address book or that you have written to — WhatsApp bans accounts that add strangers");
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
members: async (chat, { limit, offset }) => {
|
|
74
|
+
const group = await translated(engine.group(await groupId(chat)));
|
|
75
|
+
const end = limit === undefined ? group.members.length : offset + limit;
|
|
76
|
+
return {
|
|
77
|
+
chatId: group.chat.jid,
|
|
78
|
+
items: group.members.slice(offset, end).map(toGroupMember),
|
|
79
|
+
hasMore: group.members.length > end,
|
|
80
|
+
participantsCount: group.members.length,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
admins: async (chat) => {
|
|
84
|
+
const group = await translated(engine.group(await groupId(chat)));
|
|
85
|
+
return group.members.filter((member) => member.role !== "member").map((member) => member.jid);
|
|
86
|
+
},
|
|
87
|
+
people: async (references) => {
|
|
88
|
+
const chats = await translated(engine.directory());
|
|
89
|
+
return references.map((reference) => {
|
|
90
|
+
const typed = reference.trim();
|
|
91
|
+
if (typed.includes("@")) {
|
|
92
|
+
if (!isPerson(typed))
|
|
93
|
+
throw new CliError("validation_error", "that is a chat, not a person");
|
|
94
|
+
return typed;
|
|
95
|
+
}
|
|
96
|
+
const wanted = typed.toLowerCase();
|
|
97
|
+
const people = chats.filter((chat) => chat.kind === "dm" && isPerson(chat.jid) && chat.name !== null);
|
|
98
|
+
const exact = people.filter((chat) => chat.name?.toLowerCase() === wanted);
|
|
99
|
+
const found = exact.length > 0 ? exact : people.filter((chat) => chat.name?.toLowerCase().includes(wanted));
|
|
100
|
+
if (found.length === 1 && found[0])
|
|
101
|
+
return found[0].jid;
|
|
102
|
+
if (found.length > 1)
|
|
103
|
+
throw new CliError("validation_error", `${found.length} people match that name — name one by their id (…@lid)`);
|
|
104
|
+
throw new CliError("not_found", "nobody by that name in your WhatsApp contacts; name them by their id (…@lid)");
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
createGroup: async (title, people, { channel }) => {
|
|
108
|
+
if (channel)
|
|
109
|
+
throw new CliError("validation_error", "wa makes groups only; WhatsApp channels are made in the app");
|
|
110
|
+
await refuseStrangers(people);
|
|
111
|
+
const { group, notAdded } = await translated(engine.createGroup(title, people));
|
|
112
|
+
const card = toGroupCard(group);
|
|
113
|
+
return notAdded.length === 0 ? card : { ...card, providerMetadata: { ...card.providerMetadata, notAdded } };
|
|
114
|
+
},
|
|
115
|
+
join: async (link) => {
|
|
116
|
+
const joined = await translated(engine.join(link));
|
|
117
|
+
return joined.group ? toGroupCard(joined.group) : { requested: true };
|
|
118
|
+
},
|
|
119
|
+
leave: async (chat) => {
|
|
120
|
+
const chatId = await groupId(chat);
|
|
121
|
+
await translated(engine.leave(chatId));
|
|
122
|
+
return { chatId };
|
|
123
|
+
},
|
|
124
|
+
group: async (chat) => toGroupCard(await translated(engine.group(await groupId(chat), { withLink: true }))),
|
|
125
|
+
updateGroup: async (chatId, { title, description, settings = {}, photo }) => {
|
|
126
|
+
if (photo !== undefined)
|
|
127
|
+
throw new CliError("validation_error", "wa does not set a group's photo yet");
|
|
128
|
+
const missing = Object.keys(settings).filter((key) => !GROUP_SETTINGS.includes(key));
|
|
129
|
+
if (missing.length > 0)
|
|
130
|
+
throw new CliError("validation_error", `WhatsApp has no group setting ${missing.join(", ")}`);
|
|
131
|
+
const { onlyAdminsAdd, joinApproval, onlyAdminsSend, onlyAdminsEditInfo, disappearingSeconds } = settings;
|
|
132
|
+
if (typeof disappearingSeconds === "number" && !DISAPPEARING_SECONDS.includes(disappearingSeconds))
|
|
133
|
+
throw new CliError("validation_error", "WhatsApp makes messages disappear after 24h, 7d or 90d; off keeps them");
|
|
134
|
+
const group = await translated(engine.updateGroup(await groupId(chatId), {
|
|
135
|
+
...(title === undefined ? {} : { title }),
|
|
136
|
+
...(description === undefined ? {} : { description }),
|
|
137
|
+
...(typeof onlyAdminsAdd === "boolean" ? { addMode: onlyAdminsAdd ? "admin_add" : "all_member_add" } : {}),
|
|
138
|
+
...(typeof joinApproval === "boolean" ? { approval: joinApproval } : {}),
|
|
139
|
+
...(typeof onlyAdminsSend === "boolean" ? { announce: onlyAdminsSend } : {}),
|
|
140
|
+
...(typeof onlyAdminsEditInfo === "boolean" ? { locked: onlyAdminsEditInfo } : {}),
|
|
141
|
+
...(typeof disappearingSeconds === "number" ? { ephemeral: disappearingSeconds } : {}),
|
|
142
|
+
}));
|
|
143
|
+
return toGroupCard(group);
|
|
144
|
+
},
|
|
145
|
+
resetInviteLink: async (chatId) => toGroupCard(await translated(engine.resetInviteLink(await groupId(chatId)))),
|
|
146
|
+
addMembers: async (chatId, people, { history }) => {
|
|
147
|
+
if (history)
|
|
148
|
+
throw new CliError("validation_error", "WhatsApp does not show people added the messages from before");
|
|
149
|
+
await refuseStrangers(people);
|
|
150
|
+
return translated(engine.participants(await groupId(chatId), "add", people));
|
|
151
|
+
},
|
|
152
|
+
removeMembers: async (chatId, people) => {
|
|
153
|
+
await translated(engine.participants(await groupId(chatId), "remove", people));
|
|
154
|
+
},
|
|
155
|
+
addAdmin: async (chatId, person) => {
|
|
156
|
+
await translated(engine.participants(await groupId(chatId), "promote", [person]));
|
|
157
|
+
},
|
|
158
|
+
removeAdmin: async (chatId, person) => {
|
|
159
|
+
await translated(engine.participants(await groupId(chatId), "demote", [person]));
|
|
160
|
+
},
|
|
161
|
+
joinRequests: async (chatId, { limit, search, link }) => {
|
|
162
|
+
if (link !== undefined)
|
|
163
|
+
throw new CliError("validation_error", "a WhatsApp group has one invite link; leave out --link");
|
|
164
|
+
const wanted = search?.toLowerCase();
|
|
165
|
+
const found = (await translated(engine.joinRequests(await groupId(chatId))))
|
|
166
|
+
.filter((one) => wanted === undefined || (one.name?.toLowerCase().includes(wanted) ?? false))
|
|
167
|
+
.sort((a, b) => (b.requestedAt ?? "").localeCompare(a.requestedAt ?? ""));
|
|
168
|
+
return {
|
|
169
|
+
items: found.slice(0, limit).map((one) => ({
|
|
170
|
+
person: { id: one.jid, name: one.name, username: null },
|
|
171
|
+
requestedAt: one.requestedAt,
|
|
172
|
+
})),
|
|
173
|
+
hasMore: found.length > limit,
|
|
174
|
+
total: found.length,
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
answerJoinRequest: async (chatId, person, accept) => {
|
|
178
|
+
await translated(engine.answerJoinRequest(await groupId(chatId), person, accept));
|
|
179
|
+
return { already: false };
|
|
180
|
+
},
|
|
181
|
+
profile: async (reference) => {
|
|
182
|
+
const found = await translated(engine.profile(await personId(reference)));
|
|
183
|
+
return {
|
|
184
|
+
id: found.jid,
|
|
185
|
+
name: found.name,
|
|
186
|
+
usernames: [],
|
|
187
|
+
bio: found.about,
|
|
188
|
+
flags: found.verified ? { verified: true } : {},
|
|
189
|
+
contact: found.contact,
|
|
190
|
+
...(found.photo === null ? {} : { hasPhoto: found.photo }),
|
|
191
|
+
chats: [],
|
|
192
|
+
};
|
|
193
|
+
},
|
|
194
|
+
block: async (person) => {
|
|
195
|
+
await translated(engine.block(person, true));
|
|
196
|
+
},
|
|
197
|
+
unblock: async (person) => {
|
|
198
|
+
await translated(engine.block(person, false));
|
|
199
|
+
},
|
|
200
|
+
lookup: async (phone) => toMember(await translated(engine.lookup(phone))),
|
|
201
|
+
addressBook: async () => (await translated(engine.contacts())).map(toMember),
|
|
202
|
+
// Connecting is the check: WhatsApp refuses a banned account's connection, and the engine answers with the ban,
|
|
203
|
+
// whose `standing` holds the profile's writes. A connection lifts that hold (`doctor --online`, WC-PERM-18).
|
|
204
|
+
health: async () => {
|
|
205
|
+
await translated(engine.ready(new AbortController().signal));
|
|
206
|
+
return { standingChecked: true };
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/adapter/groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Attachment, Chat, Member, Message } from "@wirecat/cli-core";
|
|
2
|
+
import { type WaAttachment, type WaChat, type WaContact, type WaMessage } from "../engine/contract.js";
|
|
3
|
+
export declare const toChat: (chat: WaChat) => Chat;
|
|
4
|
+
export declare const toMember: (contact: WaContact) => Member;
|
|
5
|
+
export declare const toAttachment: ({ kind, url, width, height, title, name, size, mime, duration, ref }: WaAttachment) => Attachment;
|
|
6
|
+
export declare const toMessage: (message: WaMessage) => Message;
|
|
7
|
+
/** A stored attachment as the engine takes it back, or `undefined` when it is not one this engine wrote. */
|
|
8
|
+
export declare const toWaAttachment: ({ providerRef, ...attachment }: Attachment) => WaAttachment | undefined;
|
|
9
|
+
//# sourceMappingURL=map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.d.ts","sourceRoot":"","sources":["../../src/adapter/map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAY,MAAM,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEpF,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAgB,MAAM,uBAAuB,CAAA;AAUpH,eAAO,MAAM,MAAM,SAAU,MAAM,KAAG,IASpC,CAAA;AAEF,eAAO,MAAM,QAAQ,YAAa,SAAS,KAAG,MAAmE,CAAA;AAGjH,eAAO,MAAM,YAAY,yEAA0E,YAAY,eAY9G,CAAA;AAED,eAAO,MAAM,SAAS,YAAa,SAAS,KAAG,OAgB7C,CAAA;AAEF,4GAA4G;AAC5G,eAAO,MAAM,cAAc,mCAAoC,UAAU,KAAG,YAAY,GAAG,SAW1F,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import { waAttachment } from "../engine/contract.js";
|
|
3
|
+
const KINDS = {
|
|
4
|
+
dm: "dialog",
|
|
5
|
+
self: "saved",
|
|
6
|
+
group: "group",
|
|
7
|
+
newsletter: "channel",
|
|
8
|
+
broadcast: "unknown",
|
|
9
|
+
};
|
|
10
|
+
export const toChat = (chat) => ({
|
|
11
|
+
id: chat.jid,
|
|
12
|
+
title: chat.name,
|
|
13
|
+
kind: KINDS[chat.kind],
|
|
14
|
+
unreadCount: chat.unread,
|
|
15
|
+
lastMessageAt: chat.lastMessageAt,
|
|
16
|
+
participantsCount: chat.participants,
|
|
17
|
+
...(chat.archived === undefined ? {} : { archived: chat.archived }),
|
|
18
|
+
...(chat.muted === undefined ? {} : { muted: chat.muted }),
|
|
19
|
+
});
|
|
20
|
+
export const toMember = (contact) => ({ id: contact.jid, name: contact.name, username: null });
|
|
21
|
+
// In the domain type's order, so an answer from the store prints byte for byte the same.
|
|
22
|
+
export const toAttachment = ({ kind, url, width, height, title, name, size, mime, duration, ref }) => {
|
|
23
|
+
const attachment = { kind };
|
|
24
|
+
if (url !== undefined)
|
|
25
|
+
attachment.url = url;
|
|
26
|
+
if (width !== undefined)
|
|
27
|
+
attachment.width = width;
|
|
28
|
+
if (height !== undefined)
|
|
29
|
+
attachment.height = height;
|
|
30
|
+
if (title !== undefined)
|
|
31
|
+
attachment.title = title;
|
|
32
|
+
if (name !== undefined)
|
|
33
|
+
attachment.name = name;
|
|
34
|
+
if (size !== undefined)
|
|
35
|
+
attachment.size = size;
|
|
36
|
+
if (mime !== undefined)
|
|
37
|
+
attachment.mime = mime;
|
|
38
|
+
if (duration !== undefined)
|
|
39
|
+
attachment.duration = duration;
|
|
40
|
+
if (ref !== undefined)
|
|
41
|
+
attachment.providerRef = ref;
|
|
42
|
+
return attachment;
|
|
43
|
+
};
|
|
44
|
+
export const toMessage = (message) => ({
|
|
45
|
+
id: message.id,
|
|
46
|
+
chatId: message.chat,
|
|
47
|
+
senderId: message.sender,
|
|
48
|
+
senderName: message.senderName,
|
|
49
|
+
timestamp: message.timestamp,
|
|
50
|
+
editedAt: message.editedAt,
|
|
51
|
+
text: message.text,
|
|
52
|
+
outgoing: message.fromMe,
|
|
53
|
+
attachments: message.attachments?.map(toAttachment) ?? [],
|
|
54
|
+
replyTo: null,
|
|
55
|
+
...(message.replyTo === null ? {} : { replyToId: message.replyTo }),
|
|
56
|
+
forwardedFrom: null,
|
|
57
|
+
reactions: null,
|
|
58
|
+
// Kept with the message in the store: a vote names answers by text, and only the poll's message has them.
|
|
59
|
+
...(message.poll === undefined ? {} : { providerMetadata: { poll: message.poll } }),
|
|
60
|
+
});
|
|
61
|
+
/** A stored attachment as the engine takes it back, or `undefined` when it is not one this engine wrote. */
|
|
62
|
+
export const toWaAttachment = ({ providerRef, ...attachment }) => {
|
|
63
|
+
const parsed = v.safeParse(waAttachment, {
|
|
64
|
+
kind: attachment.kind,
|
|
65
|
+
...Object.fromEntries(["url", "width", "height", "title", "name", "size", "mime", "duration"]
|
|
66
|
+
.filter((field) => attachment[field] !== undefined && attachment[field] !== null)
|
|
67
|
+
.map((field) => [field, attachment[field]])),
|
|
68
|
+
...(providerRef ? { ref: providerRef } : {}),
|
|
69
|
+
});
|
|
70
|
+
return parsed.success ? parsed.output : undefined;
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../../src/adapter/map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Message, type PollVoteEvent } from "@wirecat/cli-core";
|
|
2
|
+
import type { HistoryVote, MessagePolls, StoredMessages } from "@wirecat/cli-core/cli";
|
|
3
|
+
import { type WaKey, type WaVote, type WhatsAppEngine } from "../engine/contract.js";
|
|
4
|
+
export type PollAdapter = Omit<MessagePolls, "closePoll">;
|
|
5
|
+
/** A live vote, for a poll the store holds; one for a poll it does not hold is dropped. */
|
|
6
|
+
export declare const toVoteEvent: (vote: WaVote, chatTitle: string | null, stored: StoredMessages) => Promise<PollVoteEvent | undefined>;
|
|
7
|
+
/** A vote from a history push, counted by the poll it carries. */
|
|
8
|
+
export declare const toHistoryVote: (vote: WaVote) => HistoryVote | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Polls as WhatsApp has them: everyone in the chat sees who voted for what, a vote can always be changed, and a poll
|
|
11
|
+
* neither closes nor is a quiz. A poll is read from the store, which holds the message that carries it and each
|
|
12
|
+
* voter's newest vote; WhatsApp has no request for either.
|
|
13
|
+
*/
|
|
14
|
+
export declare const pollAdapter: ({ engine, stored, held, keyOf, translated, }: {
|
|
15
|
+
engine: WhatsAppEngine;
|
|
16
|
+
stored: StoredMessages;
|
|
17
|
+
held: (chatId: string, messageId: string) => Promise<Message>;
|
|
18
|
+
keyOf: (chatId: string, message: Message) => WaKey;
|
|
19
|
+
translated: <T>(work: Promise<T>) => Promise<T>;
|
|
20
|
+
}) => PollAdapter;
|
|
21
|
+
//# sourceMappingURL=polls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polls.d.ts","sourceRoot":"","sources":["../../src/adapter/polls.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAC3G,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtF,OAAO,EAAE,KAAK,KAAK,EAAe,KAAK,MAAM,EAAE,KAAK,cAAc,EAAU,MAAM,uBAAuB,CAAA;AAIzG,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAA;AAwCzD,2FAA2F;AAC3F,eAAO,MAAM,WAAW,SAChB,MAAM,aACD,MAAM,GAAG,IAAI,UAChB,cAAc,KACrB,OAAO,CAAC,aAAa,GAAG,SAAS,CAInC,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,WAAW,GAAG,SAG1D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,iDAMrB;IACD,MAAM,EAAE,cAAc,CAAA;IACtB,MAAM,EAAE,cAAc,CAAA;IACtB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7D,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK,CAAA;IAClD,UAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;CAChD,KAAG,WA+DF,CAAA"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
import { countedPoll } from "@wirecat/cli-core";
|
|
3
|
+
import * as v from "valibot";
|
|
4
|
+
import { waPoll } from "../engine/contract.js";
|
|
5
|
+
import { toMessage } from "./map.js";
|
|
6
|
+
const pollIn = (message) => {
|
|
7
|
+
const parsed = v.safeParse(waPoll, message?.providerMetadata?.poll);
|
|
8
|
+
return parsed.success ? parsed.output : undefined;
|
|
9
|
+
};
|
|
10
|
+
const pollOf = (message) => {
|
|
11
|
+
const poll = pollIn(message);
|
|
12
|
+
if (!poll)
|
|
13
|
+
throw new CliError("not_found", `message ${message.id} carries no poll`);
|
|
14
|
+
return poll;
|
|
15
|
+
};
|
|
16
|
+
/** The poll as its message carries it, before the votes the store keeps are counted in. */
|
|
17
|
+
const toPoll = (chatId, message, poll) => ({
|
|
18
|
+
chatId,
|
|
19
|
+
messageId: message.id,
|
|
20
|
+
question: poll.question,
|
|
21
|
+
answers: poll.answers.map(({ id, text }) => ({ id, text, voters: null, chosen: false })),
|
|
22
|
+
closed: false,
|
|
23
|
+
multiple: poll.multiple,
|
|
24
|
+
anonymous: false,
|
|
25
|
+
voters: null,
|
|
26
|
+
quiz: false,
|
|
27
|
+
revote: true,
|
|
28
|
+
creator: message.outgoing === true,
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* A vote as cli-core keeps it. WhatsApp names each chosen answer by the full hash of its text, an answer id is the
|
|
32
|
+
* start of it. A vote whose answers this poll does not have is dropped rather than kept as a vote taken back.
|
|
33
|
+
*/
|
|
34
|
+
const toPollVote = (vote, poll) => {
|
|
35
|
+
const answers = poll.answers
|
|
36
|
+
.filter((answer) => vote.selected.some((hash) => hash.startsWith(answer.id)))
|
|
37
|
+
.map((answer) => answer.id);
|
|
38
|
+
if (answers.length === 0 && vote.selected.length > 0)
|
|
39
|
+
return undefined;
|
|
40
|
+
return { person: { id: vote.voter, name: vote.voterName, username: null }, answers, votedAt: vote.votedAt };
|
|
41
|
+
};
|
|
42
|
+
/** A live vote, for a poll the store holds; one for a poll it does not hold is dropped. */
|
|
43
|
+
export const toVoteEvent = async (vote, chatTitle, stored) => {
|
|
44
|
+
const poll = pollIn(await stored.message(vote.chat, vote.message).catch(() => undefined));
|
|
45
|
+
const counted = poll && toPollVote(vote, poll);
|
|
46
|
+
return counted && { event: "vote", chatId: vote.chat, chatTitle, messageId: vote.message, vote: counted };
|
|
47
|
+
};
|
|
48
|
+
/** A vote from a history push, counted by the poll it carries. */
|
|
49
|
+
export const toHistoryVote = (vote) => {
|
|
50
|
+
const counted = vote.poll && toPollVote(vote, vote.poll);
|
|
51
|
+
return counted && { chatId: vote.chat, messageId: vote.message, vote: counted };
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Polls as WhatsApp has them: everyone in the chat sees who voted for what, a vote can always be changed, and a poll
|
|
55
|
+
* neither closes nor is a quiz. A poll is read from the store, which holds the message that carries it and each
|
|
56
|
+
* voter's newest vote; WhatsApp has no request for either.
|
|
57
|
+
*/
|
|
58
|
+
export const pollAdapter = ({ engine, stored, held, keyOf, translated, }) => ({
|
|
59
|
+
poll: async (chatId, messageId) => {
|
|
60
|
+
const message = await held(chatId, messageId);
|
|
61
|
+
return countedPoll(toPoll(chatId, message, pollOf(message)), await stored.pollVotes(chatId, messageId), engine.self());
|
|
62
|
+
},
|
|
63
|
+
// cli-core keeps this vote only after it returns, so the answer counts it in itself.
|
|
64
|
+
vote: async (chatId, messageId, answerIds) => {
|
|
65
|
+
const message = await held(chatId, messageId);
|
|
66
|
+
const poll = pollOf(message);
|
|
67
|
+
const known = new Map(poll.answers.map((answer) => [answer.id, answer.text]));
|
|
68
|
+
const unknown = answerIds.filter((answer) => !known.has(answer));
|
|
69
|
+
if (unknown.length > 0)
|
|
70
|
+
throw new CliError("validation_error", `${unknown.join(", ")} ${unknown.length === 1 ? "is" : "are"} not an answer of this poll — its answers are ${[...known.keys()].join(", ")}`);
|
|
71
|
+
if (answerIds.length > 1 && !poll.multiple)
|
|
72
|
+
throw new CliError("validation_error", "this poll takes one answer; give one id");
|
|
73
|
+
await translated(engine.vote(keyOf(chatId, message), answerIds.map((answer) => known.get(answer))));
|
|
74
|
+
const self = engine.self();
|
|
75
|
+
const others = (await stored.pollVotes(chatId, messageId)).filter((vote) => vote.person.id !== self);
|
|
76
|
+
const mine = self === null
|
|
77
|
+
? []
|
|
78
|
+
: [{ person: { id: self, name: null, username: null }, answers: answerIds, votedAt: new Date().toISOString() }];
|
|
79
|
+
return countedPoll(toPoll(chatId, message, poll), [...mine, ...others], self);
|
|
80
|
+
},
|
|
81
|
+
pollVoters: async (chatId, messageId, { limit, answerId }) => {
|
|
82
|
+
await held(chatId, messageId);
|
|
83
|
+
const voters = (await stored.pollVotes(chatId, messageId)).filter((vote) => vote.answers.length > 0 && (answerId === undefined || vote.answers.includes(answerId)));
|
|
84
|
+
return { items: voters.slice(0, limit), hasMore: voters.length > limit, total: voters.length };
|
|
85
|
+
},
|
|
86
|
+
createPoll: async (chatId, poll, { sendId, threadId }) => {
|
|
87
|
+
if (poll.quiz !== undefined || poll.closeAfter !== undefined)
|
|
88
|
+
throw new CliError("validation_error", "WhatsApp polls are neither quizzes nor close by themselves");
|
|
89
|
+
if (threadId !== undefined)
|
|
90
|
+
throw new CliError("validation_error", "WhatsApp sends a poll without a topic");
|
|
91
|
+
if (new Set(poll.answers).size < poll.answers.length)
|
|
92
|
+
throw new CliError("validation_error", "each answer needs text of its own: WhatsApp counts a vote by it");
|
|
93
|
+
const message = await translated(engine.createPoll({
|
|
94
|
+
chat: chatId,
|
|
95
|
+
id: sendId,
|
|
96
|
+
question: poll.question,
|
|
97
|
+
answers: poll.answers,
|
|
98
|
+
multiple: poll.multiple,
|
|
99
|
+
}));
|
|
100
|
+
return { message: toMessage(message), sendId };
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=polls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polls.js","sourceRoot":"","sources":["../../src/adapter/polls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAA8D,MAAM,mBAAmB,CAAA;AAE3G,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAA6D,MAAM,EAAE,MAAM,uBAAuB,CAAA;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAKpC,MAAM,MAAM,GAAG,CAAC,OAA4B,EAAsB,EAAE;IAClE,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAA;IACnE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;AACnD,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,OAAgB,EAAU,EAAE;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAC5B,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,WAAW,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAA;IACnF,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED,2FAA2F;AAC3F,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,OAAgB,EAAE,IAAY,EAAQ,EAAE,CAAC,CAAC;IACxE,MAAM;IACN,SAAS,EAAE,OAAO,CAAC,EAAE;IACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;IACvB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACxF,MAAM,EAAE,KAAK;IACb,QAAQ,EAAE,IAAI,CAAC,QAAQ;IACvB,SAAS,EAAE,KAAK;IAChB,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,KAAK;IACX,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI;CACnC,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,IAAY,EAAwB,EAAE;IACtE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;SACzB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5E,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAA;IACtE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;AAC7G,CAAC,CAAA;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,IAAY,EACZ,SAAwB,EACxB,MAAsB,EACc,EAAE;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IACzF,MAAM,OAAO,GAAG,IAAI,IAAI,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC9C,OAAO,OAAO,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAC3G,CAAC,CAAA;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAA2B,EAAE;IACrE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IACxD,OAAO,OAAO,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AACjF,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAC1B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,UAAU,GAOX,EAAe,EAAE,CAAC,CAAC;IAClB,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC7C,OAAO,WAAW,CAChB,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,EACxC,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,EACzC,MAAM,CAAC,IAAI,EAAE,CACd,CAAA;IACH,CAAC;IAED,qFAAqF;IACrF,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC7E,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;QAChE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YACpB,MAAM,IAAI,QAAQ,CAChB,kBAAkB,EAClB,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,iDAAiD,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5I,CAAA;QACH,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;YACxC,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,yCAAyC,CAAC,CAAA;QACnF,MAAM,UAAU,CACd,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,EACtB,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAW,CAAC,CACvD,CACF,CAAA;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;QAC1B,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,CAAA;QACpG,MAAM,IAAI,GACR,IAAI,KAAK,IAAI;YACX,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QACnH,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,CAAA;IAC/E,CAAC;IAED,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3D,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC7B,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAC/D,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CACjG,CAAA;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;IAChG,CAAC;IAED,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;QACvD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YAC1D,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,4DAA4D,CAAC,CAAA;QACtG,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,uCAAuC,CAAC,CAAA;QAC3G,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM;YAClD,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,iEAAiE,CAAC,CAAA;QAC3G,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,MAAM,CAAC,UAAU,CAAC;YAChB,IAAI,EAAE,MAAM;YACZ,EAAE,EAAE,MAAM;YACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CACH,CAAA;QACD,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAChD,CAAC;CACF,CAAC,CAAA"}
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AppIdentity } from "@wirecat/cli-core/cli";
|
|
2
|
+
import { type Configuration } from "@wirecat/cli-core/cli";
|
|
3
|
+
export declare const WA: AppIdentity;
|
|
4
|
+
export declare const CONFIG: Configuration;
|
|
5
|
+
export declare const resolveSettings: (flags?: import("@wirecat/cli-core/cli").GlobalFlags, options?: import("@wirecat/cli-core/cli").ResolveOptions) => import("@wirecat/cli-core/cli").Settings & object;
|
|
6
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,KAAK,aAAa,EAAe,MAAM,uBAAuB,CAAA;AAIvE,eAAO,MAAM,EAAE,EAAE,WAShB,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,aAA+B,CAAA;AACpD,eAAO,MAAQ,eAAe,sKAAW,CAAA"}
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { settingsFor } from "@wirecat/cli-core/cli";
|
|
2
|
+
import { REASONS } from "./reasons.js";
|
|
3
|
+
import { VERSION } from "./version.js";
|
|
4
|
+
export const WA = {
|
|
5
|
+
command: "wa",
|
|
6
|
+
appName: "whatsapp-cli",
|
|
7
|
+
envPrefix: "WA",
|
|
8
|
+
description: "A personal WhatsApp account from the command line, as a linked device, for agents and scripts",
|
|
9
|
+
version: VERSION,
|
|
10
|
+
issues: "https://github.com/WireCatLabs/whatsapp-cli/issues/new",
|
|
11
|
+
locale: "en-GB",
|
|
12
|
+
errors: { reasons: REASONS },
|
|
13
|
+
};
|
|
14
|
+
export const CONFIG = settingsFor(WA);
|
|
15
|
+
export const { resolveSettings } = CONFIG;
|
|
16
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,EAAE,GAAgB;IAC7B,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,cAAc;IACvB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,+FAA+F;IAC5G,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,wDAAwD;IAChE,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE;CAC7B,CAAA;AAED,MAAM,CAAC,MAAM,MAAM,GAAkB,WAAW,CAAC,EAAE,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAAA"}
|
package/dist/bin/wa.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wa.d.ts","sourceRoot":"","sources":["../../src/bin/wa.ts"],"names":[],"mappings":""}
|
package/dist/bin/wa.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { enableCompileCache } from "node:module";
|
|
3
|
+
import { catchCrashes } from "@wirecat/cli-base";
|
|
4
|
+
import { ensureSqlite } from "@wirecat/cli-core/sqlite-runtime";
|
|
5
|
+
import { WA } from "../app.js";
|
|
6
|
+
// `wa chats --json | head` closes the pipe while we are still writing, and an unhandled EPIPE
|
|
7
|
+
// makes Node print a stack trace over the output of the command that just worked. A reader that
|
|
8
|
+
// stopped reading is not an error: leave quietly, as every other Unix tool does.
|
|
9
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
10
|
+
stream.on("error", (error) => {
|
|
11
|
+
if (error.code === "EPIPE") {
|
|
12
|
+
if (stream.listenerCount("error") === 1)
|
|
13
|
+
process.exit(0);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
// Compiling the module files is most of a start; later runs reuse what this one compiled.
|
|
20
|
+
enableCompileCache();
|
|
21
|
+
const stopCatching = catchCrashes({ cli: WA.command, interactive: process.stdout.isTTY === true });
|
|
22
|
+
await ensureSqlite();
|
|
23
|
+
stopCatching();
|
|
24
|
+
// A static import would load the whole program, and its SQLite, before ensureSqlite could swap it.
|
|
25
|
+
const { run } = await import("../program.js");
|
|
26
|
+
process.exitCode = await run(process.argv.slice(2));
|
|
27
|
+
//# sourceMappingURL=wa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wa.js","sourceRoot":"","sources":["../../src/bin/wa.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC/D,OAAO,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAE9B,8FAA8F;AAC9F,gGAAgG;AAChG,iFAAiF;AACjF,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACtD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;QAClD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,IAAI,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACxD,OAAM;QACR,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,0FAA0F;AAC1F,kBAAkB,EAAE,CAAA;AACpB,MAAM,YAAY,GAAG,YAAY,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,CAAA;AAClG,MAAM,YAAY,EAAE,CAAA;AACpB,YAAY,EAAE,CAAA;AACd,mGAAmG;AACnG,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;AAC7C,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Renderer, RenderFormat } from "@wirecat/cli-base";
|
|
2
|
+
export declare const itemAnswer: <T>(item: T) => import("@wirecat/cli-core/cli").ItemBody<T>;
|
|
3
|
+
export declare const printItem: ({ renderer, format }: {
|
|
4
|
+
renderer: Renderer;
|
|
5
|
+
format: RenderFormat;
|
|
6
|
+
}, item: unknown) => void;
|
|
7
|
+
//# sourceMappingURL=answer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/commands/answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAG/D,eAAO,MAAM,UAAU,GAAI,CAAC,QAAQ,CAAC,gDAAyB,CAAA;AAE9D,eAAO,MAAM,SAAS,yBAA0B;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,QAAQ,OAAO,KAAG,IAI7G,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { itemOf, jsonlRecords, sealed } from "@wirecat/cli-core/cli";
|
|
2
|
+
export const itemAnswer = (item) => sealed(itemOf(item));
|
|
3
|
+
export const printItem = ({ renderer, format }, item) => {
|
|
4
|
+
if (format === "json")
|
|
5
|
+
renderer.result(itemAnswer(item));
|
|
6
|
+
else if (format === "jsonl")
|
|
7
|
+
renderer.stream(jsonlRecords(itemOf(item)));
|
|
8
|
+
else
|
|
9
|
+
renderer.result(item);
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=answer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer.js","sourceRoot":"","sources":["../../src/commands/answer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAEpE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAI,IAAO,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;AAE9D,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAgD,EAAE,IAAa,EAAQ,EAAE;IACnH,IAAI,MAAM,KAAK,MAAM;QAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;SACnD,IAAI,MAAM,KAAK,OAAO;QAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;;QACnE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAC5B,CAAC,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Closeable, type MessengerContext } from "@wirecat/cli-core/cli";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
/** The phone pushes its history right after linking, once; how long to keep receiving it. */
|
|
4
|
+
export declare const HISTORY_WAIT: {
|
|
5
|
+
firstMs: number;
|
|
6
|
+
quietMs: number;
|
|
7
|
+
};
|
|
8
|
+
export interface Received {
|
|
9
|
+
chats: number;
|
|
10
|
+
messages: number;
|
|
11
|
+
people: number;
|
|
12
|
+
}
|
|
13
|
+
export interface StartSessionOptions {
|
|
14
|
+
method: "qr" | "phone";
|
|
15
|
+
qrFile?: string;
|
|
16
|
+
/** The command as typed, for the messages that name it. */
|
|
17
|
+
command?: string;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
/** How far the questions and the QR code sit right, to line up under a setup step. */
|
|
20
|
+
indent?: number;
|
|
21
|
+
/** Each connection, as it opens, for the caller's deadline to close. */
|
|
22
|
+
track?: (closeable: Closeable) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface Session {
|
|
25
|
+
profile: string;
|
|
26
|
+
account: {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string | null;
|
|
29
|
+
};
|
|
30
|
+
alreadyLinked: boolean;
|
|
31
|
+
/** Left out for a device linked before: nothing was pushed, so nothing was counted. */
|
|
32
|
+
received?: Received;
|
|
33
|
+
}
|
|
34
|
+
/** Links the profile's device unless it is linked already, then keeps the history the phone pushes once. */
|
|
35
|
+
export declare const startSession: (command: Command, context: MessengerContext, { method, qrFile, command: typed, signal, indent: pad, track }: StartSessionOptions) => Promise<Session>;
|
|
36
|
+
export declare const sessionCommand: () => Command;
|
|
37
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/commands/session.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,SAAS,EAKd,KAAK,gBAAgB,EAKtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAY,OAAO,EAAE,MAAM,WAAW,CAAA;AAK7C,6FAA6F;AAC7F,eAAO,MAAM,YAAY;IAAK,OAAO;IAAW,OAAO;CAAU,CAAA;AAEjE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAkDD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wEAAwE;IACxE,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;CACvC;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IAC5C,aAAa,EAAE,OAAO,CAAA;IACtB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AAED,4GAA4G;AAC5G,eAAO,MAAM,YAAY,YACd,OAAO,WACP,gBAAgB,kEACgE,mBAAmB,KAC3G,OAAO,CAAC,OAAO,CAiFjB,CAAA;AA6BD,eAAO,MAAM,cAAc,eAkD1B,CAAA"}
|