@auxiora/connector-microsoft 1.0.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.
@@ -0,0 +1,657 @@
1
+ import { defineConnector } from '@auxiora/connectors';
2
+ const GRAPH_BASE = 'https://graph.microsoft.com/v1.0';
3
+ async function graphFetch(token, path, options) {
4
+ const res = await fetch(`${GRAPH_BASE}${path}`, {
5
+ method: options?.method ?? 'GET',
6
+ headers: {
7
+ 'Authorization': `Bearer ${token}`,
8
+ 'Content-Type': 'application/json',
9
+ },
10
+ body: options?.body ? JSON.stringify(options.body) : undefined,
11
+ });
12
+ if (!res.ok) {
13
+ const err = await res.json().catch(() => ({}));
14
+ throw new Error(`Graph API error: ${res.status} ${err.error?.message ?? res.statusText}`);
15
+ }
16
+ if (res.status === 204)
17
+ return undefined;
18
+ return res.json();
19
+ }
20
+ export const microsoftConnector = defineConnector({
21
+ id: 'microsoft-365',
22
+ name: 'Microsoft 365',
23
+ description: 'Integration with Outlook Mail, Calendar, OneDrive, and Contacts via Microsoft Graph API',
24
+ version: '1.0.0',
25
+ category: 'productivity',
26
+ icon: 'microsoft',
27
+ auth: {
28
+ type: 'oauth2',
29
+ oauth2: {
30
+ authUrl: 'https://login.microsoftonline.com/common/oauth2/v2/authorize',
31
+ tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2/token',
32
+ scopes: [
33
+ 'Mail.ReadWrite',
34
+ 'Mail.Send',
35
+ 'Calendars.ReadWrite',
36
+ 'Contacts.Read',
37
+ 'Files.ReadWrite',
38
+ 'User.Read',
39
+ ],
40
+ },
41
+ },
42
+ actions: [
43
+ // --- Mail ---
44
+ {
45
+ id: 'mail-list-messages',
46
+ name: 'List Mail Messages',
47
+ description: 'List recent emails from Outlook',
48
+ trustMinimum: 1,
49
+ trustDomain: 'email',
50
+ reversible: false,
51
+ sideEffects: false,
52
+ params: {
53
+ folderId: { type: 'string', description: 'Mail folder ID' },
54
+ maxResults: { type: 'number', description: 'Max messages to return', default: 10 },
55
+ query: { type: 'string', description: 'OData filter query' },
56
+ },
57
+ },
58
+ {
59
+ id: 'mail-read-message',
60
+ name: 'Read Mail Message',
61
+ description: 'Read a specific email message',
62
+ trustMinimum: 1,
63
+ trustDomain: 'email',
64
+ reversible: false,
65
+ sideEffects: false,
66
+ params: {
67
+ messageId: { type: 'string', description: 'Message ID', required: true },
68
+ },
69
+ },
70
+ {
71
+ id: 'mail-send',
72
+ name: 'Send Email',
73
+ description: 'Send an email via Outlook',
74
+ trustMinimum: 3,
75
+ trustDomain: 'email',
76
+ reversible: false,
77
+ sideEffects: true,
78
+ params: {
79
+ to: { type: 'string', description: 'Recipient email', required: true },
80
+ subject: { type: 'string', description: 'Email subject', required: true },
81
+ body: { type: 'string', description: 'Email body', required: true },
82
+ cc: { type: 'string', description: 'CC recipients' },
83
+ bcc: { type: 'string', description: 'BCC recipients' },
84
+ },
85
+ },
86
+ {
87
+ id: 'mail-reply',
88
+ name: 'Reply to Email',
89
+ description: 'Reply to an email message',
90
+ trustMinimum: 3,
91
+ trustDomain: 'email',
92
+ reversible: false,
93
+ sideEffects: true,
94
+ params: {
95
+ messageId: { type: 'string', description: 'Message ID to reply to', required: true },
96
+ body: { type: 'string', description: 'Reply body', required: true },
97
+ replyAll: { type: 'boolean', description: 'Reply to all recipients' },
98
+ },
99
+ },
100
+ {
101
+ id: 'mail-forward',
102
+ name: 'Forward Email',
103
+ description: 'Forward an email message',
104
+ trustMinimum: 3,
105
+ trustDomain: 'email',
106
+ reversible: false,
107
+ sideEffects: true,
108
+ params: {
109
+ messageId: { type: 'string', description: 'Message ID to forward', required: true },
110
+ to: { type: 'string', description: 'Recipient email', required: true },
111
+ comment: { type: 'string', description: 'Comment to include' },
112
+ },
113
+ },
114
+ {
115
+ id: 'mail-move',
116
+ name: 'Move Email',
117
+ description: 'Move an email to a different folder',
118
+ trustMinimum: 2,
119
+ trustDomain: 'email',
120
+ reversible: true,
121
+ sideEffects: true,
122
+ params: {
123
+ messageId: { type: 'string', description: 'Message ID', required: true },
124
+ destinationFolderId: { type: 'string', description: 'Destination folder ID', required: true },
125
+ },
126
+ },
127
+ {
128
+ id: 'mail-archive',
129
+ name: 'Archive Email',
130
+ description: 'Archive an email message',
131
+ trustMinimum: 2,
132
+ trustDomain: 'email',
133
+ reversible: true,
134
+ sideEffects: true,
135
+ params: {
136
+ messageId: { type: 'string', description: 'Message ID', required: true },
137
+ },
138
+ },
139
+ {
140
+ id: 'mail-flag',
141
+ name: 'Flag Email',
142
+ description: 'Flag an email message for follow-up',
143
+ trustMinimum: 1,
144
+ trustDomain: 'email',
145
+ reversible: true,
146
+ sideEffects: true,
147
+ params: {
148
+ messageId: { type: 'string', description: 'Message ID', required: true },
149
+ flagStatus: { type: 'string', description: 'Flag status', default: 'flagged' },
150
+ },
151
+ },
152
+ {
153
+ id: 'mail-search',
154
+ name: 'Search Mail',
155
+ description: 'Search emails in Outlook',
156
+ trustMinimum: 1,
157
+ trustDomain: 'email',
158
+ reversible: false,
159
+ sideEffects: false,
160
+ params: {
161
+ query: { type: 'string', description: 'Search query', required: true },
162
+ maxResults: { type: 'number', description: 'Max results', default: 10 },
163
+ },
164
+ },
165
+ {
166
+ id: 'mail-draft',
167
+ name: 'Create Draft',
168
+ description: 'Create a draft email in Outlook',
169
+ trustMinimum: 2,
170
+ trustDomain: 'email',
171
+ reversible: true,
172
+ sideEffects: true,
173
+ params: {
174
+ to: { type: 'string', description: 'Recipient email', required: true },
175
+ subject: { type: 'string', description: 'Email subject', required: true },
176
+ body: { type: 'string', description: 'Email body', required: true },
177
+ },
178
+ },
179
+ // --- Calendar ---
180
+ {
181
+ id: 'calendar-list-events',
182
+ name: 'List Calendar Events',
183
+ description: 'List upcoming events from Outlook Calendar',
184
+ trustMinimum: 1,
185
+ trustDomain: 'calendar',
186
+ reversible: false,
187
+ sideEffects: false,
188
+ params: {
189
+ calendarId: { type: 'string', description: 'Calendar ID' },
190
+ maxResults: { type: 'number', description: 'Max events to return', default: 10 },
191
+ startDateTime: { type: 'string', description: 'Start time (ISO 8601)' },
192
+ endDateTime: { type: 'string', description: 'End time (ISO 8601)' },
193
+ },
194
+ },
195
+ {
196
+ id: 'calendar-create-event',
197
+ name: 'Create Calendar Event',
198
+ description: 'Create a new event in Outlook Calendar',
199
+ trustMinimum: 2,
200
+ trustDomain: 'calendar',
201
+ reversible: true,
202
+ sideEffects: true,
203
+ params: {
204
+ subject: { type: 'string', description: 'Event subject', required: true },
205
+ start: { type: 'string', description: 'Start time (ISO 8601)', required: true },
206
+ end: { type: 'string', description: 'End time (ISO 8601)', required: true },
207
+ body: { type: 'string', description: 'Event body' },
208
+ attendees: { type: 'array', description: 'List of attendee emails' },
209
+ location: { type: 'string', description: 'Event location' },
210
+ isOnlineMeeting: { type: 'boolean', description: 'Create as online meeting' },
211
+ },
212
+ },
213
+ {
214
+ id: 'calendar-update-event',
215
+ name: 'Update Calendar Event',
216
+ description: 'Update an existing calendar event',
217
+ trustMinimum: 2,
218
+ trustDomain: 'calendar',
219
+ reversible: true,
220
+ sideEffects: true,
221
+ params: {
222
+ eventId: { type: 'string', description: 'Event ID', required: true },
223
+ subject: { type: 'string', description: 'Updated subject' },
224
+ start: { type: 'string', description: 'Updated start time' },
225
+ end: { type: 'string', description: 'Updated end time' },
226
+ },
227
+ },
228
+ {
229
+ id: 'calendar-delete-event',
230
+ name: 'Delete Calendar Event',
231
+ description: 'Delete a calendar event',
232
+ trustMinimum: 3,
233
+ trustDomain: 'calendar',
234
+ reversible: false,
235
+ sideEffects: true,
236
+ params: {
237
+ eventId: { type: 'string', description: 'Event ID', required: true },
238
+ },
239
+ },
240
+ {
241
+ id: 'calendar-find-availability',
242
+ name: 'Find Availability',
243
+ description: 'Find free time slots for attendees',
244
+ trustMinimum: 1,
245
+ trustDomain: 'calendar',
246
+ reversible: false,
247
+ sideEffects: false,
248
+ params: {
249
+ attendees: { type: 'array', description: 'List of attendee emails', required: true },
250
+ startDateTime: { type: 'string', description: 'Start of window (ISO 8601)', required: true },
251
+ endDateTime: { type: 'string', description: 'End of window (ISO 8601)', required: true },
252
+ durationMinutes: { type: 'number', description: 'Desired slot duration in minutes', default: 30 },
253
+ },
254
+ },
255
+ // --- Contacts ---
256
+ {
257
+ id: 'contacts-list',
258
+ name: 'List Contacts',
259
+ description: 'List contacts from Outlook',
260
+ trustMinimum: 1,
261
+ trustDomain: 'integrations',
262
+ reversible: false,
263
+ sideEffects: false,
264
+ params: {
265
+ maxResults: { type: 'number', description: 'Max contacts to return', default: 20 },
266
+ search: { type: 'string', description: 'Search query' },
267
+ },
268
+ },
269
+ {
270
+ id: 'contacts-get',
271
+ name: 'Get Contact',
272
+ description: 'Get a specific contact',
273
+ trustMinimum: 1,
274
+ trustDomain: 'integrations',
275
+ reversible: false,
276
+ sideEffects: false,
277
+ params: {
278
+ contactId: { type: 'string', description: 'Contact ID', required: true },
279
+ },
280
+ },
281
+ // --- OneDrive ---
282
+ {
283
+ id: 'files-list',
284
+ name: 'List OneDrive Files',
285
+ description: 'List files in OneDrive',
286
+ trustMinimum: 1,
287
+ trustDomain: 'files',
288
+ reversible: false,
289
+ sideEffects: false,
290
+ params: {
291
+ folderId: { type: 'string', description: 'Folder ID (default: root)' },
292
+ maxResults: { type: 'number', description: 'Max files to return', default: 20 },
293
+ },
294
+ },
295
+ {
296
+ id: 'files-download',
297
+ name: 'Download File',
298
+ description: 'Download a file from OneDrive',
299
+ trustMinimum: 1,
300
+ trustDomain: 'files',
301
+ reversible: false,
302
+ sideEffects: false,
303
+ params: {
304
+ fileId: { type: 'string', description: 'File ID', required: true },
305
+ },
306
+ },
307
+ {
308
+ id: 'files-upload',
309
+ name: 'Upload File',
310
+ description: 'Upload a file to OneDrive',
311
+ trustMinimum: 2,
312
+ trustDomain: 'files',
313
+ reversible: true,
314
+ sideEffects: true,
315
+ params: {
316
+ name: { type: 'string', description: 'File name', required: true },
317
+ content: { type: 'string', description: 'File content', required: true },
318
+ folderId: { type: 'string', description: 'Parent folder ID' },
319
+ },
320
+ },
321
+ {
322
+ id: 'files-search',
323
+ name: 'Search Files',
324
+ description: 'Search files in OneDrive',
325
+ trustMinimum: 1,
326
+ trustDomain: 'files',
327
+ reversible: false,
328
+ sideEffects: false,
329
+ params: {
330
+ query: { type: 'string', description: 'Search query', required: true },
331
+ maxResults: { type: 'number', description: 'Max results', default: 10 },
332
+ },
333
+ },
334
+ ],
335
+ triggers: [
336
+ {
337
+ id: 'new-email',
338
+ name: 'New Email',
339
+ description: 'Triggered when a new email arrives',
340
+ type: 'poll',
341
+ pollIntervalMs: 60_000,
342
+ },
343
+ {
344
+ id: 'event-starting-soon',
345
+ name: 'Event Starting Soon',
346
+ description: 'Triggered when a calendar event is about to start',
347
+ type: 'poll',
348
+ pollIntervalMs: 60_000,
349
+ },
350
+ {
351
+ id: 'calendar-event-created',
352
+ name: 'Calendar Event Created',
353
+ description: 'Triggered when a new calendar event is created',
354
+ type: 'poll',
355
+ pollIntervalMs: 300_000,
356
+ },
357
+ ],
358
+ entities: [
359
+ {
360
+ id: 'email-message',
361
+ name: 'Email Message',
362
+ description: 'An Outlook email message',
363
+ fields: { id: 'string', from: 'string', to: 'string', subject: 'string', bodyPreview: 'string', receivedDateTime: 'string', importance: 'string', isRead: 'string' },
364
+ },
365
+ {
366
+ id: 'calendar-event',
367
+ name: 'Calendar Event',
368
+ description: 'An Outlook Calendar event',
369
+ fields: { id: 'string', subject: 'string', start: 'string', end: 'string', attendees: 'array', location: 'string', isOnlineMeeting: 'string' },
370
+ },
371
+ {
372
+ id: 'contact',
373
+ name: 'Contact',
374
+ description: 'An Outlook contact',
375
+ fields: { id: 'string', displayName: 'string', emailAddresses: 'array', companyName: 'string', jobTitle: 'string' },
376
+ },
377
+ {
378
+ id: 'drive-item',
379
+ name: 'Drive Item',
380
+ description: 'A OneDrive file or folder',
381
+ fields: { id: 'string', name: 'string', size: 'number', lastModifiedDateTime: 'string', webUrl: 'string' },
382
+ },
383
+ ],
384
+ async executeAction(actionId, params, token) {
385
+ switch (actionId) {
386
+ // --- Mail ---
387
+ case 'mail-list-messages': {
388
+ const folderId = params.folderId ?? 'inbox';
389
+ const top = params.maxResults ?? 10;
390
+ let path = `/me/mailFolders/${encodeURIComponent(folderId)}/messages?$top=${top}`;
391
+ if (params.query)
392
+ path += `&$filter=${encodeURIComponent(params.query)}`;
393
+ const res = await graphFetch(token, path);
394
+ return { messages: res.value, folderId };
395
+ }
396
+ case 'mail-read-message': {
397
+ const msg = await graphFetch(token, `/me/messages/${encodeURIComponent(params.messageId)}`);
398
+ return msg;
399
+ }
400
+ case 'mail-send': {
401
+ const toRecipients = [{ emailAddress: { address: params.to } }];
402
+ const ccRecipients = params.cc
403
+ ? params.cc.split(',').map(e => ({ emailAddress: { address: e.trim() } }))
404
+ : undefined;
405
+ const bccRecipients = params.bcc
406
+ ? params.bcc.split(',').map(e => ({ emailAddress: { address: e.trim() } }))
407
+ : undefined;
408
+ await graphFetch(token, '/me/sendMail', {
409
+ method: 'POST',
410
+ body: {
411
+ message: {
412
+ toRecipients,
413
+ subject: params.subject,
414
+ body: { contentType: 'Text', content: params.body },
415
+ ...(ccRecipients ? { ccRecipients } : {}),
416
+ ...(bccRecipients ? { bccRecipients } : {}),
417
+ },
418
+ },
419
+ });
420
+ return { status: 'sent' };
421
+ }
422
+ case 'mail-reply': {
423
+ const action = params.replyAll ? 'replyAll' : 'reply';
424
+ await graphFetch(token, `/me/messages/${encodeURIComponent(params.messageId)}/${action}`, {
425
+ method: 'POST',
426
+ body: { comment: params.body },
427
+ });
428
+ return { messageId: params.messageId, status: 'replied' };
429
+ }
430
+ case 'mail-forward': {
431
+ await graphFetch(token, `/me/messages/${encodeURIComponent(params.messageId)}/forward`, {
432
+ method: 'POST',
433
+ body: {
434
+ toRecipients: [{ emailAddress: { address: params.to } }],
435
+ comment: params.comment ?? '',
436
+ },
437
+ });
438
+ return { messageId: params.messageId, status: 'forwarded', to: params.to };
439
+ }
440
+ case 'mail-move': {
441
+ const moved = await graphFetch(token, `/me/messages/${encodeURIComponent(params.messageId)}/move`, {
442
+ method: 'POST',
443
+ body: { destinationId: params.destinationFolderId },
444
+ });
445
+ return { messageId: moved.id, status: 'moved', destinationFolderId: params.destinationFolderId };
446
+ }
447
+ case 'mail-archive': {
448
+ const archived = await graphFetch(token, `/me/messages/${encodeURIComponent(params.messageId)}/move`, {
449
+ method: 'POST',
450
+ body: { destinationId: 'archive' },
451
+ });
452
+ return { messageId: archived.id, status: 'archived' };
453
+ }
454
+ case 'mail-flag': {
455
+ const flagged = await graphFetch(token, `/me/messages/${encodeURIComponent(params.messageId)}`, {
456
+ method: 'PATCH',
457
+ body: { flag: { flagStatus: params.flagStatus ?? 'flagged' } },
458
+ });
459
+ return { messageId: flagged.id, status: 'flagged' };
460
+ }
461
+ case 'mail-search': {
462
+ const top = params.maxResults ?? 10;
463
+ const query = encodeURIComponent(`"${params.query}"`);
464
+ const res = await graphFetch(token, `/me/messages?$search=${query}&$top=${top}`);
465
+ return { messages: res.value, query: params.query };
466
+ }
467
+ case 'mail-draft': {
468
+ const draft = await graphFetch(token, '/me/messages', {
469
+ method: 'POST',
470
+ body: {
471
+ toRecipients: [{ emailAddress: { address: params.to } }],
472
+ subject: params.subject,
473
+ body: { contentType: 'Text', content: params.body },
474
+ isDraft: true,
475
+ },
476
+ });
477
+ return { draftId: draft.id, status: 'created' };
478
+ }
479
+ // --- Calendar ---
480
+ case 'calendar-list-events': {
481
+ const top = params.maxResults ?? 10;
482
+ let res;
483
+ if (params.startDateTime && params.endDateTime) {
484
+ const start = encodeURIComponent(params.startDateTime);
485
+ const end = encodeURIComponent(params.endDateTime);
486
+ res = await graphFetch(token, `/me/calendarView?startDateTime=${start}&endDateTime=${end}&$top=${top}`);
487
+ }
488
+ else {
489
+ res = await graphFetch(token, `/me/events?$top=${top}&$orderby=start/dateTime`);
490
+ }
491
+ return { events: res.value };
492
+ }
493
+ case 'calendar-create-event': {
494
+ const attendees = params.attendees
495
+ ? params.attendees.map(email => ({
496
+ emailAddress: { address: email },
497
+ type: 'required',
498
+ }))
499
+ : undefined;
500
+ const eventBody = {
501
+ subject: params.subject,
502
+ start: { dateTime: params.start, timeZone: 'UTC' },
503
+ end: { dateTime: params.end, timeZone: 'UTC' },
504
+ };
505
+ if (params.body)
506
+ eventBody.body = { contentType: 'Text', content: params.body };
507
+ if (attendees)
508
+ eventBody.attendees = attendees;
509
+ if (params.location)
510
+ eventBody.location = { displayName: params.location };
511
+ if (params.isOnlineMeeting)
512
+ eventBody.isOnlineMeeting = true;
513
+ const created = await graphFetch(token, '/me/events', {
514
+ method: 'POST',
515
+ body: eventBody,
516
+ });
517
+ return { eventId: created.id, status: 'created', subject: created.subject };
518
+ }
519
+ case 'calendar-update-event': {
520
+ const updates = {};
521
+ if (params.subject)
522
+ updates.subject = params.subject;
523
+ if (params.start)
524
+ updates.start = { dateTime: params.start, timeZone: 'UTC' };
525
+ if (params.end)
526
+ updates.end = { dateTime: params.end, timeZone: 'UTC' };
527
+ const updated = await graphFetch(token, `/me/events/${encodeURIComponent(params.eventId)}`, {
528
+ method: 'PATCH',
529
+ body: updates,
530
+ });
531
+ return { eventId: updated.id, status: 'updated' };
532
+ }
533
+ case 'calendar-delete-event': {
534
+ await graphFetch(token, `/me/events/${encodeURIComponent(params.eventId)}`, {
535
+ method: 'DELETE',
536
+ });
537
+ return { eventId: params.eventId, status: 'deleted' };
538
+ }
539
+ case 'calendar-find-availability': {
540
+ const schedules = params.attendees;
541
+ const res = await graphFetch(token, '/me/calendar/getSchedule', {
542
+ method: 'POST',
543
+ body: {
544
+ schedules,
545
+ startTime: { dateTime: params.startDateTime, timeZone: 'UTC' },
546
+ endTime: { dateTime: params.endDateTime, timeZone: 'UTC' },
547
+ availabilityViewInterval: params.durationMinutes ?? 30,
548
+ },
549
+ });
550
+ return res;
551
+ }
552
+ // --- Contacts ---
553
+ case 'contacts-list': {
554
+ const top = params.maxResults ?? 20;
555
+ let path = `/me/contacts?$top=${top}`;
556
+ if (params.search)
557
+ path += `&$search="${encodeURIComponent(params.search)}"`;
558
+ const res = await graphFetch(token, path);
559
+ return { contacts: res.value };
560
+ }
561
+ case 'contacts-get': {
562
+ const contact = await graphFetch(token, `/me/contacts/${encodeURIComponent(params.contactId)}`);
563
+ return contact;
564
+ }
565
+ // --- OneDrive ---
566
+ case 'files-list': {
567
+ const top = params.maxResults ?? 20;
568
+ const path = params.folderId
569
+ ? `/me/drive/items/${encodeURIComponent(params.folderId)}/children?$top=${top}`
570
+ : `/me/drive/root/children?$top=${top}`;
571
+ const res = await graphFetch(token, path);
572
+ return { files: res.value };
573
+ }
574
+ case 'files-download': {
575
+ const downloadRes = await fetch(`${GRAPH_BASE}/me/drive/items/${encodeURIComponent(params.fileId)}/content`, {
576
+ headers: { 'Authorization': `Bearer ${token}` },
577
+ redirect: 'follow',
578
+ });
579
+ if (!downloadRes.ok) {
580
+ throw new Error(`Graph API error: ${downloadRes.status} ${downloadRes.statusText}`);
581
+ }
582
+ const content = await downloadRes.text();
583
+ return { fileId: params.fileId, content };
584
+ }
585
+ case 'files-upload': {
586
+ const fileName = encodeURIComponent(params.name);
587
+ const uploadPath = params.folderId
588
+ ? `/me/drive/items/${encodeURIComponent(params.folderId)}:/${fileName}:/content`
589
+ : `/me/drive/root:/${fileName}:/content`;
590
+ const uploadRes = await fetch(`${GRAPH_BASE}${uploadPath}`, {
591
+ method: 'PUT',
592
+ headers: {
593
+ 'Authorization': `Bearer ${token}`,
594
+ 'Content-Type': 'application/octet-stream',
595
+ },
596
+ body: params.content,
597
+ });
598
+ if (!uploadRes.ok) {
599
+ const err = await uploadRes.json().catch(() => ({}));
600
+ throw new Error(`Graph API error: ${uploadRes.status} ${err.error?.message ?? uploadRes.statusText}`);
601
+ }
602
+ const uploaded = await uploadRes.json();
603
+ return { fileId: uploaded.id, status: 'uploaded', name: uploaded.name };
604
+ }
605
+ case 'files-search': {
606
+ const q = encodeURIComponent(params.query);
607
+ const top = params.maxResults ?? 10;
608
+ const res = await graphFetch(token, `/me/drive/root/search(q='${q}')?$top=${top}`);
609
+ return { files: res.value, query: params.query };
610
+ }
611
+ default:
612
+ throw new Error(`Unknown action: ${actionId}`);
613
+ }
614
+ },
615
+ async pollTrigger(triggerId, token, lastPollAt) {
616
+ switch (triggerId) {
617
+ case 'new-email': {
618
+ const res = await graphFetch(token, '/me/mailFolders/inbox/messages?$orderby=receivedDateTime desc&$top=10');
619
+ const since = lastPollAt ?? (Date.now() - 120_000);
620
+ const newMessages = res.value.filter(m => new Date(m.receivedDateTime).getTime() > since);
621
+ return newMessages.map(m => ({
622
+ triggerId: 'new-email',
623
+ connectorId: 'microsoft-365',
624
+ timestamp: new Date(m.receivedDateTime).getTime(),
625
+ data: { messageId: m.id, subject: m.subject, from: m.from },
626
+ }));
627
+ }
628
+ case 'event-starting-soon': {
629
+ const now = new Date();
630
+ const soon = new Date(now.getTime() + 15 * 60_000);
631
+ const start = encodeURIComponent(now.toISOString());
632
+ const end = encodeURIComponent(soon.toISOString());
633
+ const res = await graphFetch(token, `/me/calendarView?startDateTime=${start}&endDateTime=${end}&$top=10`);
634
+ return res.value.map(e => ({
635
+ triggerId: 'event-starting-soon',
636
+ connectorId: 'microsoft-365',
637
+ timestamp: Date.now(),
638
+ data: { eventId: e.id, subject: e.subject, start: e.start, end: e.end },
639
+ }));
640
+ }
641
+ case 'calendar-event-created': {
642
+ const res = await graphFetch(token, '/me/events?$orderby=createdDateTime desc&$top=10');
643
+ const since = lastPollAt ?? (Date.now() - 300_000);
644
+ const newEvents = res.value.filter(e => new Date(e.createdDateTime).getTime() > since);
645
+ return newEvents.map(e => ({
646
+ triggerId: 'calendar-event-created',
647
+ connectorId: 'microsoft-365',
648
+ timestamp: new Date(e.createdDateTime).getTime(),
649
+ data: { eventId: e.id, subject: e.subject, start: e.start },
650
+ }));
651
+ }
652
+ default:
653
+ return [];
654
+ }
655
+ },
656
+ });
657
+ //# sourceMappingURL=connector.js.map