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,880 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveGraphAuth } from '../lib/graph-auth.js';
|
|
4
|
+
import {
|
|
5
|
+
copyMailMessage,
|
|
6
|
+
createContact,
|
|
7
|
+
createMailFolder,
|
|
8
|
+
createMailForwardDraft,
|
|
9
|
+
createMailReplyAllDraft,
|
|
10
|
+
createMailReplyDraft,
|
|
11
|
+
deleteContact,
|
|
12
|
+
deleteMailFolder,
|
|
13
|
+
deleteMailMessage,
|
|
14
|
+
downloadMailMessageAttachmentBytes,
|
|
15
|
+
getContact,
|
|
16
|
+
getMailFolder,
|
|
17
|
+
getMailMessageAttachment,
|
|
18
|
+
getMessage,
|
|
19
|
+
listChildMailFolders,
|
|
20
|
+
listContacts,
|
|
21
|
+
listMailboxMessages,
|
|
22
|
+
listMailFolders,
|
|
23
|
+
listMailMessageAttachments,
|
|
24
|
+
listMessagesInFolder,
|
|
25
|
+
type MessagesQueryOptions,
|
|
26
|
+
moveMailMessage,
|
|
27
|
+
patchMailMessage,
|
|
28
|
+
type RootMailboxMessagesQuery,
|
|
29
|
+
sendMail,
|
|
30
|
+
sendMailMessage,
|
|
31
|
+
updateContact,
|
|
32
|
+
updateMailFolder
|
|
33
|
+
} from '../lib/outlook-graph-client.js';
|
|
34
|
+
import { checkReadOnly } from '../lib/utils.js';
|
|
35
|
+
|
|
36
|
+
export const outlookGraphCommand = new Command('outlook-graph').description(
|
|
37
|
+
'Microsoft Graph Outlook REST: mail folders, messages (list/send/patch/move/copy/attachments/reply), contacts (distinct from EWS mail/folders)'
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
outlookGraphCommand
|
|
41
|
+
.command('list-folders')
|
|
42
|
+
.description('List mail folders (Graph GET /mailFolders)')
|
|
43
|
+
.option('--json', 'Output as JSON')
|
|
44
|
+
.option('--token <token>', 'Use a specific token')
|
|
45
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
46
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
47
|
+
.action(async (opts: { json?: boolean; token?: string; identity?: string; user?: string }) => {
|
|
48
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
49
|
+
if (!auth.success) {
|
|
50
|
+
console.error(`Auth error: ${auth.error}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const r = await listMailFolders(auth.token!, opts.user);
|
|
54
|
+
if (!r.ok || !r.data) {
|
|
55
|
+
console.error(`Error: ${r.error?.message}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
59
|
+
else {
|
|
60
|
+
for (const f of r.data) {
|
|
61
|
+
console.log(`${f.displayName}\t${f.id}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
outlookGraphCommand
|
|
67
|
+
.command('child-folders')
|
|
68
|
+
.description('List child folders under a parent folder id')
|
|
69
|
+
.requiredOption('-p, --parent <folderId>', 'Parent folder id (e.g. Inbox id from list-folders)')
|
|
70
|
+
.option('--json', 'Output as JSON')
|
|
71
|
+
.option('--token <token>', 'Use a specific token')
|
|
72
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
73
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
74
|
+
.action(async (opts: { parent: string; json?: boolean; token?: string; identity?: string; user?: string }) => {
|
|
75
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
76
|
+
if (!auth.success) {
|
|
77
|
+
console.error(`Auth error: ${auth.error}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const r = await listChildMailFolders(auth.token!, opts.parent, opts.user);
|
|
81
|
+
if (!r.ok || !r.data) {
|
|
82
|
+
console.error(`Error: ${r.error?.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
86
|
+
else {
|
|
87
|
+
for (const f of r.data) {
|
|
88
|
+
console.log(`${f.displayName}\t${f.id}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
outlookGraphCommand
|
|
94
|
+
.command('get-folder')
|
|
95
|
+
.description('Get one mail folder by id (well-known: inbox, sentitems, drafts, deleteditems, archive, junkemail)')
|
|
96
|
+
.argument('<folderId>', 'Folder id')
|
|
97
|
+
.option('--json', 'Output as JSON')
|
|
98
|
+
.option('--token <token>', 'Use a specific token')
|
|
99
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
100
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
101
|
+
.action(async (folderId: string, opts: { json?: boolean; token?: string; identity?: string; user?: string }) => {
|
|
102
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
103
|
+
if (!auth.success) {
|
|
104
|
+
console.error(`Auth error: ${auth.error}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
const r = await getMailFolder(auth.token!, folderId, opts.user);
|
|
108
|
+
if (!r.ok || !r.data) {
|
|
109
|
+
console.error(`Error: ${r.error?.message}`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
113
|
+
else console.log(JSON.stringify(r.data, null, 2));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
outlookGraphCommand
|
|
117
|
+
.command('create-folder')
|
|
118
|
+
.description('Create a mail folder (optionally under --parent)')
|
|
119
|
+
.requiredOption('-n, --name <displayName>', 'Folder display name')
|
|
120
|
+
.option('-p, --parent <folderId>', 'Parent folder id (omit for root-level where allowed)')
|
|
121
|
+
.option('--json', 'Output as JSON')
|
|
122
|
+
.option('--token <token>', 'Use a specific token')
|
|
123
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
124
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
125
|
+
.action(
|
|
126
|
+
async (
|
|
127
|
+
opts: { name: string; parent?: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
128
|
+
cmd: any
|
|
129
|
+
) => {
|
|
130
|
+
checkReadOnly(cmd);
|
|
131
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
132
|
+
if (!auth.success) {
|
|
133
|
+
console.error(`Auth error: ${auth.error}`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
const r = await createMailFolder(auth.token!, opts.name, opts.parent, opts.user);
|
|
137
|
+
if (!r.ok || !r.data) {
|
|
138
|
+
console.error(`Error: ${r.error?.message}`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
142
|
+
else console.log(`Created folder: ${r.data.displayName} (${r.data.id})`);
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
outlookGraphCommand
|
|
147
|
+
.command('update-folder')
|
|
148
|
+
.description('Rename a mail folder (PATCH displayName)')
|
|
149
|
+
.argument('<folderId>', 'Folder id')
|
|
150
|
+
.requiredOption('-n, --name <displayName>', 'New display name')
|
|
151
|
+
.option('--json', 'Output as JSON')
|
|
152
|
+
.option('--token <token>', 'Use a specific token')
|
|
153
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
154
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
155
|
+
.action(
|
|
156
|
+
async (
|
|
157
|
+
folderId: string,
|
|
158
|
+
opts: { name: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
159
|
+
cmd: any
|
|
160
|
+
) => {
|
|
161
|
+
checkReadOnly(cmd);
|
|
162
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
163
|
+
if (!auth.success) {
|
|
164
|
+
console.error(`Auth error: ${auth.error}`);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
const r = await updateMailFolder(auth.token!, folderId, opts.name, opts.user);
|
|
168
|
+
if (!r.ok || !r.data) {
|
|
169
|
+
console.error(`Error: ${r.error?.message}`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
173
|
+
else console.log(`Updated folder: ${r.data.displayName}`);
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
outlookGraphCommand
|
|
178
|
+
.command('delete-folder')
|
|
179
|
+
.description('Delete a mail folder (not allowed for default folders)')
|
|
180
|
+
.argument('<folderId>', 'Folder id')
|
|
181
|
+
.option('--confirm', 'Confirm delete')
|
|
182
|
+
.option('--token <token>', 'Use a specific token')
|
|
183
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
184
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
185
|
+
.action(
|
|
186
|
+
async (
|
|
187
|
+
folderId: string,
|
|
188
|
+
opts: { confirm?: boolean; token?: string; identity?: string; user?: string },
|
|
189
|
+
cmd: any
|
|
190
|
+
) => {
|
|
191
|
+
checkReadOnly(cmd);
|
|
192
|
+
if (!opts.confirm) {
|
|
193
|
+
console.error('Refusing to delete without --confirm');
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
197
|
+
if (!auth.success) {
|
|
198
|
+
console.error(`Auth error: ${auth.error}`);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
const r = await deleteMailFolder(auth.token!, folderId, opts.user);
|
|
202
|
+
if (!r.ok) {
|
|
203
|
+
console.error(`Error: ${r.error?.message}`);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
console.log('Deleted folder.');
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
outlookGraphCommand
|
|
211
|
+
.command('list-messages')
|
|
212
|
+
.description('List messages in a folder (Graph; use well-known id e.g. inbox)')
|
|
213
|
+
.requiredOption('-f, --folder <folderId>', 'Folder id (e.g. inbox)')
|
|
214
|
+
.option('--top <n>', 'Page size (default 25). Omit with --all to page entire folder', '25')
|
|
215
|
+
.option('--all', 'Follow all pages (may be slow/large)')
|
|
216
|
+
.option('--filter <odata>', 'OData $filter')
|
|
217
|
+
.option('--orderby <odata>', 'OData $orderby')
|
|
218
|
+
.option('--select <fields>', 'OData $select (comma-separated)')
|
|
219
|
+
.option('--json', 'Output as JSON')
|
|
220
|
+
.option('--token <token>', 'Use a specific token')
|
|
221
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
222
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
223
|
+
.action(
|
|
224
|
+
async (opts: {
|
|
225
|
+
folder: string;
|
|
226
|
+
top?: string;
|
|
227
|
+
all?: boolean;
|
|
228
|
+
filter?: string;
|
|
229
|
+
orderby?: string;
|
|
230
|
+
select?: string;
|
|
231
|
+
json?: boolean;
|
|
232
|
+
token?: string;
|
|
233
|
+
identity?: string;
|
|
234
|
+
user?: string;
|
|
235
|
+
}) => {
|
|
236
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
237
|
+
if (!auth.success) {
|
|
238
|
+
console.error(`Auth error: ${auth.error}`);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
const q: MessagesQueryOptions = {};
|
|
242
|
+
if (opts.filter) q.filter = opts.filter;
|
|
243
|
+
if (opts.orderby) q.orderby = opts.orderby;
|
|
244
|
+
if (opts.select) q.select = opts.select;
|
|
245
|
+
if (opts.all) {
|
|
246
|
+
// fetch all pages — no $top
|
|
247
|
+
} else {
|
|
248
|
+
q.top = Math.max(1, parseInt(opts.top ?? '25', 10) || 25);
|
|
249
|
+
}
|
|
250
|
+
const r = await listMessagesInFolder(auth.token!, opts.folder, opts.user, q);
|
|
251
|
+
if (!r.ok || !r.data) {
|
|
252
|
+
console.error(`Error: ${r.error?.message}`);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
256
|
+
else {
|
|
257
|
+
for (const m of r.data) {
|
|
258
|
+
const from = m.from?.emailAddress?.address ?? '';
|
|
259
|
+
const sub = m.subject ?? '(no subject)';
|
|
260
|
+
console.log(`${m.receivedDateTime ?? ''}\t${from}\t${sub}\t${m.id}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
outlookGraphCommand
|
|
267
|
+
.command('list-mail')
|
|
268
|
+
.description('List messages mailbox-wide (Graph GET /messages; use --folder on list-messages for one folder)')
|
|
269
|
+
.option('--top <n>', 'Page size (default 25). Omit with --all to page entire result set', '25')
|
|
270
|
+
.option('--all', 'Follow all pages (may be slow/large)')
|
|
271
|
+
.option('--filter <odata>', 'OData $filter (do not combine with --search)')
|
|
272
|
+
.option('--orderby <odata>', 'OData $orderby')
|
|
273
|
+
.option('--select <fields>', 'OData $select (comma-separated)')
|
|
274
|
+
.option('--skip <n>', 'OData $skip')
|
|
275
|
+
.option('--search <text>', 'Keyword search ($search; adds ConsistencyLevel; do not combine with --filter)')
|
|
276
|
+
.option('--json', 'Output as JSON')
|
|
277
|
+
.option('--token <token>', 'Use a specific token')
|
|
278
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
279
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
280
|
+
.action(
|
|
281
|
+
async (opts: {
|
|
282
|
+
top?: string;
|
|
283
|
+
all?: boolean;
|
|
284
|
+
filter?: string;
|
|
285
|
+
orderby?: string;
|
|
286
|
+
select?: string;
|
|
287
|
+
skip?: string;
|
|
288
|
+
search?: string;
|
|
289
|
+
json?: boolean;
|
|
290
|
+
token?: string;
|
|
291
|
+
identity?: string;
|
|
292
|
+
user?: string;
|
|
293
|
+
}) => {
|
|
294
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
295
|
+
if (!auth.success) {
|
|
296
|
+
console.error(`Auth error: ${auth.error}`);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
const q: RootMailboxMessagesQuery = {};
|
|
300
|
+
if (opts.filter) q.filter = opts.filter;
|
|
301
|
+
if (opts.orderby) q.orderby = opts.orderby;
|
|
302
|
+
if (opts.select) q.select = opts.select;
|
|
303
|
+
if (opts.search) q.search = opts.search;
|
|
304
|
+
if (opts.skip !== undefined) q.skip = Math.max(0, parseInt(opts.skip, 10) || 0);
|
|
305
|
+
if (opts.all) {
|
|
306
|
+
// full pagination
|
|
307
|
+
} else {
|
|
308
|
+
q.top = Math.max(1, parseInt(opts.top ?? '25', 10) || 25);
|
|
309
|
+
}
|
|
310
|
+
const r = await listMailboxMessages(auth.token!, opts.user, q);
|
|
311
|
+
if (!r.ok || !r.data) {
|
|
312
|
+
console.error(`Error: ${r.error?.message}`);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
316
|
+
else {
|
|
317
|
+
for (const m of r.data) {
|
|
318
|
+
const from = m.from?.emailAddress?.address ?? '';
|
|
319
|
+
const sub = m.subject ?? '(no subject)';
|
|
320
|
+
console.log(`${m.receivedDateTime ?? ''}\t${from}\t${sub}\t${m.id}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
outlookGraphCommand
|
|
327
|
+
.command('get-message')
|
|
328
|
+
.description('Get one message by id (Graph GET /messages/{id})')
|
|
329
|
+
.requiredOption('-i, --id <messageId>', 'Message id')
|
|
330
|
+
.option('--select <fields>', 'OData $select')
|
|
331
|
+
.option('--json', 'Output as JSON')
|
|
332
|
+
.option('--token <token>', 'Use a specific token')
|
|
333
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
334
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
335
|
+
.action(
|
|
336
|
+
async (opts: { id: string; select?: string; json?: boolean; token?: string; identity?: string; user?: string }) => {
|
|
337
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
338
|
+
if (!auth.success) {
|
|
339
|
+
console.error(`Auth error: ${auth.error}`);
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
const r = await getMessage(auth.token!, opts.id, opts.user, opts.select);
|
|
343
|
+
if (!r.ok || !r.data) {
|
|
344
|
+
console.error(`Error: ${r.error?.message}`);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
348
|
+
else console.log(JSON.stringify(r.data, null, 2));
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
outlookGraphCommand
|
|
353
|
+
.command('send-mail')
|
|
354
|
+
.description('Send email in one request (Graph POST /sendMail; JSON body with message + optional saveToSentItems)')
|
|
355
|
+
.requiredOption('--json-file <path>', 'Path to JSON: { "message": { ... }, "saveToSentItems": true }')
|
|
356
|
+
.option('--token <token>', 'Use a specific token')
|
|
357
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
358
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
359
|
+
.action(async (opts: { jsonFile: string; token?: string; identity?: string; user?: string }, cmd: any) => {
|
|
360
|
+
checkReadOnly(cmd);
|
|
361
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
362
|
+
if (!auth.success) {
|
|
363
|
+
console.error(`Auth error: ${auth.error}`);
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
const raw = await readFile(opts.jsonFile, 'utf-8');
|
|
367
|
+
const body = JSON.parse(raw) as { message: Record<string, unknown>; saveToSentItems?: boolean };
|
|
368
|
+
if (!body.message) {
|
|
369
|
+
console.error('JSON must include a "message" object');
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
const r = await sendMail(auth.token!, body, opts.user);
|
|
373
|
+
if (!r.ok) {
|
|
374
|
+
console.error(`Error: ${r.error?.message}`);
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
console.log('Sent.');
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
outlookGraphCommand
|
|
381
|
+
.command('patch-message')
|
|
382
|
+
.description('PATCH a message (e.g. isRead, flag, categories — Graph PATCH /messages/{id})')
|
|
383
|
+
.argument('<messageId>', 'Message id')
|
|
384
|
+
.requiredOption('--json-file <path>', 'Path to JSON patch body')
|
|
385
|
+
.option('--json', 'Echo updated message as JSON')
|
|
386
|
+
.option('--token <token>', 'Use a specific token')
|
|
387
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
388
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
389
|
+
.action(
|
|
390
|
+
async (
|
|
391
|
+
messageId: string,
|
|
392
|
+
opts: { jsonFile: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
393
|
+
cmd: any
|
|
394
|
+
) => {
|
|
395
|
+
checkReadOnly(cmd);
|
|
396
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
397
|
+
if (!auth.success) {
|
|
398
|
+
console.error(`Auth error: ${auth.error}`);
|
|
399
|
+
process.exit(1);
|
|
400
|
+
}
|
|
401
|
+
const raw = await readFile(opts.jsonFile, 'utf-8');
|
|
402
|
+
const patch = JSON.parse(raw) as Record<string, unknown>;
|
|
403
|
+
const r = await patchMailMessage(auth.token!, messageId, patch, opts.user);
|
|
404
|
+
if (!r.ok || !r.data) {
|
|
405
|
+
console.error(`Error: ${r.error?.message}`);
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
409
|
+
else console.log(`Updated message ${r.data.id}`);
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
outlookGraphCommand
|
|
414
|
+
.command('delete-message')
|
|
415
|
+
.description('Delete a message (Graph DELETE /messages/{id})')
|
|
416
|
+
.argument('<messageId>', 'Message id')
|
|
417
|
+
.option('--confirm', 'Confirm delete')
|
|
418
|
+
.option('--token <token>', 'Use a specific token')
|
|
419
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
420
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
421
|
+
.action(
|
|
422
|
+
async (
|
|
423
|
+
messageId: string,
|
|
424
|
+
opts: { confirm?: boolean; token?: string; identity?: string; user?: string },
|
|
425
|
+
cmd: any
|
|
426
|
+
) => {
|
|
427
|
+
checkReadOnly(cmd);
|
|
428
|
+
if (!opts.confirm) {
|
|
429
|
+
console.error('Refusing to delete without --confirm');
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
433
|
+
if (!auth.success) {
|
|
434
|
+
console.error(`Auth error: ${auth.error}`);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
const r = await deleteMailMessage(auth.token!, messageId, opts.user);
|
|
438
|
+
if (!r.ok) {
|
|
439
|
+
console.error(`Error: ${r.error?.message}`);
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
console.log('Deleted message.');
|
|
443
|
+
}
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
outlookGraphCommand
|
|
447
|
+
.command('move-message')
|
|
448
|
+
.description('Move a message to another folder (Graph POST .../move)')
|
|
449
|
+
.argument('<messageId>', 'Message id')
|
|
450
|
+
.requiredOption('-d, --destination <folderId>', 'Destination folder id (e.g. deleteditems)')
|
|
451
|
+
.option('--json', 'Echo moved message as JSON')
|
|
452
|
+
.option('--token <token>', 'Use a specific token')
|
|
453
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
454
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
455
|
+
.action(
|
|
456
|
+
async (
|
|
457
|
+
messageId: string,
|
|
458
|
+
opts: { destination: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
459
|
+
cmd: any
|
|
460
|
+
) => {
|
|
461
|
+
checkReadOnly(cmd);
|
|
462
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
463
|
+
if (!auth.success) {
|
|
464
|
+
console.error(`Auth error: ${auth.error}`);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
const r = await moveMailMessage(auth.token!, messageId, opts.destination, opts.user);
|
|
468
|
+
if (!r.ok || !r.data) {
|
|
469
|
+
console.error(`Error: ${r.error?.message}`);
|
|
470
|
+
process.exit(1);
|
|
471
|
+
}
|
|
472
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
473
|
+
else console.log(`Moved to folder; message id: ${r.data.id}`);
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
outlookGraphCommand
|
|
478
|
+
.command('copy-message')
|
|
479
|
+
.description('Copy a message to another folder (Graph POST .../copy)')
|
|
480
|
+
.argument('<messageId>', 'Message id')
|
|
481
|
+
.requiredOption('-d, --destination <folderId>', 'Destination folder id')
|
|
482
|
+
.option('--json', 'Echo copy as JSON')
|
|
483
|
+
.option('--token <token>', 'Use a specific token')
|
|
484
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
485
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
486
|
+
.action(
|
|
487
|
+
async (
|
|
488
|
+
messageId: string,
|
|
489
|
+
opts: { destination: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
490
|
+
cmd: any
|
|
491
|
+
) => {
|
|
492
|
+
checkReadOnly(cmd);
|
|
493
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
494
|
+
if (!auth.success) {
|
|
495
|
+
console.error(`Auth error: ${auth.error}`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
const r = await copyMailMessage(auth.token!, messageId, opts.destination, opts.user);
|
|
499
|
+
if (!r.ok || !r.data) {
|
|
500
|
+
console.error(`Error: ${r.error?.message}`);
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
504
|
+
else console.log(`Copy id: ${r.data.id}`);
|
|
505
|
+
}
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
outlookGraphCommand
|
|
509
|
+
.command('list-message-attachments')
|
|
510
|
+
.description('List attachments on a message (Graph GET .../messages/{id}/attachments)')
|
|
511
|
+
.requiredOption('-i, --id <messageId>', 'Message id')
|
|
512
|
+
.option('--json', 'Output as JSON')
|
|
513
|
+
.option('--token <token>', 'Use a specific token')
|
|
514
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
515
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
516
|
+
.action(async (opts: { id: string; json?: boolean; token?: string; identity?: string; user?: string }) => {
|
|
517
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
518
|
+
if (!auth.success) {
|
|
519
|
+
console.error(`Auth error: ${auth.error}`);
|
|
520
|
+
process.exit(1);
|
|
521
|
+
}
|
|
522
|
+
const r = await listMailMessageAttachments(auth.token!, opts.id, opts.user);
|
|
523
|
+
if (!r.ok || !r.data) {
|
|
524
|
+
console.error(`Error: ${r.error?.message}`);
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
528
|
+
else {
|
|
529
|
+
for (const a of r.data) {
|
|
530
|
+
console.log(`${a.name ?? a.id}\t${a.contentType ?? ''}\t${a.id}`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
outlookGraphCommand
|
|
536
|
+
.command('get-message-attachment')
|
|
537
|
+
.description('Get attachment metadata (Graph GET .../attachments/{id})')
|
|
538
|
+
.requiredOption('-i, --id <messageId>', 'Message id')
|
|
539
|
+
.requiredOption('-a, --attachment <attachmentId>', 'Attachment id')
|
|
540
|
+
.option('--json', 'Output as JSON')
|
|
541
|
+
.option('--token <token>', 'Use a specific token')
|
|
542
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
543
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
544
|
+
.action(
|
|
545
|
+
async (opts: {
|
|
546
|
+
id: string;
|
|
547
|
+
attachment: string;
|
|
548
|
+
json?: boolean;
|
|
549
|
+
token?: string;
|
|
550
|
+
identity?: string;
|
|
551
|
+
user?: string;
|
|
552
|
+
}) => {
|
|
553
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
554
|
+
if (!auth.success) {
|
|
555
|
+
console.error(`Auth error: ${auth.error}`);
|
|
556
|
+
process.exit(1);
|
|
557
|
+
}
|
|
558
|
+
const r = await getMailMessageAttachment(auth.token!, opts.id, opts.attachment, opts.user);
|
|
559
|
+
if (!r.ok || !r.data) {
|
|
560
|
+
console.error(`Error: ${r.error?.message}`);
|
|
561
|
+
process.exit(1);
|
|
562
|
+
}
|
|
563
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
564
|
+
else console.log(JSON.stringify(r.data, null, 2));
|
|
565
|
+
}
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
outlookGraphCommand
|
|
569
|
+
.command('download-message-attachment')
|
|
570
|
+
.description('Download file attachment bytes (Graph GET .../attachments/{id}/$value)')
|
|
571
|
+
.requiredOption('-i, --id <messageId>', 'Message id')
|
|
572
|
+
.requiredOption('-a, --attachment <attachmentId>', 'Attachment id')
|
|
573
|
+
.requiredOption('-o, --output <path>', 'Output file path')
|
|
574
|
+
.option('--token <token>', 'Use a specific token')
|
|
575
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
576
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
577
|
+
.action(
|
|
578
|
+
async (opts: {
|
|
579
|
+
id: string;
|
|
580
|
+
attachment: string;
|
|
581
|
+
output: string;
|
|
582
|
+
token?: string;
|
|
583
|
+
identity?: string;
|
|
584
|
+
user?: string;
|
|
585
|
+
}) => {
|
|
586
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
587
|
+
if (!auth.success) {
|
|
588
|
+
console.error(`Auth error: ${auth.error}`);
|
|
589
|
+
process.exit(1);
|
|
590
|
+
}
|
|
591
|
+
const r = await downloadMailMessageAttachmentBytes(auth.token!, opts.id, opts.attachment, opts.user);
|
|
592
|
+
if (!r.ok || !r.data) {
|
|
593
|
+
console.error(`Error: ${r.error?.message}`);
|
|
594
|
+
process.exit(1);
|
|
595
|
+
}
|
|
596
|
+
await writeFile(opts.output, r.data);
|
|
597
|
+
console.log(`Wrote ${r.data.byteLength} bytes to ${opts.output}`);
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
outlookGraphCommand
|
|
602
|
+
.command('create-reply')
|
|
603
|
+
.description('Create a reply draft (Graph POST .../createReply); then patch body and outlook-graph send-message')
|
|
604
|
+
.argument('<messageId>', 'Message id to reply to')
|
|
605
|
+
.option('--comment <text>', 'Optional comment included in the draft')
|
|
606
|
+
.option('--json', 'Output draft message as JSON')
|
|
607
|
+
.option('--token <token>', 'Use a specific token')
|
|
608
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
609
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
610
|
+
.action(
|
|
611
|
+
async (
|
|
612
|
+
messageId: string,
|
|
613
|
+
opts: { comment?: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
614
|
+
cmd: any
|
|
615
|
+
) => {
|
|
616
|
+
checkReadOnly(cmd);
|
|
617
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
618
|
+
if (!auth.success) {
|
|
619
|
+
console.error(`Auth error: ${auth.error}`);
|
|
620
|
+
process.exit(1);
|
|
621
|
+
}
|
|
622
|
+
const r = await createMailReplyDraft(auth.token!, messageId, opts.user, opts.comment);
|
|
623
|
+
if (!r.ok || !r.data) {
|
|
624
|
+
console.error(`Error: ${r.error?.message}`);
|
|
625
|
+
process.exit(1);
|
|
626
|
+
}
|
|
627
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
628
|
+
else console.log(`Draft message id: ${r.data.id}`);
|
|
629
|
+
}
|
|
630
|
+
);
|
|
631
|
+
|
|
632
|
+
outlookGraphCommand
|
|
633
|
+
.command('create-reply-all')
|
|
634
|
+
.description('Create a reply-all draft (Graph POST .../createReplyAll)')
|
|
635
|
+
.argument('<messageId>', 'Message id')
|
|
636
|
+
.option('--comment <text>', 'Optional comment')
|
|
637
|
+
.option('--json', 'Output draft message as JSON')
|
|
638
|
+
.option('--token <token>', 'Use a specific token')
|
|
639
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
640
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
641
|
+
.action(
|
|
642
|
+
async (
|
|
643
|
+
messageId: string,
|
|
644
|
+
opts: { comment?: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
645
|
+
cmd: any
|
|
646
|
+
) => {
|
|
647
|
+
checkReadOnly(cmd);
|
|
648
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
649
|
+
if (!auth.success) {
|
|
650
|
+
console.error(`Auth error: ${auth.error}`);
|
|
651
|
+
process.exit(1);
|
|
652
|
+
}
|
|
653
|
+
const r = await createMailReplyAllDraft(auth.token!, messageId, opts.user, opts.comment);
|
|
654
|
+
if (!r.ok || !r.data) {
|
|
655
|
+
console.error(`Error: ${r.error?.message}`);
|
|
656
|
+
process.exit(1);
|
|
657
|
+
}
|
|
658
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
659
|
+
else console.log(`Draft message id: ${r.data.id}`);
|
|
660
|
+
}
|
|
661
|
+
);
|
|
662
|
+
|
|
663
|
+
outlookGraphCommand
|
|
664
|
+
.command('create-forward')
|
|
665
|
+
.description('Create a forward draft (Graph POST .../createForward)')
|
|
666
|
+
.argument('<messageId>', 'Message id')
|
|
667
|
+
.requiredOption('--to <emails>', 'Comma-separated recipient addresses')
|
|
668
|
+
.option('--comment <text>', 'Optional comment')
|
|
669
|
+
.option('--json', 'Output draft message as JSON')
|
|
670
|
+
.option('--token <token>', 'Use a specific token')
|
|
671
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
672
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
673
|
+
.action(
|
|
674
|
+
async (
|
|
675
|
+
messageId: string,
|
|
676
|
+
opts: {
|
|
677
|
+
to: string;
|
|
678
|
+
comment?: string;
|
|
679
|
+
json?: boolean;
|
|
680
|
+
token?: string;
|
|
681
|
+
identity?: string;
|
|
682
|
+
user?: string;
|
|
683
|
+
},
|
|
684
|
+
cmd: any
|
|
685
|
+
) => {
|
|
686
|
+
checkReadOnly(cmd);
|
|
687
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
688
|
+
if (!auth.success) {
|
|
689
|
+
console.error(`Auth error: ${auth.error}`);
|
|
690
|
+
process.exit(1);
|
|
691
|
+
}
|
|
692
|
+
const recipients = opts.to
|
|
693
|
+
.split(',')
|
|
694
|
+
.map((s) => s.trim())
|
|
695
|
+
.filter(Boolean);
|
|
696
|
+
if (recipients.length === 0) {
|
|
697
|
+
console.error('Provide at least one address in --to');
|
|
698
|
+
process.exit(1);
|
|
699
|
+
}
|
|
700
|
+
const r = await createMailForwardDraft(auth.token!, messageId, recipients, opts.user, opts.comment);
|
|
701
|
+
if (!r.ok || !r.data) {
|
|
702
|
+
console.error(`Error: ${r.error?.message}`);
|
|
703
|
+
process.exit(1);
|
|
704
|
+
}
|
|
705
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
706
|
+
else console.log(`Draft message id: ${r.data.id}`);
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
outlookGraphCommand
|
|
711
|
+
.command('send-message')
|
|
712
|
+
.description('Send a draft message (Graph POST /messages/{id}/send)')
|
|
713
|
+
.argument('<messageId>', 'Draft message id')
|
|
714
|
+
.option('--token <token>', 'Use a specific token')
|
|
715
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
716
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
717
|
+
.action(async (messageId: string, opts: { token?: string; identity?: string; user?: string }, cmd: any) => {
|
|
718
|
+
checkReadOnly(cmd);
|
|
719
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
720
|
+
if (!auth.success) {
|
|
721
|
+
console.error(`Auth error: ${auth.error}`);
|
|
722
|
+
process.exit(1);
|
|
723
|
+
}
|
|
724
|
+
const r = await sendMailMessage(auth.token!, messageId, opts.user);
|
|
725
|
+
if (!r.ok) {
|
|
726
|
+
console.error(`Error: ${r.error?.message}`);
|
|
727
|
+
process.exit(1);
|
|
728
|
+
}
|
|
729
|
+
console.log('Sent.');
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
outlookGraphCommand
|
|
733
|
+
.command('list-contacts')
|
|
734
|
+
.description('List personal contacts (Graph GET /contacts)')
|
|
735
|
+
.option('--json', 'Output as JSON')
|
|
736
|
+
.option('--token <token>', 'Use a specific token')
|
|
737
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
738
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
739
|
+
.action(async (opts: { json?: boolean; token?: string; identity?: string; user?: string }) => {
|
|
740
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
741
|
+
if (!auth.success) {
|
|
742
|
+
console.error(`Auth error: ${auth.error}`);
|
|
743
|
+
process.exit(1);
|
|
744
|
+
}
|
|
745
|
+
const r = await listContacts(auth.token!, opts.user);
|
|
746
|
+
if (!r.ok || !r.data) {
|
|
747
|
+
console.error(`Error: ${r.error?.message}`);
|
|
748
|
+
process.exit(1);
|
|
749
|
+
}
|
|
750
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
751
|
+
else {
|
|
752
|
+
for (const c of r.data) {
|
|
753
|
+
const em = c.emailAddresses?.[0]?.address ?? '';
|
|
754
|
+
console.log(`${c.displayName ?? '(no name)'}\t${em}\t${c.id}`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
outlookGraphCommand
|
|
760
|
+
.command('get-contact')
|
|
761
|
+
.description('Get one contact by id')
|
|
762
|
+
.argument('<contactId>', 'Contact id')
|
|
763
|
+
.option('--select <fields>', 'OData $select')
|
|
764
|
+
.option('--json', 'Output as JSON')
|
|
765
|
+
.option('--token <token>', 'Use a specific token')
|
|
766
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
767
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
768
|
+
.action(
|
|
769
|
+
async (
|
|
770
|
+
contactId: string,
|
|
771
|
+
opts: { select?: string; json?: boolean; token?: string; identity?: string; user?: string }
|
|
772
|
+
) => {
|
|
773
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
774
|
+
if (!auth.success) {
|
|
775
|
+
console.error(`Auth error: ${auth.error}`);
|
|
776
|
+
process.exit(1);
|
|
777
|
+
}
|
|
778
|
+
const r = await getContact(auth.token!, contactId, opts.user, opts.select);
|
|
779
|
+
if (!r.ok || !r.data) {
|
|
780
|
+
console.error(`Error: ${r.error?.message}`);
|
|
781
|
+
process.exit(1);
|
|
782
|
+
}
|
|
783
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
784
|
+
else console.log(JSON.stringify(r.data, null, 2));
|
|
785
|
+
}
|
|
786
|
+
);
|
|
787
|
+
|
|
788
|
+
outlookGraphCommand
|
|
789
|
+
.command('create-contact')
|
|
790
|
+
.description('Create a contact (JSON body per Graph contact resource)')
|
|
791
|
+
.requiredOption('--json-file <path>', 'Path to JSON file')
|
|
792
|
+
.option('--json', 'Echo created contact as JSON')
|
|
793
|
+
.option('--token <token>', 'Use a specific token')
|
|
794
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
795
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
796
|
+
.action(
|
|
797
|
+
async (opts: { jsonFile: string; json?: boolean; token?: string; identity?: string; user?: string }, cmd: any) => {
|
|
798
|
+
checkReadOnly(cmd);
|
|
799
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
800
|
+
if (!auth.success) {
|
|
801
|
+
console.error(`Auth error: ${auth.error}`);
|
|
802
|
+
process.exit(1);
|
|
803
|
+
}
|
|
804
|
+
const raw = await readFile(opts.jsonFile, 'utf-8');
|
|
805
|
+
const body = JSON.parse(raw) as Record<string, unknown>;
|
|
806
|
+
const r = await createContact(auth.token!, body, opts.user);
|
|
807
|
+
if (!r.ok || !r.data) {
|
|
808
|
+
console.error(`Error: ${r.error?.message}`);
|
|
809
|
+
process.exit(1);
|
|
810
|
+
}
|
|
811
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
812
|
+
else console.log(`Created contact: ${r.data.displayName ?? r.data.id} (${r.data.id})`);
|
|
813
|
+
}
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
outlookGraphCommand
|
|
817
|
+
.command('update-contact')
|
|
818
|
+
.description('PATCH a contact (merge JSON from file)')
|
|
819
|
+
.argument('<contactId>', 'Contact id')
|
|
820
|
+
.requiredOption('--json-file <path>', 'Path to JSON patch body')
|
|
821
|
+
.option('--json', 'Echo updated contact as JSON')
|
|
822
|
+
.option('--token <token>', 'Use a specific token')
|
|
823
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
824
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
825
|
+
.action(
|
|
826
|
+
async (
|
|
827
|
+
contactId: string,
|
|
828
|
+
opts: { jsonFile: string; json?: boolean; token?: string; identity?: string; user?: string },
|
|
829
|
+
cmd: any
|
|
830
|
+
) => {
|
|
831
|
+
checkReadOnly(cmd);
|
|
832
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
833
|
+
if (!auth.success) {
|
|
834
|
+
console.error(`Auth error: ${auth.error}`);
|
|
835
|
+
process.exit(1);
|
|
836
|
+
}
|
|
837
|
+
const raw = await readFile(opts.jsonFile, 'utf-8');
|
|
838
|
+
const patch = JSON.parse(raw) as Record<string, unknown>;
|
|
839
|
+
const r = await updateContact(auth.token!, contactId, patch, opts.user);
|
|
840
|
+
if (!r.ok || !r.data) {
|
|
841
|
+
console.error(`Error: ${r.error?.message}`);
|
|
842
|
+
process.exit(1);
|
|
843
|
+
}
|
|
844
|
+
if (opts.json) console.log(JSON.stringify(r.data, null, 2));
|
|
845
|
+
else console.log(`Updated contact: ${r.data.id}`);
|
|
846
|
+
}
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
outlookGraphCommand
|
|
850
|
+
.command('delete-contact')
|
|
851
|
+
.description('Delete a contact')
|
|
852
|
+
.argument('<contactId>', 'Contact id')
|
|
853
|
+
.option('--confirm', 'Confirm delete')
|
|
854
|
+
.option('--token <token>', 'Use a specific token')
|
|
855
|
+
.option('--identity <name>', 'Graph token cache identity (default: default)')
|
|
856
|
+
.option('--user <email>', 'Target user (Graph delegation)')
|
|
857
|
+
.action(
|
|
858
|
+
async (
|
|
859
|
+
contactId: string,
|
|
860
|
+
opts: { confirm?: boolean; token?: string; identity?: string; user?: string },
|
|
861
|
+
cmd: any
|
|
862
|
+
) => {
|
|
863
|
+
checkReadOnly(cmd);
|
|
864
|
+
if (!opts.confirm) {
|
|
865
|
+
console.error('Refusing to delete without --confirm');
|
|
866
|
+
process.exit(1);
|
|
867
|
+
}
|
|
868
|
+
const auth = await resolveGraphAuth({ token: opts.token, identity: opts.identity });
|
|
869
|
+
if (!auth.success) {
|
|
870
|
+
console.error(`Auth error: ${auth.error}`);
|
|
871
|
+
process.exit(1);
|
|
872
|
+
}
|
|
873
|
+
const r = await deleteContact(auth.token!, contactId, opts.user);
|
|
874
|
+
if (!r.ok) {
|
|
875
|
+
console.error(`Error: ${r.error?.message}`);
|
|
876
|
+
process.exit(1);
|
|
877
|
+
}
|
|
878
|
+
console.log('Deleted contact.');
|
|
879
|
+
}
|
|
880
|
+
);
|