1 | |
2 |
|
3 | export type DynSelect_calendar = string |
4 |
|
5 | export async function calendar(auth: RT.Outlook) { |
6 | const r = await fetch( |
7 | "https://graph.microsoft.com/v1.0/me/calendars?$top=100&$select=id,name", |
8 | { |
9 | headers: { |
10 | Authorization: `Bearer ${auth.token}`, |
11 | Accept: "application/json", |
12 | }, |
13 | } |
14 | ) |
15 | if (!r.ok) throw new Error(`${r.status} ${await r.text()}`) |
16 | const { value } = (await r.json()) as { |
17 | value: { id: string; name: string }[] |
18 | } |
19 | return value.map((c) => ({ value: c.id, label: c.name })) |
20 | } |
21 |
|
22 | |
23 | * Create Calendar Event |
24 | * Create an event in the default calendar or a chosen one. `start` and `end` are local times in `time_zone` (`2026-01-15T14:00:00`); attendees receive an invitation. `recurrence` takes a Graph patternedRecurrence object, e.g. `{"pattern":{"type":"weekly","interval":1,"daysOfWeek":["monday"]},"range":{"type":"noEnd","startDate":"2026-01-19"}}`; `extra` takes any other event property. Requires Calendars.ReadWrite (a connection default). |
25 | */ |
26 | export async function main( |
27 | auth: RT.Outlook, |
28 | subject: string, |
29 | start: string, |
30 | end: string, |
31 | time_zone: string = "UTC", |
32 | body: string | undefined, |
33 | content_type: "HTML" | "Text" = "HTML", |
34 | location: string | undefined, |
35 | attendees: string[] | undefined, |
36 | is_all_day: boolean = false, |
37 | is_online_meeting: boolean = false, |
38 | calendar: DynSelect_calendar | undefined, |
39 | recurrence: { [key: string]: any } | undefined, |
40 | extra: { [key: string]: any } | undefined |
41 | ) { |
42 | const base = `https://graph.microsoft.com/v1.0/me${ |
43 | calendar != null && calendar !== "" |
44 | ? `/calendars/${encodeURIComponent(calendar)}` |
45 | : "" |
46 | }` |
47 | const event: { [key: string]: any } = { |
48 | ...(extra ?? {}), |
49 | subject, |
50 | start: { dateTime: start, timeZone: time_zone }, |
51 | end: { dateTime: end, timeZone: time_zone }, |
52 | isAllDay: is_all_day, |
53 | isOnlineMeeting: is_online_meeting, |
54 | } |
55 | if (body != null && body !== "") { |
56 | event.body = { contentType: content_type, content: body } |
57 | } |
58 | if (location != null && location !== "") { |
59 | event.location = { displayName: location } |
60 | } |
61 | if (attendees?.length) { |
62 | event.attendees = attendees.map((address) => ({ |
63 | emailAddress: { address }, |
64 | type: "required", |
65 | })) |
66 | } |
67 | if (recurrence != null && Object.keys(recurrence).length > 0) { |
68 | event.recurrence = recurrence |
69 | } |
70 |
|
71 | const response = await fetch(`${base}/events`, { |
72 | method: "POST", |
73 | headers: { |
74 | Authorization: `Bearer ${auth.token}`, |
75 | "Content-Type": "application/json", |
76 | Accept: "application/json", |
77 | }, |
78 | body: JSON.stringify(event), |
79 | }) |
80 |
|
81 | if (!response.ok) { |
82 | throw new Error(`${response.status} ${await response.text()}`) |
83 | } |
84 |
|
85 | return await response.json() |
86 | } |
87 |
|