@memberjunction/communication-ms-graph 6.1.0-edge.5 → 6.1.0-edge.7
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/README.md +41 -1
- package/dist/MSGraphProvider.d.ts +52 -1
- package/dist/MSGraphProvider.d.ts.map +1 -1
- package/dist/MSGraphProvider.js +226 -38
- package/dist/MSGraphProvider.js.map +1 -1
- package/dist/__tests__/GetEvents.test.d.ts +2 -0
- package/dist/__tests__/GetEvents.test.d.ts.map +1 -0
- package/dist/__tests__/GetEvents.test.js +230 -0
- package/dist/__tests__/GetEvents.test.js.map +1 -0
- package/dist/__tests__/MSGraphProvider.test.js +211 -38
- package/dist/__tests__/MSGraphProvider.test.js.map +1 -1
- package/dist/__tests__/graph-mocks.d.ts +63 -0
- package/dist/__tests__/graph-mocks.d.ts.map +1 -0
- package/dist/__tests__/graph-mocks.js +103 -0
- package/dist/__tests__/graph-mocks.js.map +1 -0
- package/package.json +9 -9
- package/readme.md +41 -1
package/README.md
CHANGED
|
@@ -60,11 +60,17 @@ AZURE_ACCOUNT_EMAIL=mailbox@yourdomain.com
|
|
|
60
60
|
| `Mail.Send` | SendSingleMessage, ForwardMessage, ReplyToMessage |
|
|
61
61
|
| `Mail.Read` | GetMessages, GetSingleMessage, SearchMessages, ListFolders, ListAttachments, DownloadAttachment |
|
|
62
62
|
| `Mail.ReadWrite` | CreateDraft, DeleteMessage, MoveMessage, MarkAsRead, ArchiveMessage |
|
|
63
|
+
| `Calendars.Read` | GetEvents |
|
|
63
64
|
| `User.Read.All` | GetServiceAccount (user lookup, optional) |
|
|
64
65
|
|
|
66
|
+
`Calendars.Read` is sufficient for `GetEvents`; `Calendars.ReadWrite` is not required, since nothing
|
|
67
|
+
here creates or modifies an event. As **Application** permissions these are granted against the
|
|
68
|
+
tenant, not against one mailbox — narrowing an app to specific mailboxes is done in Exchange with
|
|
69
|
+
RBAC for Applications, not by these grants.
|
|
70
|
+
|
|
65
71
|
## Supported Operations
|
|
66
72
|
|
|
67
|
-
This provider supports all
|
|
73
|
+
This provider supports all 15 operations defined in `BaseCommunicationProvider`:
|
|
68
74
|
|
|
69
75
|
| Operation | Description |
|
|
70
76
|
|-----------|-------------|
|
|
@@ -82,6 +88,7 @@ This provider supports all 14 operations defined in `BaseCommunicationProvider`:
|
|
|
82
88
|
| `SearchMessages` | Full-text search with KQL syntax and date filtering |
|
|
83
89
|
| `ListAttachments` | List attachments on a message |
|
|
84
90
|
| `DownloadAttachment` | Download attachment content as base64/Buffer |
|
|
91
|
+
| `GetEvents` | Read calendar events for one mailbox |
|
|
85
92
|
|
|
86
93
|
## Usage
|
|
87
94
|
|
|
@@ -151,6 +158,39 @@ result.Messages.forEach(msg => {
|
|
|
151
158
|
});
|
|
152
159
|
```
|
|
153
160
|
|
|
161
|
+
### Reading Calendar Events
|
|
162
|
+
|
|
163
|
+
Requires `Calendars.Read`. **Whether you pass a window changes what comes back**, so `GetEvents`
|
|
164
|
+
reports which it did via `RecurrenceExpanded` rather than leaving you to guess:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const provider = engine.GetProvider('Microsoft Graph');
|
|
168
|
+
|
|
169
|
+
// With a window -> /calendarView: a recurring series is EXPANDED into one entry per occurrence.
|
|
170
|
+
const occurrences = await provider.GetEvents({
|
|
171
|
+
Identifier: 'rep@example.com',
|
|
172
|
+
NumEvents: 50,
|
|
173
|
+
StartDateTime: new Date('2026-09-01T00:00:00Z'),
|
|
174
|
+
EndDateTime: new Date('2026-09-08T00:00:00Z')
|
|
175
|
+
});
|
|
176
|
+
console.log(occurrences.RecurrenceExpanded); // true
|
|
177
|
+
|
|
178
|
+
// Without one -> /events: a weekly stand-up is ONE row, the series master, whose start time is
|
|
179
|
+
// whenever the series began — possibly years ago.
|
|
180
|
+
const masters = await provider.GetEvents({ Identifier: 'rep@example.com', NumEvents: 50 });
|
|
181
|
+
console.log(masters.RecurrenceExpanded); // false
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Three things worth knowing before syncing on this:
|
|
185
|
+
|
|
186
|
+
- **The window selects overlap, not start times.** An event that began before `StartDateTime` and is
|
|
187
|
+
still running when the window opens is returned. An event straddling a boundary therefore appears
|
|
188
|
+
in both adjacent windows — dedupe on the event id.
|
|
189
|
+
- **`NumEvents` is one page.** It becomes `$top`; there is no `@odata.nextLink` following. To cover a
|
|
190
|
+
period completely, narrow the window rather than raise the number.
|
|
191
|
+
- **Cancelled events are excluded by default** and cannot be recovered after the fact — Graph does not
|
|
192
|
+
return them once filtered. Pass `IncludeCancelled: true` if you are logging history.
|
|
193
|
+
|
|
154
194
|
### Searching Messages
|
|
155
195
|
|
|
156
196
|
MS Graph supports KQL (Keyword Query Language) for search:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseCommunicationProvider, CreateDraftParams, CreateDraftResult, ForwardMessageParams, ForwardMessageResult, GetMessagesParams, GetMessagesResult, GetSingleMessageParams, GetSingleMessageResult, DeleteMessageParams, DeleteMessageResult, MoveMessageParams, MoveMessageResult, ListFoldersParams, ListFoldersResult, MarkAsReadParams, MarkAsReadResult, ArchiveMessageParams, ArchiveMessageResult, SearchMessagesParams, SearchMessagesResult, ListAttachmentsParams, ListAttachmentsResult, DownloadAttachmentParams, DownloadAttachmentResult, ProviderOperation, MessageResult, ProcessedMessage, ProviderCredentialsBase, ReplyToMessageParams, ReplyToMessageResult, CreateSubscriptionParams, RenewSubscriptionParams, DeleteSubscriptionParams, SubscriptionResult, SubscriptionCapabilities, WebhookNotificationInput, ParseNotificationResult, BaseMessageResult } from "@memberjunction/communication-types";
|
|
1
|
+
import { BaseCommunicationProvider, MessageRetrievalCapabilities, CreateDraftParams, CreateDraftResult, ForwardMessageParams, ForwardMessageResult, GetEventsParams, GetEventsResult, GetMessagesParams, GetMessagesResult, GetSingleMessageParams, GetSingleMessageResult, DeleteMessageParams, DeleteMessageResult, MoveMessageParams, MoveMessageResult, ListFoldersParams, ListFoldersResult, MarkAsReadParams, MarkAsReadResult, ArchiveMessageParams, ArchiveMessageResult, SearchMessagesParams, SearchMessagesResult, ListAttachmentsParams, ListAttachmentsResult, DownloadAttachmentParams, DownloadAttachmentResult, ProviderOperation, MessageResult, ProcessedMessage, ProviderCredentialsBase, ReplyToMessageParams, ReplyToMessageResult, CreateSubscriptionParams, RenewSubscriptionParams, DeleteSubscriptionParams, SubscriptionResult, SubscriptionCapabilities, WebhookNotificationInput, ParseNotificationResult, BaseMessageResult } from "@memberjunction/communication-types";
|
|
2
2
|
import { Client } from '@microsoft/microsoft-graph-client';
|
|
3
3
|
import { Message } from "@microsoft/microsoft-graph-types";
|
|
4
4
|
/**
|
|
@@ -78,6 +78,11 @@ export interface MSGraphCredentials extends ProviderCredentialsBase {
|
|
|
78
78
|
* ```
|
|
79
79
|
*/
|
|
80
80
|
export declare class MSGraphProvider extends BaseCommunicationProvider {
|
|
81
|
+
/**
|
|
82
|
+
* Graph filters both of these server-side, so neither is emulated here — `receivedDateTime`
|
|
83
|
+
* comparisons and `isRead` are ordinary `$filter` clauses.
|
|
84
|
+
*/
|
|
85
|
+
get MessageRetrieval(): MessageRetrievalCapabilities;
|
|
81
86
|
private HTMLConverter;
|
|
82
87
|
/**
|
|
83
88
|
* Cache clients keyed by tenant + clientId. Bounded LRU(100) + 1-hour TTL —
|
|
@@ -90,6 +95,18 @@ export declare class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
90
95
|
* Resolves MS Graph credentials from request and environment.
|
|
91
96
|
*/
|
|
92
97
|
private resolveCredentials;
|
|
98
|
+
/**
|
|
99
|
+
* The mailbox an operation will act on, or a refusal that says how to supply one.
|
|
100
|
+
*
|
|
101
|
+
* WHY THIS THROWS. Every caller interpolates the result into a Graph path. Returning `undefined`
|
|
102
|
+
* would put the literal string "undefined" in the URL and come back as a 404 that reads like
|
|
103
|
+
* "message not found" — a wrong answer that looks like a real one. This package does not enable
|
|
104
|
+
* `strictNullChecks`, so the compiler would not have caught that either.
|
|
105
|
+
*
|
|
106
|
+
* `credentials.accountEmail` is the LAST candidate on purpose: it is a default for the deployment,
|
|
107
|
+
* and anything the caller named for this specific request outranks it.
|
|
108
|
+
*/
|
|
109
|
+
private resolveMailbox;
|
|
93
110
|
/**
|
|
94
111
|
* Gets or creates a Graph client for the given credentials.
|
|
95
112
|
* Uses cached client if credentials match environment (default case).
|
|
@@ -208,6 +225,40 @@ export declare class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
208
225
|
* @requires MS Graph Scope: Mail.ReadWrite (Application)
|
|
209
226
|
*/
|
|
210
227
|
CreateDraft(params: CreateDraftParams, credentials?: MSGraphCredentials): Promise<CreateDraftResult>;
|
|
228
|
+
/**
|
|
229
|
+
* Reads calendar events for one mailbox.
|
|
230
|
+
*
|
|
231
|
+
* @requires MS Graph Scope: Calendars.Read (Application)
|
|
232
|
+
*
|
|
233
|
+
* TWO ENDPOINTS, AND THE CHOICE IS VISIBLE TO THE CALLER. Graph exposes calendar data two ways
|
|
234
|
+
* and they do not return the same thing:
|
|
235
|
+
*
|
|
236
|
+
* - `/calendarView` REQUIRES a start and end and EXPANDS recurring series into one entry per
|
|
237
|
+
* occurrence. A weekly stand-up in a two-week window comes back as two events, each with its
|
|
238
|
+
* own start time and id.
|
|
239
|
+
* - `/events` needs no window and does NOT expand. That same stand-up is one row, the series
|
|
240
|
+
* master, whose start time is whenever the series began - possibly years ago.
|
|
241
|
+
*
|
|
242
|
+
* A caller logging what actually happened wants occurrences; one asking "what meetings exist"
|
|
243
|
+
* may want masters. Silently picking would be a trap, because the two are indistinguishable by
|
|
244
|
+
* inspection - so the window decides, and `RecurrenceExpanded` on the result REPORTS which
|
|
245
|
+
* happened rather than leaving the caller to infer it.
|
|
246
|
+
*
|
|
247
|
+
* CANCELLED EVENTS ARE EXCLUDED BY DEFAULT and cannot be recovered afterwards - Graph does not
|
|
248
|
+
* return them once filtered - so `IncludeCancelled` is honoured before the `$top` cap rather
|
|
249
|
+
* than by discarding rows after the fetch, which would silently shrink the page.
|
|
250
|
+
*/
|
|
251
|
+
GetEvents(params: GetEventsParams, credentials?: MSGraphCredentials): Promise<GetEventsResult>;
|
|
252
|
+
/**
|
|
253
|
+
* Graph event -> the normalized shape. Lossy by design; `SourceData` keeps the original.
|
|
254
|
+
*
|
|
255
|
+
* A start Graph cannot express as an instant becomes NULL rather than a guess. Graph returns
|
|
256
|
+
* naive local strings plus a separate timeZone, so a value with neither a zone suffix nor a UTC
|
|
257
|
+
* marker genuinely has no instant here, and inventing one would file a meeting at the wrong time.
|
|
258
|
+
*/
|
|
259
|
+
private toGetEventsEvent;
|
|
260
|
+
/** A Graph date slot as an instant, or null when it does not determine one. */
|
|
261
|
+
private static graphInstant;
|
|
211
262
|
/**
|
|
212
263
|
* Returns the list of operations supported by MS Graph provider.
|
|
213
264
|
* MS Graph supports all mailbox operations.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MSGraphProvider.d.ts","sourceRoot":"","sources":["../src/MSGraphProvider.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"MSGraphProvider.d.ts","sourceRoot":"","sources":["../src/MSGraphProvider.ts"],"names":[],"mappings":"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"}
|
package/dist/MSGraphProvider.js
CHANGED
|
@@ -7,7 +7,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
|
|
10
|
+
var MSGraphProvider_1;
|
|
11
|
+
import { BaseCommunicationProvider, CombineFilterClauses, resolveCredentialValue, validateRequiredCredentials } from "@memberjunction/communication-types";
|
|
11
12
|
import { Client } from '@microsoft/microsoft-graph-client';
|
|
12
13
|
import { ClientSecretCredential } from '@azure/identity';
|
|
13
14
|
import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials/index.js";
|
|
@@ -20,6 +21,16 @@ import * as Config from "./config.js";
|
|
|
20
21
|
* The maximum lifetime, in minutes, that Microsoft Graph allows for a mail-resource
|
|
21
22
|
* change-notification subscription (~3 days). Requested expirations are clamped to this.
|
|
22
23
|
*/
|
|
24
|
+
/**
|
|
25
|
+
* Format an instant the way an OData `$filter` comparison wants it: ISO-8601, UTC, UNQUOTED.
|
|
26
|
+
*
|
|
27
|
+
* Quoting it makes Graph compare a datetime against a string and reject the request, which is the
|
|
28
|
+
* mistake this exists to keep out of the call sites. `toISOString` is always UTC with a trailing Z
|
|
29
|
+
* regardless of the Date's origin, so a caller passing a local-time Date still filters correctly.
|
|
30
|
+
*/
|
|
31
|
+
function ODataInstant(when) {
|
|
32
|
+
return when.toISOString();
|
|
33
|
+
}
|
|
23
34
|
const MSGRAPH_MAX_SUBSCRIPTION_MINUTES = 4230;
|
|
24
35
|
/**
|
|
25
36
|
* Implementation of the MS Graph provider for sending and receiving messages.
|
|
@@ -46,7 +57,14 @@ const MSGRAPH_MAX_SUBSCRIPTION_MINUTES = 4230;
|
|
|
46
57
|
* });
|
|
47
58
|
* ```
|
|
48
59
|
*/
|
|
49
|
-
let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
60
|
+
let MSGraphProvider = MSGraphProvider_1 = class MSGraphProvider extends BaseCommunicationProvider {
|
|
61
|
+
/**
|
|
62
|
+
* Graph filters both of these server-side, so neither is emulated here — `receivedDateTime`
|
|
63
|
+
* comparisons and `isRead` are ordinary `$filter` clauses.
|
|
64
|
+
*/
|
|
65
|
+
get MessageRetrieval() {
|
|
66
|
+
return { FilterByReceivedDate: true, FilterByUnread: true };
|
|
67
|
+
}
|
|
50
68
|
constructor() {
|
|
51
69
|
super();
|
|
52
70
|
/**
|
|
@@ -71,7 +89,12 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
71
89
|
const clientId = resolveCredentialValue(credentials?.clientId, Config.AZURE_CLIENT_ID, disableFallback);
|
|
72
90
|
const clientSecret = resolveCredentialValue(credentials?.clientSecret, Config.AZURE_CLIENT_SECRET, disableFallback);
|
|
73
91
|
const accountEmail = resolveCredentialValue(credentials?.accountEmail, Config.AZURE_ACCOUNT_EMAIL, disableFallback);
|
|
74
|
-
|
|
92
|
+
// The THREE authentication fields, which is exactly what a service principal is and exactly
|
|
93
|
+
// what the `Azure Service Principal` credential type declares. `accountEmail` used to be
|
|
94
|
+
// required here, which made every stored credential of that type unusable: there was no
|
|
95
|
+
// fourth field for an operator to fill in, so every operation failed before doing anything.
|
|
96
|
+
// A mailbox is resolved per operation instead — see `resolveMailbox`.
|
|
97
|
+
validateRequiredCredentials({ tenantId, clientId, clientSecret }, ['tenantId', 'clientId', 'clientSecret'], 'Microsoft Graph');
|
|
75
98
|
return {
|
|
76
99
|
tenantId: tenantId,
|
|
77
100
|
clientId: clientId,
|
|
@@ -79,6 +102,25 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
79
102
|
accountEmail: accountEmail
|
|
80
103
|
};
|
|
81
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* The mailbox an operation will act on, or a refusal that says how to supply one.
|
|
107
|
+
*
|
|
108
|
+
* WHY THIS THROWS. Every caller interpolates the result into a Graph path. Returning `undefined`
|
|
109
|
+
* would put the literal string "undefined" in the URL and come back as a 404 that reads like
|
|
110
|
+
* "message not found" — a wrong answer that looks like a real one. This package does not enable
|
|
111
|
+
* `strictNullChecks`, so the compiler would not have caught that either.
|
|
112
|
+
*
|
|
113
|
+
* `credentials.accountEmail` is the LAST candidate on purpose: it is a default for the deployment,
|
|
114
|
+
* and anything the caller named for this specific request outranks it.
|
|
115
|
+
*/
|
|
116
|
+
resolveMailbox(operation, creds, ...preferred) {
|
|
117
|
+
for (const candidate of [...preferred, creds.accountEmail]) {
|
|
118
|
+
if (candidate && candidate.trim() !== '')
|
|
119
|
+
return candidate.trim();
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Microsoft Graph: ${operation} needs a mailbox and none was supplied. Pass one on the ` +
|
|
122
|
+
`request, or set accountEmail on the credential (or AZURE_ACCOUNT_EMAIL) as a default.`);
|
|
123
|
+
}
|
|
82
124
|
/**
|
|
83
125
|
* Gets or creates a Graph client for the given credentials.
|
|
84
126
|
* Uses cached client if credentials match environment (default case).
|
|
@@ -129,12 +171,9 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
129
171
|
const creds = this.resolveCredentials(credentials);
|
|
130
172
|
const client = this.getGraphClient(creds);
|
|
131
173
|
// Smart selection: use message.From if provided and different from resolved accountEmail
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
message.From !== creds.accountEmail) {
|
|
136
|
-
senderEmail = message.From;
|
|
137
|
-
}
|
|
174
|
+
// Whatever the caller named outranks the credential default; a request that names
|
|
175
|
+
// neither is refused here rather than sending from "undefined".
|
|
176
|
+
const senderEmail = this.resolveMailbox('SendSingleMessage', creds, message.From);
|
|
138
177
|
if (!message) {
|
|
139
178
|
return {
|
|
140
179
|
Message: message,
|
|
@@ -237,8 +276,13 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
237
276
|
},
|
|
238
277
|
comment: params.Message.ProcessedBody || params.Message.ProcessedHTMLBody
|
|
239
278
|
};
|
|
240
|
-
//
|
|
241
|
-
|
|
279
|
+
// `ContextData.Email` FIRST, as eleven sibling operations already read it. Without it this
|
|
280
|
+
// site could only resolve `creds.accountEmail` — which the `Azure Service Principal`
|
|
281
|
+
// credential type declares no property for, and which `disableEnvironmentFallback` removes
|
|
282
|
+
// the environment source for. Reply was therefore unreachable on exactly the stored
|
|
283
|
+
// credential the mailbox rework exists to support.
|
|
284
|
+
const mailbox = this.resolveMailbox('ReplyToMessage', creds, params.ContextData?.Email);
|
|
285
|
+
const sendMessagePath = `${this.getApiUri()}/${encodeURIComponent(mailbox)}/messages/${params.MessageID}/reply`;
|
|
242
286
|
const result = await client.api(sendMessagePath).post(reply);
|
|
243
287
|
return {
|
|
244
288
|
Success: true,
|
|
@@ -249,7 +293,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
249
293
|
LogError(ex);
|
|
250
294
|
return {
|
|
251
295
|
Success: false,
|
|
252
|
-
ErrorMessage:
|
|
296
|
+
ErrorMessage: `Error sending message: ${ex instanceof Error ? ex.message : String(ex)}`
|
|
253
297
|
};
|
|
254
298
|
}
|
|
255
299
|
}
|
|
@@ -262,15 +306,29 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
262
306
|
const creds = this.resolveCredentials(credentials);
|
|
263
307
|
const client = this.getGraphClient(creds);
|
|
264
308
|
const contextData = params.ContextData;
|
|
265
|
-
const emailToUse = params.Identifier
|
|
266
|
-
let filter = "";
|
|
309
|
+
const emailToUse = this.resolveMailbox('GetMessages', creds, params.Identifier, contextData?.Email);
|
|
267
310
|
const top = params.NumMessages;
|
|
311
|
+
const applied = { ReceivedAfter: false, ReceivedBefore: false, UnreadOnly: false };
|
|
312
|
+
const clauses = [];
|
|
268
313
|
if (params.UnreadOnly) {
|
|
269
|
-
|
|
314
|
+
clauses.push("(isRead eq false)");
|
|
315
|
+
applied.UnreadOnly = true;
|
|
270
316
|
}
|
|
317
|
+
if (params.ReceivedAfter) {
|
|
318
|
+
clauses.push(`(receivedDateTime ge ${ODataInstant(params.ReceivedAfter)})`);
|
|
319
|
+
applied.ReceivedAfter = true;
|
|
320
|
+
}
|
|
321
|
+
if (params.ReceivedBefore) {
|
|
322
|
+
clauses.push(`(receivedDateTime le ${ODataInstant(params.ReceivedBefore)})`);
|
|
323
|
+
applied.ReceivedBefore = true;
|
|
324
|
+
}
|
|
325
|
+
// COMPOSED, not assigned. This branch used to overwrite `filter` outright, so a caller that
|
|
326
|
+
// passed UnreadOnly together with a ContextData.Filter silently lost the UnreadOnly clause
|
|
327
|
+
// and got read mail back. Anything the caller supplies here now narrows alongside the rest.
|
|
271
328
|
if (contextData && contextData.Filter) {
|
|
272
|
-
|
|
329
|
+
clauses.push(String(contextData.Filter));
|
|
273
330
|
}
|
|
331
|
+
const filter = CombineFilterClauses(clauses, " and ");
|
|
274
332
|
// Use email address directly in API path
|
|
275
333
|
const messagesPath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages`;
|
|
276
334
|
const response = await client.api(messagesPath)
|
|
@@ -285,7 +343,8 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
285
343
|
const messageResults = {
|
|
286
344
|
Success: true,
|
|
287
345
|
SourceData: sourceMessages,
|
|
288
|
-
Messages: []
|
|
346
|
+
Messages: [],
|
|
347
|
+
AppliedFilters: applied
|
|
289
348
|
};
|
|
290
349
|
let headers = null;
|
|
291
350
|
// GetHeaders is an async function for one specific message. I need
|
|
@@ -360,7 +419,8 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
360
419
|
}))
|
|
361
420
|
};
|
|
362
421
|
// Use email address directly in API path
|
|
363
|
-
const
|
|
422
|
+
const mailbox = this.resolveMailbox('ForwardMessage', creds);
|
|
423
|
+
const sendMessagePath = `${this.getApiUri()}/${encodeURIComponent(mailbox)}/messages/${params.MessageID}/forward`;
|
|
364
424
|
const forwardResult = await client.api(sendMessagePath).post(forward);
|
|
365
425
|
return {
|
|
366
426
|
Success: true,
|
|
@@ -370,7 +430,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
370
430
|
catch (ex) {
|
|
371
431
|
LogError(ex);
|
|
372
432
|
return {
|
|
373
|
-
ErrorMessage:
|
|
433
|
+
ErrorMessage: `An Error occurred while forwarding the message: ${ex instanceof Error ? ex.message : String(ex)}`,
|
|
374
434
|
Success: false
|
|
375
435
|
};
|
|
376
436
|
}
|
|
@@ -523,12 +583,9 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
523
583
|
const creds = this.resolveCredentials(credentials);
|
|
524
584
|
const client = this.getGraphClient(creds);
|
|
525
585
|
// Smart selection: use message.From if provided and different from resolved accountEmail
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
params.Message.From !== creds.accountEmail) {
|
|
530
|
-
senderEmail = params.Message.From;
|
|
531
|
-
}
|
|
586
|
+
// Whatever the caller named outranks the credential default; a request that names
|
|
587
|
+
// neither is refused here rather than sending from "undefined".
|
|
588
|
+
const senderEmail = this.resolveMailbox('CreateDraft', creds, params.Message.From);
|
|
532
589
|
// Build message object (similar to SendSingleMessage but saved as draft)
|
|
533
590
|
const draftMessage = {
|
|
534
591
|
subject: params.Message.ProcessedSubject,
|
|
@@ -568,13 +625,143 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
568
625
|
LogError('Error creating draft via MS Graph', undefined, ex);
|
|
569
626
|
return {
|
|
570
627
|
Success: false,
|
|
571
|
-
ErrorMessage:
|
|
628
|
+
ErrorMessage: `Error creating draft: ${ex instanceof Error ? ex.message : String(ex)}`
|
|
572
629
|
};
|
|
573
630
|
}
|
|
574
631
|
}
|
|
575
632
|
// ========================================================================
|
|
576
633
|
// EXTENDED OPERATIONS - MS Graph supports full mailbox access
|
|
577
634
|
// ========================================================================
|
|
635
|
+
/**
|
|
636
|
+
* Reads calendar events for one mailbox.
|
|
637
|
+
*
|
|
638
|
+
* @requires MS Graph Scope: Calendars.Read (Application)
|
|
639
|
+
*
|
|
640
|
+
* TWO ENDPOINTS, AND THE CHOICE IS VISIBLE TO THE CALLER. Graph exposes calendar data two ways
|
|
641
|
+
* and they do not return the same thing:
|
|
642
|
+
*
|
|
643
|
+
* - `/calendarView` REQUIRES a start and end and EXPANDS recurring series into one entry per
|
|
644
|
+
* occurrence. A weekly stand-up in a two-week window comes back as two events, each with its
|
|
645
|
+
* own start time and id.
|
|
646
|
+
* - `/events` needs no window and does NOT expand. That same stand-up is one row, the series
|
|
647
|
+
* master, whose start time is whenever the series began - possibly years ago.
|
|
648
|
+
*
|
|
649
|
+
* A caller logging what actually happened wants occurrences; one asking "what meetings exist"
|
|
650
|
+
* may want masters. Silently picking would be a trap, because the two are indistinguishable by
|
|
651
|
+
* inspection - so the window decides, and `RecurrenceExpanded` on the result REPORTS which
|
|
652
|
+
* happened rather than leaving the caller to infer it.
|
|
653
|
+
*
|
|
654
|
+
* CANCELLED EVENTS ARE EXCLUDED BY DEFAULT and cannot be recovered afterwards - Graph does not
|
|
655
|
+
* return them once filtered - so `IncludeCancelled` is honoured before the `$top` cap rather
|
|
656
|
+
* than by discarding rows after the fetch, which would silently shrink the page.
|
|
657
|
+
*/
|
|
658
|
+
async GetEvents(params, credentials) {
|
|
659
|
+
const creds = this.resolveCredentials(credentials);
|
|
660
|
+
const client = this.getGraphClient(creds);
|
|
661
|
+
const contextData = params.ContextData;
|
|
662
|
+
const mailbox = params.Identifier || contextData?.Email || creds.accountEmail;
|
|
663
|
+
if (!mailbox) {
|
|
664
|
+
return {
|
|
665
|
+
Success: false,
|
|
666
|
+
Events: [],
|
|
667
|
+
ErrorMessage: 'GetEvents needs an Identifier (mailbox) or credentials scoped to one.'
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
const expand = !!params.StartDateTime && !!params.EndDateTime;
|
|
671
|
+
const base = `${this.getApiUri()}/${encodeURIComponent(mailbox)}`;
|
|
672
|
+
try {
|
|
673
|
+
let request = expand
|
|
674
|
+
? client
|
|
675
|
+
.api(`${base}/calendarView`)
|
|
676
|
+
.query({
|
|
677
|
+
startDateTime: params.StartDateTime.toISOString(),
|
|
678
|
+
endDateTime: params.EndDateTime.toISOString()
|
|
679
|
+
})
|
|
680
|
+
.orderby('start/dateTime')
|
|
681
|
+
: client.api(`${base}/events`).orderby('lastModifiedDateTime desc');
|
|
682
|
+
// Ask for UTC explicitly rather than relying on it. Graph returns start/end in UTC when no
|
|
683
|
+
// `Prefer: outlook.timezone` is sent, so this changes nothing today — but the default is
|
|
684
|
+
// Microsoft's to change, and every other value would need a tz database to resolve. Saying
|
|
685
|
+
// it makes the mapper's UTC assumption a request rather than a bet. `graphInstant` keeps
|
|
686
|
+
// its null fallback for the case where a non-UTC zone comes back anyway.
|
|
687
|
+
request = request.header('Prefer', 'outlook.timezone="UTC"');
|
|
688
|
+
// Applied server-side so the $top cap counts only events the caller asked for. Filtering
|
|
689
|
+
// after the fetch would return fewer than NumEvents and look like an empty calendar.
|
|
690
|
+
//
|
|
691
|
+
// $filter AND $orderby TOGETHER ARE ACCEPTED HERE. Outlook's backend requires every
|
|
692
|
+
// $orderby property to also appear in $filter for MESSAGES, returning 400
|
|
693
|
+
// `InefficientFilter` otherwise, and Microsoft's announcement of that rule is titled for
|
|
694
|
+
// Mail, Calendar and Contacts — so this combination looks like it should fail. It does
|
|
695
|
+
// not: both shapes below were sent against a live tenant and returned 200. Recorded here
|
|
696
|
+
// because the unit tests mock the Graph client and can never catch a 400, so the next
|
|
697
|
+
// reader has no way to re-derive it short of running the query again.
|
|
698
|
+
if (!params.IncludeCancelled) {
|
|
699
|
+
request = request.filter('isCancelled eq false');
|
|
700
|
+
}
|
|
701
|
+
const response = await request.top(params.NumEvents).get();
|
|
702
|
+
if (!response) {
|
|
703
|
+
return { Success: false, Events: [], ErrorMessage: 'Graph returned no response for the calendar read.' };
|
|
704
|
+
}
|
|
705
|
+
const sourceEvents = response.value ?? [];
|
|
706
|
+
return {
|
|
707
|
+
Success: true,
|
|
708
|
+
SourceData: sourceEvents,
|
|
709
|
+
RecurrenceExpanded: expand,
|
|
710
|
+
Events: sourceEvents.map((e) => this.toGetEventsEvent(e))
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
catch (err) {
|
|
714
|
+
// Surfaced, not swallowed into an empty list: a caller advancing a watermark must be able
|
|
715
|
+
// to tell "could not read" from "nothing scheduled".
|
|
716
|
+
return {
|
|
717
|
+
Success: false,
|
|
718
|
+
Events: [],
|
|
719
|
+
ErrorMessage: `Graph calendar read failed for ${mailbox}: ${err instanceof Error ? err.message : String(err)}`
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Graph event -> the normalized shape. Lossy by design; `SourceData` keeps the original.
|
|
725
|
+
*
|
|
726
|
+
* A start Graph cannot express as an instant becomes NULL rather than a guess. Graph returns
|
|
727
|
+
* naive local strings plus a separate timeZone, so a value with neither a zone suffix nor a UTC
|
|
728
|
+
* marker genuinely has no instant here, and inventing one would file a meeting at the wrong time.
|
|
729
|
+
*/
|
|
730
|
+
toGetEventsEvent(raw) {
|
|
731
|
+
const event = raw;
|
|
732
|
+
const organizer = event.organizer?.emailAddress?.address?.trim().toLowerCase() || undefined;
|
|
733
|
+
const attendees = (event.attendees ?? [])
|
|
734
|
+
.map((a) => a.emailAddress?.address?.trim().toLowerCase())
|
|
735
|
+
.filter((a) => !!a && a !== organizer);
|
|
736
|
+
return {
|
|
737
|
+
ExternalSystemRecordID: event.id ?? '',
|
|
738
|
+
SeriesID: event.seriesMasterId ?? null,
|
|
739
|
+
Subject: event.subject ?? '',
|
|
740
|
+
Body: event.bodyPreview ?? '',
|
|
741
|
+
StartTime: MSGraphProvider_1.graphInstant(event.start),
|
|
742
|
+
EndTime: MSGraphProvider_1.graphInstant(event.end),
|
|
743
|
+
Location: event.location?.displayName ?? null,
|
|
744
|
+
Organizer: organizer,
|
|
745
|
+
Attendees: [...new Set(attendees)],
|
|
746
|
+
IsCancelled: event.isCancelled === true
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
/** A Graph date slot as an instant, or null when it does not determine one. */
|
|
750
|
+
static graphInstant(slot) {
|
|
751
|
+
const raw = slot?.dateTime?.trim();
|
|
752
|
+
if (!raw)
|
|
753
|
+
return null;
|
|
754
|
+
// Both alternatives anchored. Unanchored, the `[Zz]` matched a "z" ANYWHERE in the string, so
|
|
755
|
+
// a value that merely contained one counted as carrying an offset and skipped the UTC check.
|
|
756
|
+
const hasOffset = /(?:[Zz]|[+-]\d{2}:?\d{2})$/.test(raw);
|
|
757
|
+
const zone = (slot?.timeZone ?? 'UTC').trim().toUpperCase();
|
|
758
|
+
// Only UTC is safe to assume. Any other named zone would need a tz database to resolve, and
|
|
759
|
+
// guessing puts the meeting hours away from when it happened.
|
|
760
|
+
if (!hasOffset && zone !== 'UTC')
|
|
761
|
+
return null;
|
|
762
|
+
const parsed = new Date(hasOffset ? raw : `${raw}Z`);
|
|
763
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
764
|
+
}
|
|
578
765
|
/**
|
|
579
766
|
* Returns the list of operations supported by MS Graph provider.
|
|
580
767
|
* MS Graph supports all mailbox operations.
|
|
@@ -598,7 +785,8 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
598
785
|
'CreateSubscription',
|
|
599
786
|
'RenewSubscription',
|
|
600
787
|
'DeleteSubscription',
|
|
601
|
-
'ParseNotification'
|
|
788
|
+
'ParseNotification',
|
|
789
|
+
'GetEvents'
|
|
602
790
|
];
|
|
603
791
|
}
|
|
604
792
|
// ========================================================================
|
|
@@ -668,7 +856,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
668
856
|
try {
|
|
669
857
|
const creds = this.resolveCredentials(credentials);
|
|
670
858
|
const client = this.getGraphClient(creds);
|
|
671
|
-
const mailboxId =
|
|
859
|
+
const mailboxId = this.resolveMailbox('CreateSubscription', creds, params.Identifier);
|
|
672
860
|
const context = params.ContextData;
|
|
673
861
|
const folderSegment = await this.resolveSubscriptionFolderSegment(client, mailboxId, context);
|
|
674
862
|
if (!folderSegment) {
|
|
@@ -871,7 +1059,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
871
1059
|
try {
|
|
872
1060
|
const creds = this.resolveCredentials(credentials);
|
|
873
1061
|
const client = this.getGraphClient(creds);
|
|
874
|
-
const emailToUse = params.ContextData?.Email
|
|
1062
|
+
const emailToUse = this.resolveMailbox('GetSingleMessage', creds, params.ContextData?.Email);
|
|
875
1063
|
// Use email address directly in API path
|
|
876
1064
|
const messagePath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages/${params.MessageID}`;
|
|
877
1065
|
const msgResponse = await client.api(messagePath).get();
|
|
@@ -921,7 +1109,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
921
1109
|
try {
|
|
922
1110
|
const creds = this.resolveCredentials(credentials);
|
|
923
1111
|
const client = this.getGraphClient(creds);
|
|
924
|
-
const emailToUse = params.ContextData?.Email
|
|
1112
|
+
const emailToUse = this.resolveMailbox('DeleteMessage', creds, params.ContextData?.Email);
|
|
925
1113
|
// Use email address directly in API path
|
|
926
1114
|
const messagePath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages/${params.MessageID}`;
|
|
927
1115
|
if (params.PermanentDelete) {
|
|
@@ -961,7 +1149,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
961
1149
|
try {
|
|
962
1150
|
const creds = this.resolveCredentials(credentials);
|
|
963
1151
|
const client = this.getGraphClient(creds);
|
|
964
|
-
const emailToUse = params.ContextData?.Email
|
|
1152
|
+
const emailToUse = this.resolveMailbox('MoveMessage', creds, params.ContextData?.Email);
|
|
965
1153
|
// Use email address directly in API path
|
|
966
1154
|
const movePath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages/${params.MessageID}/move`;
|
|
967
1155
|
const result = await client.api(movePath).post({
|
|
@@ -991,7 +1179,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
991
1179
|
try {
|
|
992
1180
|
const creds = this.resolveCredentials(credentials);
|
|
993
1181
|
const client = this.getGraphClient(creds);
|
|
994
|
-
const emailToUse = params.ContextData?.Email
|
|
1182
|
+
const emailToUse = this.resolveMailbox('ListFolders', creds, params.ContextData?.Email);
|
|
995
1183
|
// Use email address directly in API path
|
|
996
1184
|
let foldersPath;
|
|
997
1185
|
if (params.ParentFolderID) {
|
|
@@ -1039,7 +1227,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
1039
1227
|
try {
|
|
1040
1228
|
const creds = this.resolveCredentials(credentials);
|
|
1041
1229
|
const client = this.getGraphClient(creds);
|
|
1042
|
-
const emailToUse = params.ContextData?.Email
|
|
1230
|
+
const emailToUse = this.resolveMailbox('MarkAsRead', creds, params.ContextData?.Email);
|
|
1043
1231
|
// Use email address directly in API path - update each message
|
|
1044
1232
|
const updatePromises = params.MessageIDs.map(async (messageId) => {
|
|
1045
1233
|
const updatePath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages/${messageId}`;
|
|
@@ -1066,7 +1254,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
1066
1254
|
try {
|
|
1067
1255
|
const creds = this.resolveCredentials(credentials);
|
|
1068
1256
|
const client = this.getGraphClient(creds);
|
|
1069
|
-
const emailToUse = params.ContextData?.Email
|
|
1257
|
+
const emailToUse = this.resolveMailbox('ArchiveMessage', creds, params.ContextData?.Email);
|
|
1070
1258
|
// Find or create the Archive folder - use email address directly
|
|
1071
1259
|
let archiveFolderId = await this.findSystemFolder(client, emailToUse, 'archive');
|
|
1072
1260
|
if (!archiveFolderId) {
|
|
@@ -1104,7 +1292,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
1104
1292
|
try {
|
|
1105
1293
|
const creds = this.resolveCredentials(credentials);
|
|
1106
1294
|
const client = this.getGraphClient(creds);
|
|
1107
|
-
const emailToUse = params.ContextData?.Email
|
|
1295
|
+
const emailToUse = this.resolveMailbox('SearchMessages', creds, params.ContextData?.Email);
|
|
1108
1296
|
// Build search path - use email address directly in API path
|
|
1109
1297
|
let messagesPath;
|
|
1110
1298
|
if (params.FolderID) {
|
|
@@ -1176,7 +1364,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
1176
1364
|
try {
|
|
1177
1365
|
const creds = this.resolveCredentials(credentials);
|
|
1178
1366
|
const client = this.getGraphClient(creds);
|
|
1179
|
-
const emailToUse = params.ContextData?.Email
|
|
1367
|
+
const emailToUse = this.resolveMailbox('ListAttachments', creds, params.ContextData?.Email);
|
|
1180
1368
|
// Use email address directly in API path
|
|
1181
1369
|
const attachmentsPath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages/${params.MessageID}/attachments`;
|
|
1182
1370
|
const response = await client.api(attachmentsPath).get();
|
|
@@ -1217,7 +1405,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
1217
1405
|
try {
|
|
1218
1406
|
const creds = this.resolveCredentials(credentials);
|
|
1219
1407
|
const client = this.getGraphClient(creds);
|
|
1220
|
-
const emailToUse = params.ContextData?.Email
|
|
1408
|
+
const emailToUse = this.resolveMailbox('DownloadAttachment', creds, params.ContextData?.Email);
|
|
1221
1409
|
// Use email address directly in API path
|
|
1222
1410
|
const attachmentPath = `${this.getApiUri()}/${encodeURIComponent(emailToUse)}/messages/${params.MessageID}/attachments/${params.AttachmentID}`;
|
|
1223
1411
|
const response = await client.api(attachmentPath).get();
|
|
@@ -1403,7 +1591,7 @@ let MSGraphProvider = class MSGraphProvider extends BaseCommunicationProvider {
|
|
|
1403
1591
|
return effective.toISOString();
|
|
1404
1592
|
}
|
|
1405
1593
|
};
|
|
1406
|
-
MSGraphProvider = __decorate([
|
|
1594
|
+
MSGraphProvider = MSGraphProvider_1 = __decorate([
|
|
1407
1595
|
RegisterClass(BaseCommunicationProvider, 'Microsoft Graph'),
|
|
1408
1596
|
__metadata("design:paramtypes", [])
|
|
1409
1597
|
], MSGraphProvider);
|