@cli4ai/gmail 1.0.7 → 1.0.8
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/package.json +1 -3
- package/lib/api.test.ts +0 -287
- package/lib/api.ts +0 -299
- package/lib/attachments.ts +0 -199
- package/lib/drafts.ts +0 -434
- package/lib/labels.ts +0 -198
- package/lib/messages.ts +0 -310
- package/lib/send.ts +0 -331
- package/lib/threads.ts +0 -164
package/lib/labels.ts
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { getGmail, output, type OutputOptions } from './api';
|
|
2
|
-
|
|
3
|
-
/** Label data */
|
|
4
|
-
export interface LabelData {
|
|
5
|
-
id: string;
|
|
6
|
-
name: string;
|
|
7
|
-
type?: string;
|
|
8
|
-
messageListVisibility?: string;
|
|
9
|
-
labelListVisibility?: string;
|
|
10
|
-
messagesTotal?: number;
|
|
11
|
-
messagesUnread?: number;
|
|
12
|
-
threadsTotal?: number;
|
|
13
|
-
threadsUnread?: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Label action result */
|
|
17
|
-
export interface LabelActionResult {
|
|
18
|
-
ok: boolean;
|
|
19
|
-
id?: string;
|
|
20
|
-
name?: string;
|
|
21
|
-
messageId?: string;
|
|
22
|
-
labelAdded?: string;
|
|
23
|
-
labelRemoved?: string;
|
|
24
|
-
deleted?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* List all labels
|
|
29
|
-
*/
|
|
30
|
-
export async function list(options: OutputOptions = {}): Promise<LabelData[]> {
|
|
31
|
-
const gmail = await getGmail();
|
|
32
|
-
|
|
33
|
-
const res = await gmail.users.labels.list({
|
|
34
|
-
userId: 'me'
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const labels: LabelData[] = (res.data.labels || []).map(label => ({
|
|
38
|
-
id: label.id!,
|
|
39
|
-
name: label.name!,
|
|
40
|
-
type: label.type || undefined,
|
|
41
|
-
messageListVisibility: label.messageListVisibility || undefined,
|
|
42
|
-
labelListVisibility: label.labelListVisibility || undefined
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
// Sort: system labels first, then user labels
|
|
46
|
-
labels.sort((a, b) => {
|
|
47
|
-
if (a.type === 'system' && b.type !== 'system') return -1;
|
|
48
|
-
if (a.type !== 'system' && b.type === 'system') return 1;
|
|
49
|
-
return a.name.localeCompare(b.name);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
output(labels, options);
|
|
53
|
-
return labels;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Get label details with counts
|
|
58
|
-
*/
|
|
59
|
-
export async function get(labelId: string, options: OutputOptions = {}): Promise<LabelData> {
|
|
60
|
-
const gmail = await getGmail();
|
|
61
|
-
|
|
62
|
-
// Resolve label name to ID if needed
|
|
63
|
-
const resolvedId = await resolveLabelId(gmail, labelId);
|
|
64
|
-
|
|
65
|
-
const res = await gmail.users.labels.get({
|
|
66
|
-
userId: 'me',
|
|
67
|
-
id: resolvedId
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const label: LabelData = {
|
|
71
|
-
id: res.data.id!,
|
|
72
|
-
name: res.data.name!,
|
|
73
|
-
type: res.data.type || undefined,
|
|
74
|
-
messagesTotal: res.data.messagesTotal || undefined,
|
|
75
|
-
messagesUnread: res.data.messagesUnread || undefined,
|
|
76
|
-
threadsTotal: res.data.threadsTotal || undefined,
|
|
77
|
-
threadsUnread: res.data.threadsUnread || undefined
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
output(label, options);
|
|
81
|
-
return label;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Add label to message
|
|
86
|
-
*/
|
|
87
|
-
export async function addToMessage(messageId: string, labelName: string, options: OutputOptions = {}): Promise<LabelActionResult> {
|
|
88
|
-
const gmail = await getGmail();
|
|
89
|
-
|
|
90
|
-
const labelId = await resolveLabelId(gmail, labelName);
|
|
91
|
-
|
|
92
|
-
await gmail.users.messages.modify({
|
|
93
|
-
userId: 'me',
|
|
94
|
-
id: messageId,
|
|
95
|
-
requestBody: {
|
|
96
|
-
addLabelIds: [labelId]
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
const result: LabelActionResult = { ok: true, messageId, labelAdded: labelName };
|
|
101
|
-
output(result, options);
|
|
102
|
-
return result;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Remove label from message
|
|
107
|
-
*/
|
|
108
|
-
export async function removeFromMessage(messageId: string, labelName: string, options: OutputOptions = {}): Promise<LabelActionResult> {
|
|
109
|
-
const gmail = await getGmail();
|
|
110
|
-
|
|
111
|
-
const labelId = await resolveLabelId(gmail, labelName);
|
|
112
|
-
|
|
113
|
-
await gmail.users.messages.modify({
|
|
114
|
-
userId: 'me',
|
|
115
|
-
id: messageId,
|
|
116
|
-
requestBody: {
|
|
117
|
-
removeLabelIds: [labelId]
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
const result: LabelActionResult = { ok: true, messageId, labelRemoved: labelName };
|
|
122
|
-
output(result, options);
|
|
123
|
-
return result;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Create a new label
|
|
128
|
-
*/
|
|
129
|
-
export async function create(labelName: string, options: OutputOptions = {}): Promise<LabelActionResult> {
|
|
130
|
-
const gmail = await getGmail();
|
|
131
|
-
|
|
132
|
-
const res = await gmail.users.labels.create({
|
|
133
|
-
userId: 'me',
|
|
134
|
-
requestBody: {
|
|
135
|
-
name: labelName,
|
|
136
|
-
labelListVisibility: 'labelShow',
|
|
137
|
-
messageListVisibility: 'show'
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const result: LabelActionResult = {
|
|
142
|
-
ok: true,
|
|
143
|
-
id: res.data.id!,
|
|
144
|
-
name: res.data.name!
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
output(result, options);
|
|
148
|
-
return result;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Delete a label
|
|
153
|
-
*/
|
|
154
|
-
export async function remove(labelName: string, options: OutputOptions = {}): Promise<LabelActionResult> {
|
|
155
|
-
const gmail = await getGmail();
|
|
156
|
-
|
|
157
|
-
const labelId = await resolveLabelId(gmail, labelName);
|
|
158
|
-
|
|
159
|
-
// Don't allow deleting system labels
|
|
160
|
-
const systemLabels = ['INBOX', 'SENT', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT', 'DRAFT'];
|
|
161
|
-
if (labelId.startsWith('CATEGORY_') || systemLabels.includes(labelId)) {
|
|
162
|
-
throw new Error(`Cannot delete system label: ${labelName}`);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
await gmail.users.labels.delete({
|
|
166
|
-
userId: 'me',
|
|
167
|
-
id: labelId
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const result: LabelActionResult = { ok: true, deleted: labelName };
|
|
171
|
-
output(result, options);
|
|
172
|
-
return result;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Resolve label name to ID
|
|
177
|
-
*/
|
|
178
|
-
async function resolveLabelId(gmail: ReturnType<typeof import('googleapis').google.gmail>, labelNameOrId: string): Promise<string> {
|
|
179
|
-
// Check if already an ID (system labels or Label_xxx format)
|
|
180
|
-
const systemLabels = ['INBOX', 'SENT', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT', 'DRAFT', 'CHAT'];
|
|
181
|
-
if (labelNameOrId.startsWith('Label_') ||
|
|
182
|
-
labelNameOrId.startsWith('CATEGORY_') ||
|
|
183
|
-
systemLabels.includes(labelNameOrId.toUpperCase())) {
|
|
184
|
-
return labelNameOrId.toUpperCase();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Look up by name
|
|
188
|
-
const res = await gmail.users.labels.list({ userId: 'me' });
|
|
189
|
-
const label = res.data.labels?.find(
|
|
190
|
-
l => l.name?.toLowerCase() === labelNameOrId.toLowerCase()
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
if (!label) {
|
|
194
|
-
throw new Error(`Label not found: ${labelNameOrId}`);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return label.id!;
|
|
198
|
-
}
|
package/lib/messages.ts
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
import { getGmail, output, formatDate, extractHeaders, extractBody, cleanBody, type OutputOptions, type MessagePayload } from './api';
|
|
2
|
-
|
|
3
|
-
/** Message summary */
|
|
4
|
-
export interface MessageSummary {
|
|
5
|
-
id: string;
|
|
6
|
-
threadId?: string;
|
|
7
|
-
date: string | null;
|
|
8
|
-
from: string;
|
|
9
|
-
to: string;
|
|
10
|
-
subject: string;
|
|
11
|
-
snippet?: string;
|
|
12
|
-
labels?: string[];
|
|
13
|
-
unread?: boolean;
|
|
14
|
-
starred?: boolean;
|
|
15
|
-
important?: boolean;
|
|
16
|
-
body?: string;
|
|
17
|
-
cc?: string | null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Action result */
|
|
21
|
-
export interface ActionResult {
|
|
22
|
-
ok: boolean;
|
|
23
|
-
archived?: string;
|
|
24
|
-
trashed?: string;
|
|
25
|
-
untrashed?: string;
|
|
26
|
-
starred?: string;
|
|
27
|
-
unstarred?: string;
|
|
28
|
-
markedRead?: string;
|
|
29
|
-
markedUnread?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Message list options */
|
|
33
|
-
export interface MessageListOptions extends OutputOptions {
|
|
34
|
-
limit?: number;
|
|
35
|
-
body?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* List inbox messages
|
|
40
|
-
*/
|
|
41
|
-
export async function inbox(options: MessageListOptions = {}): Promise<MessageSummary[]> {
|
|
42
|
-
const gmail = await getGmail();
|
|
43
|
-
const limit = options.limit || 20;
|
|
44
|
-
|
|
45
|
-
const res = await gmail.users.messages.list({
|
|
46
|
-
userId: 'me',
|
|
47
|
-
maxResults: limit,
|
|
48
|
-
labelIds: ['INBOX']
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (!res.data.messages || res.data.messages.length === 0) {
|
|
52
|
-
output([], options);
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const messages = await Promise.all(
|
|
57
|
-
res.data.messages.map(msg => getMessageSummary(gmail, msg.id!, options))
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
output(messages, options);
|
|
61
|
-
return messages;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* List unread messages
|
|
66
|
-
*/
|
|
67
|
-
export async function unread(options: MessageListOptions = {}): Promise<MessageSummary[]> {
|
|
68
|
-
const gmail = await getGmail();
|
|
69
|
-
const limit = options.limit || 20;
|
|
70
|
-
|
|
71
|
-
const res = await gmail.users.messages.list({
|
|
72
|
-
userId: 'me',
|
|
73
|
-
maxResults: limit,
|
|
74
|
-
q: 'is:unread'
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
if (!res.data.messages || res.data.messages.length === 0) {
|
|
78
|
-
output([], options);
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const messages = await Promise.all(
|
|
83
|
-
res.data.messages.map(msg => getMessageSummary(gmail, msg.id!, options))
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
output(messages, options);
|
|
87
|
-
return messages;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Search messages with Gmail query syntax
|
|
92
|
-
*/
|
|
93
|
-
export async function search(query: string, options: MessageListOptions = {}): Promise<MessageSummary[]> {
|
|
94
|
-
const gmail = await getGmail();
|
|
95
|
-
const limit = options.limit || 20;
|
|
96
|
-
|
|
97
|
-
const res = await gmail.users.messages.list({
|
|
98
|
-
userId: 'me',
|
|
99
|
-
maxResults: limit,
|
|
100
|
-
q: query
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
if (!res.data.messages || res.data.messages.length === 0) {
|
|
104
|
-
output([], options);
|
|
105
|
-
return [];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const messages = await Promise.all(
|
|
109
|
-
res.data.messages.map(msg => getMessageSummary(gmail, msg.id!, options))
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
output(messages, options);
|
|
113
|
-
return messages;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Get message summary (for list views)
|
|
118
|
-
*/
|
|
119
|
-
async function getMessageSummary(gmail: ReturnType<typeof import('googleapis').google.gmail>, messageId: string, options: MessageListOptions = {}): Promise<MessageSummary> {
|
|
120
|
-
const res = await gmail.users.messages.get({
|
|
121
|
-
userId: 'me',
|
|
122
|
-
id: messageId,
|
|
123
|
-
format: options.body ? 'full' : 'metadata',
|
|
124
|
-
metadataHeaders: ['From', 'To', 'Subject', 'Date']
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const headers = extractHeaders(res.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
128
|
-
const labels = res.data.labelIds || [];
|
|
129
|
-
|
|
130
|
-
const summary: MessageSummary = {
|
|
131
|
-
id: res.data.id!,
|
|
132
|
-
threadId: res.data.threadId || undefined,
|
|
133
|
-
date: formatDate(res.data.internalDate),
|
|
134
|
-
from: headers.from || '',
|
|
135
|
-
to: headers.to || '',
|
|
136
|
-
subject: headers.subject || '(no subject)',
|
|
137
|
-
snippet: res.data.snippet || '',
|
|
138
|
-
labels: labels,
|
|
139
|
-
unread: labels.includes('UNREAD'),
|
|
140
|
-
starred: labels.includes('STARRED'),
|
|
141
|
-
important: labels.includes('IMPORTANT')
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
if (options.body) {
|
|
145
|
-
summary.body = cleanBody(extractBody(res.data.payload as MessagePayload), 1000);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return summary;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Read a full message
|
|
153
|
-
*/
|
|
154
|
-
export async function read(messageId: string, options: OutputOptions = {}): Promise<MessageSummary> {
|
|
155
|
-
const gmail = await getGmail();
|
|
156
|
-
|
|
157
|
-
const res = await gmail.users.messages.get({
|
|
158
|
-
userId: 'me',
|
|
159
|
-
id: messageId,
|
|
160
|
-
format: 'full'
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
const headers = extractHeaders(res.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
164
|
-
const labels = res.data.labelIds || [];
|
|
165
|
-
const body = extractBody(res.data.payload as MessagePayload);
|
|
166
|
-
|
|
167
|
-
const message: MessageSummary = {
|
|
168
|
-
id: res.data.id!,
|
|
169
|
-
threadId: res.data.threadId || undefined,
|
|
170
|
-
date: formatDate(res.data.internalDate),
|
|
171
|
-
from: headers.from || '',
|
|
172
|
-
to: headers.to || '',
|
|
173
|
-
cc: headers.cc || null,
|
|
174
|
-
subject: headers.subject || '(no subject)',
|
|
175
|
-
body: body,
|
|
176
|
-
labels: labels,
|
|
177
|
-
unread: labels.includes('UNREAD'),
|
|
178
|
-
starred: labels.includes('STARRED')
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
output(message, options);
|
|
182
|
-
return message;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Archive a message (remove from INBOX)
|
|
187
|
-
*/
|
|
188
|
-
export async function archive(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
189
|
-
const gmail = await getGmail();
|
|
190
|
-
|
|
191
|
-
await gmail.users.messages.modify({
|
|
192
|
-
userId: 'me',
|
|
193
|
-
id: messageId,
|
|
194
|
-
requestBody: {
|
|
195
|
-
removeLabelIds: ['INBOX']
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const result: ActionResult = { ok: true, archived: messageId };
|
|
200
|
-
output(result, options);
|
|
201
|
-
return result;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Trash a message
|
|
206
|
-
*/
|
|
207
|
-
export async function trash(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
208
|
-
const gmail = await getGmail();
|
|
209
|
-
|
|
210
|
-
await gmail.users.messages.trash({
|
|
211
|
-
userId: 'me',
|
|
212
|
-
id: messageId
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
const result: ActionResult = { ok: true, trashed: messageId };
|
|
216
|
-
output(result, options);
|
|
217
|
-
return result;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Untrash a message
|
|
222
|
-
*/
|
|
223
|
-
export async function untrash(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
224
|
-
const gmail = await getGmail();
|
|
225
|
-
|
|
226
|
-
await gmail.users.messages.untrash({
|
|
227
|
-
userId: 'me',
|
|
228
|
-
id: messageId
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
const result: ActionResult = { ok: true, untrashed: messageId };
|
|
232
|
-
output(result, options);
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Star a message
|
|
238
|
-
*/
|
|
239
|
-
export async function star(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
240
|
-
const gmail = await getGmail();
|
|
241
|
-
|
|
242
|
-
await gmail.users.messages.modify({
|
|
243
|
-
userId: 'me',
|
|
244
|
-
id: messageId,
|
|
245
|
-
requestBody: {
|
|
246
|
-
addLabelIds: ['STARRED']
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
const result: ActionResult = { ok: true, starred: messageId };
|
|
251
|
-
output(result, options);
|
|
252
|
-
return result;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Unstar a message
|
|
257
|
-
*/
|
|
258
|
-
export async function unstar(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
259
|
-
const gmail = await getGmail();
|
|
260
|
-
|
|
261
|
-
await gmail.users.messages.modify({
|
|
262
|
-
userId: 'me',
|
|
263
|
-
id: messageId,
|
|
264
|
-
requestBody: {
|
|
265
|
-
removeLabelIds: ['STARRED']
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
const result: ActionResult = { ok: true, unstarred: messageId };
|
|
270
|
-
output(result, options);
|
|
271
|
-
return result;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Mark as read
|
|
276
|
-
*/
|
|
277
|
-
export async function markRead(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
278
|
-
const gmail = await getGmail();
|
|
279
|
-
|
|
280
|
-
await gmail.users.messages.modify({
|
|
281
|
-
userId: 'me',
|
|
282
|
-
id: messageId,
|
|
283
|
-
requestBody: {
|
|
284
|
-
removeLabelIds: ['UNREAD']
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
const result: ActionResult = { ok: true, markedRead: messageId };
|
|
289
|
-
output(result, options);
|
|
290
|
-
return result;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Mark as unread
|
|
295
|
-
*/
|
|
296
|
-
export async function markUnread(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
297
|
-
const gmail = await getGmail();
|
|
298
|
-
|
|
299
|
-
await gmail.users.messages.modify({
|
|
300
|
-
userId: 'me',
|
|
301
|
-
id: messageId,
|
|
302
|
-
requestBody: {
|
|
303
|
-
addLabelIds: ['UNREAD']
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
const result: ActionResult = { ok: true, markedUnread: messageId };
|
|
308
|
-
output(result, options);
|
|
309
|
-
return result;
|
|
310
|
-
}
|