m365-agent-cli 1.2.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 +22 -0
- package/README.md +916 -0
- package/package.json +50 -0
- package/src/cli.ts +100 -0
- package/src/commands/auto-reply.ts +182 -0
- package/src/commands/calendar.ts +576 -0
- package/src/commands/counter.ts +87 -0
- package/src/commands/create-event.ts +544 -0
- package/src/commands/delegates.ts +286 -0
- package/src/commands/delete-event.ts +321 -0
- package/src/commands/drafts.ts +502 -0
- package/src/commands/files.ts +532 -0
- package/src/commands/find.ts +195 -0
- package/src/commands/findtime.ts +270 -0
- package/src/commands/folders.ts +177 -0
- package/src/commands/forward-event.ts +49 -0
- package/src/commands/graph-calendar.ts +217 -0
- package/src/commands/login.ts +195 -0
- package/src/commands/mail.ts +950 -0
- package/src/commands/oof.ts +263 -0
- package/src/commands/outlook-categories.ts +173 -0
- package/src/commands/outlook-graph.ts +880 -0
- package/src/commands/planner.ts +1678 -0
- package/src/commands/respond.ts +291 -0
- package/src/commands/rooms.ts +210 -0
- package/src/commands/rules.ts +511 -0
- package/src/commands/schedule.ts +109 -0
- package/src/commands/send.ts +204 -0
- package/src/commands/serve.ts +14 -0
- package/src/commands/sharepoint.ts +179 -0
- package/src/commands/site-pages.ts +163 -0
- package/src/commands/subscribe.ts +103 -0
- package/src/commands/subscriptions.ts +29 -0
- package/src/commands/suggest.ts +155 -0
- package/src/commands/todo.ts +2092 -0
- package/src/commands/update-event.ts +608 -0
- package/src/commands/update.ts +88 -0
- package/src/commands/verify-token.ts +62 -0
- package/src/commands/whoami.ts +74 -0
- package/src/index.ts +190 -0
- package/src/lib/atomic-write.ts +20 -0
- package/src/lib/attach-link-spec.test.ts +24 -0
- package/src/lib/attach-link-spec.ts +70 -0
- package/src/lib/attachments.ts +79 -0
- package/src/lib/auth.ts +192 -0
- package/src/lib/calendar-range.test.ts +41 -0
- package/src/lib/calendar-range.ts +103 -0
- package/src/lib/dates.test.ts +74 -0
- package/src/lib/dates.ts +137 -0
- package/src/lib/delegate-client.test.ts +74 -0
- package/src/lib/delegate-client.ts +322 -0
- package/src/lib/ews-client.ts +3418 -0
- package/src/lib/git-commit.ts +4 -0
- package/src/lib/glitchtip-eligibility.ts +220 -0
- package/src/lib/glitchtip.ts +253 -0
- package/src/lib/global-env.ts +3 -0
- package/src/lib/graph-auth.ts +223 -0
- package/src/lib/graph-calendar-client.test.ts +118 -0
- package/src/lib/graph-calendar-client.ts +112 -0
- package/src/lib/graph-client.test.ts +107 -0
- package/src/lib/graph-client.ts +1058 -0
- package/src/lib/graph-constants.ts +12 -0
- package/src/lib/graph-directory.ts +116 -0
- package/src/lib/graph-event.ts +134 -0
- package/src/lib/graph-schedule.ts +173 -0
- package/src/lib/graph-subscriptions.ts +94 -0
- package/src/lib/graph-user-path.ts +13 -0
- package/src/lib/jwt-utils.ts +34 -0
- package/src/lib/markdown.test.ts +21 -0
- package/src/lib/markdown.ts +174 -0
- package/src/lib/mime-type.ts +106 -0
- package/src/lib/oof-client.test.ts +59 -0
- package/src/lib/oof-client.ts +122 -0
- package/src/lib/outlook-graph-client.test.ts +146 -0
- package/src/lib/outlook-graph-client.ts +649 -0
- package/src/lib/outlook-master-categories.ts +145 -0
- package/src/lib/package-info.ts +59 -0
- package/src/lib/places-client.ts +144 -0
- package/src/lib/planner-client.ts +1226 -0
- package/src/lib/rules-client.ts +178 -0
- package/src/lib/sharepoint-client.ts +101 -0
- package/src/lib/site-pages-client.ts +73 -0
- package/src/lib/todo-client.test.ts +298 -0
- package/src/lib/todo-client.ts +1309 -0
- package/src/lib/url-validation.ts +40 -0
- package/src/lib/utils.ts +45 -0
- package/src/lib/webhook-server.ts +51 -0
- package/src/test/auth.test.ts +104 -0
- package/src/test/cli.integration.test.ts +1083 -0
- package/src/test/ews-client.test.ts +268 -0
- package/src/test/mocks/index.ts +375 -0
- package/src/test/mocks/responses.ts +861 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import {
|
|
2
|
+
callGraph,
|
|
3
|
+
fetchAllPages,
|
|
4
|
+
fetchGraphRaw,
|
|
5
|
+
GraphApiError,
|
|
6
|
+
type GraphResponse,
|
|
7
|
+
graphError,
|
|
8
|
+
graphResult
|
|
9
|
+
} from './graph-client.js';
|
|
10
|
+
import { graphUserPath } from './graph-user-path.js';
|
|
11
|
+
|
|
12
|
+
function mailFoldersRoot(user?: string): string {
|
|
13
|
+
return graphUserPath(user, 'mailFolders');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function contactsRoot(user?: string): string {
|
|
17
|
+
return graphUserPath(user, 'contacts');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Graph [mailFolder](https://learn.microsoft.com/en-us/graph/api/resources/mailfolder) (subset). */
|
|
21
|
+
export interface OutlookMailFolder {
|
|
22
|
+
id: string;
|
|
23
|
+
displayName: string;
|
|
24
|
+
parentFolderId?: string;
|
|
25
|
+
childFolderCount?: number;
|
|
26
|
+
unreadItemCount?: number;
|
|
27
|
+
totalItemCount?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Graph [message](https://learn.microsoft.com/en-us/graph/api/resources/message) (subset). */
|
|
31
|
+
export interface OutlookMessage {
|
|
32
|
+
id: string;
|
|
33
|
+
subject?: string;
|
|
34
|
+
bodyPreview?: string;
|
|
35
|
+
receivedDateTime?: string;
|
|
36
|
+
sentDateTime?: string;
|
|
37
|
+
isRead?: boolean;
|
|
38
|
+
importance?: string;
|
|
39
|
+
from?: { emailAddress?: { name?: string; address?: string } };
|
|
40
|
+
toRecipients?: Array<{ emailAddress?: { name?: string; address?: string } }>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Graph [contact](https://learn.microsoft.com/en-us/graph/api/resources/contact) (subset). */
|
|
44
|
+
export interface OutlookContact {
|
|
45
|
+
id: string;
|
|
46
|
+
displayName?: string;
|
|
47
|
+
givenName?: string;
|
|
48
|
+
surname?: string;
|
|
49
|
+
emailAddresses?: Array<{ name?: string; address?: string; type?: string }>;
|
|
50
|
+
mobilePhone?: string;
|
|
51
|
+
businessPhones?: string[];
|
|
52
|
+
companyName?: string;
|
|
53
|
+
jobTitle?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function listMailFolders(token: string, user?: string): Promise<GraphResponse<OutlookMailFolder[]>> {
|
|
57
|
+
return fetchAllPages<OutlookMailFolder>(token, mailFoldersRoot(user), 'Failed to list mail folders');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Child folders of a folder (e.g. under Inbox). */
|
|
61
|
+
export async function listChildMailFolders(
|
|
62
|
+
token: string,
|
|
63
|
+
parentFolderId: string,
|
|
64
|
+
user?: string
|
|
65
|
+
): Promise<GraphResponse<OutlookMailFolder[]>> {
|
|
66
|
+
return fetchAllPages<OutlookMailFolder>(
|
|
67
|
+
token,
|
|
68
|
+
`${mailFoldersRoot(user)}/${encodeURIComponent(parentFolderId)}/childFolders`,
|
|
69
|
+
'Failed to list child mail folders'
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function getMailFolder(
|
|
74
|
+
token: string,
|
|
75
|
+
folderId: string,
|
|
76
|
+
user?: string
|
|
77
|
+
): Promise<GraphResponse<OutlookMailFolder>> {
|
|
78
|
+
try {
|
|
79
|
+
const result = await callGraph<OutlookMailFolder>(
|
|
80
|
+
token,
|
|
81
|
+
`${mailFoldersRoot(user)}/${encodeURIComponent(folderId)}`
|
|
82
|
+
);
|
|
83
|
+
if (!result.ok || !result.data) {
|
|
84
|
+
return graphError(result.error?.message || 'Failed to get mail folder', result.error?.code, result.error?.status);
|
|
85
|
+
}
|
|
86
|
+
return graphResult(result.data);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
89
|
+
return graphError(err instanceof Error ? err.message : 'Failed to get mail folder');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function createMailFolder(
|
|
94
|
+
token: string,
|
|
95
|
+
displayName: string,
|
|
96
|
+
parentFolderId: string | undefined,
|
|
97
|
+
user?: string
|
|
98
|
+
): Promise<GraphResponse<OutlookMailFolder>> {
|
|
99
|
+
const body: Record<string, unknown> = { displayName };
|
|
100
|
+
if (parentFolderId) body.parentFolderId = parentFolderId;
|
|
101
|
+
try {
|
|
102
|
+
const result = await callGraph<OutlookMailFolder>(token, mailFoldersRoot(user), {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
body: JSON.stringify(body)
|
|
105
|
+
});
|
|
106
|
+
if (!result.ok || !result.data) {
|
|
107
|
+
return graphError(
|
|
108
|
+
result.error?.message || 'Failed to create mail folder',
|
|
109
|
+
result.error?.code,
|
|
110
|
+
result.error?.status
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return graphResult(result.data);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
116
|
+
return graphError(err instanceof Error ? err.message : 'Failed to create mail folder');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function updateMailFolder(
|
|
121
|
+
token: string,
|
|
122
|
+
folderId: string,
|
|
123
|
+
displayName: string,
|
|
124
|
+
user?: string
|
|
125
|
+
): Promise<GraphResponse<OutlookMailFolder>> {
|
|
126
|
+
try {
|
|
127
|
+
const result = await callGraph<OutlookMailFolder>(
|
|
128
|
+
token,
|
|
129
|
+
`${mailFoldersRoot(user)}/${encodeURIComponent(folderId)}`,
|
|
130
|
+
{
|
|
131
|
+
method: 'PATCH',
|
|
132
|
+
body: JSON.stringify({ displayName })
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
if (!result.ok || !result.data) {
|
|
136
|
+
return graphError(
|
|
137
|
+
result.error?.message || 'Failed to update mail folder',
|
|
138
|
+
result.error?.code,
|
|
139
|
+
result.error?.status
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
return graphResult(result.data);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
145
|
+
return graphError(err instanceof Error ? err.message : 'Failed to update mail folder');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function deleteMailFolder(token: string, folderId: string, user?: string): Promise<GraphResponse<void>> {
|
|
150
|
+
try {
|
|
151
|
+
return await callGraph<void>(
|
|
152
|
+
token,
|
|
153
|
+
`${mailFoldersRoot(user)}/${encodeURIComponent(folderId)}`,
|
|
154
|
+
{ method: 'DELETE' },
|
|
155
|
+
false
|
|
156
|
+
);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
159
|
+
return graphError(err instanceof Error ? err.message : 'Failed to delete mail folder');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface MessagesQueryOptions {
|
|
164
|
+
filter?: string;
|
|
165
|
+
orderby?: string;
|
|
166
|
+
select?: string;
|
|
167
|
+
/** When set, only one page (no automatic paging). */
|
|
168
|
+
top?: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Query for `GET /me/messages` (mailbox-wide, not folder-scoped). */
|
|
172
|
+
export interface RootMailboxMessagesQuery extends MessagesQueryOptions {
|
|
173
|
+
skip?: number;
|
|
174
|
+
/**
|
|
175
|
+
* Sets OData `$search` (keyword search). Graph requires `ConsistencyLevel: eventual` on the request.
|
|
176
|
+
* Do not combine with `$filter` on the same request (Graph limitation).
|
|
177
|
+
*/
|
|
178
|
+
search?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Graph [attachment](https://learn.microsoft.com/en-us/graph/api/resources/attachment) on a message (subset). */
|
|
182
|
+
export interface GraphMailMessageAttachment {
|
|
183
|
+
id: string;
|
|
184
|
+
name?: string;
|
|
185
|
+
contentType?: string;
|
|
186
|
+
size?: number;
|
|
187
|
+
isInline?: boolean;
|
|
188
|
+
'@odata.type'?: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function messagesPath(folderId: string, user: string | undefined, query?: MessagesQueryOptions): string {
|
|
192
|
+
const params = new URLSearchParams();
|
|
193
|
+
if (query?.filter) params.set('$filter', query.filter);
|
|
194
|
+
if (query?.orderby) params.set('$orderby', query.orderby);
|
|
195
|
+
if (query?.select) params.set('$select', query.select);
|
|
196
|
+
if (query?.top !== undefined) params.set('$top', String(query.top));
|
|
197
|
+
const qs = params.toString() ? `?${params.toString()}` : '';
|
|
198
|
+
return `${mailFoldersRoot(user)}/${encodeURIComponent(folderId)}/messages${qs}`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function mailboxMessagesPath(user: string | undefined, query?: RootMailboxMessagesQuery): string {
|
|
202
|
+
const params = new URLSearchParams();
|
|
203
|
+
if (query?.filter) params.set('$filter', query.filter);
|
|
204
|
+
if (query?.orderby) params.set('$orderby', query.orderby);
|
|
205
|
+
if (query?.select) params.set('$select', query.select);
|
|
206
|
+
if (query?.top !== undefined) params.set('$top', String(query.top));
|
|
207
|
+
if (query?.skip !== undefined) params.set('$skip', String(query.skip));
|
|
208
|
+
if (query?.search) {
|
|
209
|
+
const escaped = query.search.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
210
|
+
params.set('$search', `"${escaped}"`);
|
|
211
|
+
}
|
|
212
|
+
const qs = params.toString() ? `?${params.toString()}` : '';
|
|
213
|
+
return `${graphUserPath(user, 'messages')}${qs}`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function searchRequestInit(query?: RootMailboxMessagesQuery): RequestInit | undefined {
|
|
217
|
+
return query?.search ? { headers: { ConsistencyLevel: 'eventual' } } : undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* List messages in a folder. Well-known folder ids include `inbox`, `sentitems`, `drafts`, `deleteditems`, `archive`, `junkemail`.
|
|
222
|
+
* Use `top` for a single page; omit `top` to page through all results (can be large).
|
|
223
|
+
*/
|
|
224
|
+
export async function listMessagesInFolder(
|
|
225
|
+
token: string,
|
|
226
|
+
folderId: string,
|
|
227
|
+
user?: string,
|
|
228
|
+
query?: MessagesQueryOptions
|
|
229
|
+
): Promise<GraphResponse<OutlookMessage[]>> {
|
|
230
|
+
const path = messagesPath(folderId, user, query);
|
|
231
|
+
const singlePage = query?.top !== undefined;
|
|
232
|
+
|
|
233
|
+
if (singlePage) {
|
|
234
|
+
try {
|
|
235
|
+
const result = await callGraph<{ value: OutlookMessage[] }>(token, path);
|
|
236
|
+
if (!result.ok || !result.data) {
|
|
237
|
+
return graphError(result.error?.message || 'Failed to list messages', result.error?.code, result.error?.status);
|
|
238
|
+
}
|
|
239
|
+
return graphResult(result.data.value || []);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
242
|
+
return graphError(err instanceof Error ? err.message : 'Failed to list messages');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return fetchAllPages<OutlookMessage>(token, path, 'Failed to list messages');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* List messages via `GET /me/messages` (entire mailbox, not limited to one folder).
|
|
251
|
+
* When `search` is set, Graph requires `ConsistencyLevel: eventual` (applied automatically).
|
|
252
|
+
*/
|
|
253
|
+
export async function listMailboxMessages(
|
|
254
|
+
token: string,
|
|
255
|
+
user?: string,
|
|
256
|
+
query?: RootMailboxMessagesQuery
|
|
257
|
+
): Promise<GraphResponse<OutlookMessage[]>> {
|
|
258
|
+
const path = mailboxMessagesPath(user, query);
|
|
259
|
+
const singlePage = query?.top !== undefined;
|
|
260
|
+
const req = searchRequestInit(query);
|
|
261
|
+
|
|
262
|
+
if (singlePage) {
|
|
263
|
+
try {
|
|
264
|
+
const result = await callGraph<{ value: OutlookMessage[] }>(token, path, req ?? {});
|
|
265
|
+
if (!result.ok || !result.data) {
|
|
266
|
+
return graphError(result.error?.message || 'Failed to list messages', result.error?.code, result.error?.status);
|
|
267
|
+
}
|
|
268
|
+
return graphResult(result.data.value || []);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
271
|
+
return graphError(err instanceof Error ? err.message : 'Failed to list messages');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return fetchAllPages<OutlookMessage>(token, path, 'Failed to list messages', undefined, req);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** `GET /me/messages/{id}` — message ids are unique within the mailbox (folder path not required). */
|
|
279
|
+
export async function getMessage(
|
|
280
|
+
token: string,
|
|
281
|
+
messageId: string,
|
|
282
|
+
user?: string,
|
|
283
|
+
select?: string
|
|
284
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
285
|
+
const qs = select ? `?$select=${encodeURIComponent(select)}` : '';
|
|
286
|
+
try {
|
|
287
|
+
const result = await callGraph<OutlookMessage>(
|
|
288
|
+
token,
|
|
289
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}${qs}`
|
|
290
|
+
);
|
|
291
|
+
if (!result.ok || !result.data) {
|
|
292
|
+
return graphError(result.error?.message || 'Failed to get message', result.error?.code, result.error?.status);
|
|
293
|
+
}
|
|
294
|
+
return graphResult(result.data);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
297
|
+
return graphError(err instanceof Error ? err.message : 'Failed to get message');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export async function patchMailMessage(
|
|
302
|
+
token: string,
|
|
303
|
+
messageId: string,
|
|
304
|
+
patch: Record<string, unknown>,
|
|
305
|
+
user?: string
|
|
306
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
307
|
+
try {
|
|
308
|
+
const result = await callGraph<OutlookMessage>(
|
|
309
|
+
token,
|
|
310
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}`,
|
|
311
|
+
{ method: 'PATCH', body: JSON.stringify(patch) }
|
|
312
|
+
);
|
|
313
|
+
if (!result.ok || !result.data) {
|
|
314
|
+
return graphError(result.error?.message || 'Failed to update message', result.error?.code, result.error?.status);
|
|
315
|
+
}
|
|
316
|
+
return graphResult(result.data);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
319
|
+
return graphError(err instanceof Error ? err.message : 'Failed to update message');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export async function deleteMailMessage(token: string, messageId: string, user?: string): Promise<GraphResponse<void>> {
|
|
324
|
+
try {
|
|
325
|
+
return await callGraph<void>(
|
|
326
|
+
token,
|
|
327
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}`,
|
|
328
|
+
{ method: 'DELETE' },
|
|
329
|
+
false
|
|
330
|
+
);
|
|
331
|
+
} catch (err) {
|
|
332
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
333
|
+
return graphError(err instanceof Error ? err.message : 'Failed to delete message');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function moveMailMessage(
|
|
338
|
+
token: string,
|
|
339
|
+
messageId: string,
|
|
340
|
+
destinationFolderId: string,
|
|
341
|
+
user?: string
|
|
342
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
343
|
+
try {
|
|
344
|
+
const result = await callGraph<OutlookMessage>(
|
|
345
|
+
token,
|
|
346
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/move`,
|
|
347
|
+
{
|
|
348
|
+
method: 'POST',
|
|
349
|
+
body: JSON.stringify({ destinationId: destinationFolderId })
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
if (!result.ok || !result.data) {
|
|
353
|
+
return graphError(result.error?.message || 'Failed to move message', result.error?.code, result.error?.status);
|
|
354
|
+
}
|
|
355
|
+
return graphResult(result.data);
|
|
356
|
+
} catch (err) {
|
|
357
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
358
|
+
return graphError(err instanceof Error ? err.message : 'Failed to move message');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export async function copyMailMessage(
|
|
363
|
+
token: string,
|
|
364
|
+
messageId: string,
|
|
365
|
+
destinationFolderId: string,
|
|
366
|
+
user?: string
|
|
367
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
368
|
+
try {
|
|
369
|
+
const result = await callGraph<OutlookMessage>(
|
|
370
|
+
token,
|
|
371
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/copy`,
|
|
372
|
+
{
|
|
373
|
+
method: 'POST',
|
|
374
|
+
body: JSON.stringify({ destinationId: destinationFolderId })
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
if (!result.ok || !result.data) {
|
|
378
|
+
return graphError(result.error?.message || 'Failed to copy message', result.error?.code, result.error?.status);
|
|
379
|
+
}
|
|
380
|
+
return graphResult(result.data);
|
|
381
|
+
} catch (err) {
|
|
382
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
383
|
+
return graphError(err instanceof Error ? err.message : 'Failed to copy message');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Send a new message in one request (`POST /sendMail`). */
|
|
388
|
+
export async function sendMail(
|
|
389
|
+
token: string,
|
|
390
|
+
body: { message: Record<string, unknown>; saveToSentItems?: boolean },
|
|
391
|
+
user?: string
|
|
392
|
+
): Promise<GraphResponse<void>> {
|
|
393
|
+
try {
|
|
394
|
+
return await callGraph<void>(
|
|
395
|
+
token,
|
|
396
|
+
`${graphUserPath(user, 'sendMail')}`,
|
|
397
|
+
{ method: 'POST', body: JSON.stringify(body) },
|
|
398
|
+
false
|
|
399
|
+
);
|
|
400
|
+
} catch (err) {
|
|
401
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
402
|
+
return graphError(err instanceof Error ? err.message : 'Failed to send mail');
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** Send an existing draft (`POST /messages/{id}/send`). */
|
|
407
|
+
export async function sendMailMessage(token: string, messageId: string, user?: string): Promise<GraphResponse<void>> {
|
|
408
|
+
try {
|
|
409
|
+
return await callGraph<void>(
|
|
410
|
+
token,
|
|
411
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/send`,
|
|
412
|
+
{ method: 'POST' },
|
|
413
|
+
false
|
|
414
|
+
);
|
|
415
|
+
} catch (err) {
|
|
416
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
417
|
+
return graphError(err instanceof Error ? err.message : 'Failed to send message');
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export async function listMailMessageAttachments(
|
|
422
|
+
token: string,
|
|
423
|
+
messageId: string,
|
|
424
|
+
user?: string
|
|
425
|
+
): Promise<GraphResponse<GraphMailMessageAttachment[]>> {
|
|
426
|
+
return fetchAllPages<GraphMailMessageAttachment>(
|
|
427
|
+
token,
|
|
428
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/attachments`,
|
|
429
|
+
'Failed to list attachments'
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export async function getMailMessageAttachment(
|
|
434
|
+
token: string,
|
|
435
|
+
messageId: string,
|
|
436
|
+
attachmentId: string,
|
|
437
|
+
user?: string
|
|
438
|
+
): Promise<GraphResponse<GraphMailMessageAttachment>> {
|
|
439
|
+
try {
|
|
440
|
+
const result = await callGraph<GraphMailMessageAttachment>(
|
|
441
|
+
token,
|
|
442
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`
|
|
443
|
+
);
|
|
444
|
+
if (!result.ok || !result.data) {
|
|
445
|
+
return graphError(result.error?.message || 'Failed to get attachment', result.error?.code, result.error?.status);
|
|
446
|
+
}
|
|
447
|
+
return graphResult(result.data);
|
|
448
|
+
} catch (err) {
|
|
449
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
450
|
+
return graphError(err instanceof Error ? err.message : 'Failed to get attachment');
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export async function downloadMailMessageAttachmentBytes(
|
|
455
|
+
token: string,
|
|
456
|
+
messageId: string,
|
|
457
|
+
attachmentId: string,
|
|
458
|
+
user?: string
|
|
459
|
+
): Promise<GraphResponse<Uint8Array>> {
|
|
460
|
+
const path = `${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}/$value`;
|
|
461
|
+
try {
|
|
462
|
+
const res = await fetchGraphRaw(token, path);
|
|
463
|
+
if (!res.ok) {
|
|
464
|
+
let message = `Failed to download attachment: HTTP ${res.status}`;
|
|
465
|
+
try {
|
|
466
|
+
const json = (await res.json()) as { error?: { message?: string } };
|
|
467
|
+
message = json.error?.message || message;
|
|
468
|
+
} catch {
|
|
469
|
+
// ignore
|
|
470
|
+
}
|
|
471
|
+
return graphError(message, undefined, res.status);
|
|
472
|
+
}
|
|
473
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
474
|
+
return graphResult(buf);
|
|
475
|
+
} catch (err) {
|
|
476
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
477
|
+
return graphError(err instanceof Error ? err.message : 'Failed to download attachment');
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export async function createMailReplyDraft(
|
|
482
|
+
token: string,
|
|
483
|
+
messageId: string,
|
|
484
|
+
user?: string,
|
|
485
|
+
comment?: string
|
|
486
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
487
|
+
const body = JSON.stringify(comment ? { comment } : {});
|
|
488
|
+
try {
|
|
489
|
+
const result = await callGraph<OutlookMessage>(
|
|
490
|
+
token,
|
|
491
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/createReply`,
|
|
492
|
+
{ method: 'POST', body },
|
|
493
|
+
true
|
|
494
|
+
);
|
|
495
|
+
if (!result.ok || !result.data) {
|
|
496
|
+
return graphError(
|
|
497
|
+
result.error?.message || 'Failed to create reply draft',
|
|
498
|
+
result.error?.code,
|
|
499
|
+
result.error?.status
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
return graphResult(result.data);
|
|
503
|
+
} catch (err) {
|
|
504
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
505
|
+
return graphError(err instanceof Error ? err.message : 'Failed to create reply draft');
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export async function createMailReplyAllDraft(
|
|
510
|
+
token: string,
|
|
511
|
+
messageId: string,
|
|
512
|
+
user?: string,
|
|
513
|
+
comment?: string
|
|
514
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
515
|
+
const body = JSON.stringify(comment ? { comment } : {});
|
|
516
|
+
try {
|
|
517
|
+
const result = await callGraph<OutlookMessage>(
|
|
518
|
+
token,
|
|
519
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/createReplyAll`,
|
|
520
|
+
{ method: 'POST', body },
|
|
521
|
+
true
|
|
522
|
+
);
|
|
523
|
+
if (!result.ok || !result.data) {
|
|
524
|
+
return graphError(
|
|
525
|
+
result.error?.message || 'Failed to create reply-all draft',
|
|
526
|
+
result.error?.code,
|
|
527
|
+
result.error?.status
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
return graphResult(result.data);
|
|
531
|
+
} catch (err) {
|
|
532
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
533
|
+
return graphError(err instanceof Error ? err.message : 'Failed to create reply-all draft');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export async function createMailForwardDraft(
|
|
538
|
+
token: string,
|
|
539
|
+
messageId: string,
|
|
540
|
+
toRecipients: string[],
|
|
541
|
+
user?: string,
|
|
542
|
+
comment?: string
|
|
543
|
+
): Promise<GraphResponse<OutlookMessage>> {
|
|
544
|
+
const recipients = toRecipients.map((address) => ({
|
|
545
|
+
emailAddress: { address }
|
|
546
|
+
}));
|
|
547
|
+
const payload: Record<string, unknown> = { toRecipients: recipients };
|
|
548
|
+
if (comment) payload.comment = comment;
|
|
549
|
+
try {
|
|
550
|
+
const result = await callGraph<OutlookMessage>(
|
|
551
|
+
token,
|
|
552
|
+
`${graphUserPath(user, 'messages')}/${encodeURIComponent(messageId)}/createForward`,
|
|
553
|
+
{ method: 'POST', body: JSON.stringify(payload) },
|
|
554
|
+
true
|
|
555
|
+
);
|
|
556
|
+
if (!result.ok || !result.data) {
|
|
557
|
+
return graphError(
|
|
558
|
+
result.error?.message || 'Failed to create forward draft',
|
|
559
|
+
result.error?.code,
|
|
560
|
+
result.error?.status
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
return graphResult(result.data);
|
|
564
|
+
} catch (err) {
|
|
565
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
566
|
+
return graphError(err instanceof Error ? err.message : 'Failed to create forward draft');
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export async function listContacts(token: string, user?: string): Promise<GraphResponse<OutlookContact[]>> {
|
|
571
|
+
return fetchAllPages<OutlookContact>(token, contactsRoot(user), 'Failed to list contacts');
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
export async function getContact(
|
|
575
|
+
token: string,
|
|
576
|
+
contactId: string,
|
|
577
|
+
user?: string,
|
|
578
|
+
select?: string
|
|
579
|
+
): Promise<GraphResponse<OutlookContact>> {
|
|
580
|
+
const qs = select ? `?$select=${encodeURIComponent(select)}` : '';
|
|
581
|
+
try {
|
|
582
|
+
const result = await callGraph<OutlookContact>(
|
|
583
|
+
token,
|
|
584
|
+
`${contactsRoot(user)}/${encodeURIComponent(contactId)}${qs}`
|
|
585
|
+
);
|
|
586
|
+
if (!result.ok || !result.data) {
|
|
587
|
+
return graphError(result.error?.message || 'Failed to get contact', result.error?.code, result.error?.status);
|
|
588
|
+
}
|
|
589
|
+
return graphResult(result.data);
|
|
590
|
+
} catch (err) {
|
|
591
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
592
|
+
return graphError(err instanceof Error ? err.message : 'Failed to get contact');
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
export async function createContact(
|
|
597
|
+
token: string,
|
|
598
|
+
body: Record<string, unknown>,
|
|
599
|
+
user?: string
|
|
600
|
+
): Promise<GraphResponse<OutlookContact>> {
|
|
601
|
+
try {
|
|
602
|
+
const result = await callGraph<OutlookContact>(token, contactsRoot(user), {
|
|
603
|
+
method: 'POST',
|
|
604
|
+
body: JSON.stringify(body)
|
|
605
|
+
});
|
|
606
|
+
if (!result.ok || !result.data) {
|
|
607
|
+
return graphError(result.error?.message || 'Failed to create contact', result.error?.code, result.error?.status);
|
|
608
|
+
}
|
|
609
|
+
return graphResult(result.data);
|
|
610
|
+
} catch (err) {
|
|
611
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
612
|
+
return graphError(err instanceof Error ? err.message : 'Failed to create contact');
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
export async function updateContact(
|
|
617
|
+
token: string,
|
|
618
|
+
contactId: string,
|
|
619
|
+
patch: Record<string, unknown>,
|
|
620
|
+
user?: string
|
|
621
|
+
): Promise<GraphResponse<OutlookContact>> {
|
|
622
|
+
try {
|
|
623
|
+
const result = await callGraph<OutlookContact>(token, `${contactsRoot(user)}/${encodeURIComponent(contactId)}`, {
|
|
624
|
+
method: 'PATCH',
|
|
625
|
+
body: JSON.stringify(patch)
|
|
626
|
+
});
|
|
627
|
+
if (!result.ok || !result.data) {
|
|
628
|
+
return graphError(result.error?.message || 'Failed to update contact', result.error?.code, result.error?.status);
|
|
629
|
+
}
|
|
630
|
+
return graphResult(result.data);
|
|
631
|
+
} catch (err) {
|
|
632
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
633
|
+
return graphError(err instanceof Error ? err.message : 'Failed to update contact');
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export async function deleteContact(token: string, contactId: string, user?: string): Promise<GraphResponse<void>> {
|
|
638
|
+
try {
|
|
639
|
+
return await callGraph<void>(
|
|
640
|
+
token,
|
|
641
|
+
`${contactsRoot(user)}/${encodeURIComponent(contactId)}`,
|
|
642
|
+
{ method: 'DELETE' },
|
|
643
|
+
false
|
|
644
|
+
);
|
|
645
|
+
} catch (err) {
|
|
646
|
+
if (err instanceof GraphApiError) return graphError(err.message, err.code, err.status);
|
|
647
|
+
return graphError(err instanceof Error ? err.message : 'Failed to delete contact');
|
|
648
|
+
}
|
|
649
|
+
}
|