microsoft-graph-client 1.0.33 → 1.0.34

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.
@@ -1,21 +1,152 @@
1
1
  import { BaseApi } from './base.js';
2
- import type { AddChatMemberParams, Chat, CreateChatParams, GetChatParams, ListChatsParams, ListChatsResult, RemoveChatMemberParams, UpdateChatParams } from '../types/index.js';
2
+ import type { AddChatMemberParams, Chat, CreateChatParams, FindDmParams, GetChatParams, ListChatsParams, ListChatsResult, RemoveChatMemberParams, UpdateChatParams } from '../types/index.js';
3
3
  /**
4
4
  * API for chat operations.
5
+ *
6
+ * Microsoft Graph's `/me/chats` is unusually limited compared to other Graph
7
+ * resources. Several quirks documented below shape every method here:
8
+ *
9
+ * - **`$top` is hard-capped at 50.** Values above 50 return HTTP 400.
10
+ * Source: https://learn.microsoft.com/en-us/graph/api/chat-list (Optional
11
+ * query parameters table).
12
+ *
13
+ * - **All `$filter` predicates are post-filtered, not indexed lookups.**
14
+ * Graph applies `$filter` AFTER taking the next `$top` chats from the
15
+ * recency-ordered chat list. So a single page returns "matches found
16
+ * within the next 50 chats by recency", and `@odata.nextLink` advances
17
+ * the scan window. Even `chatType eq 'oneOnOne'` behaves this way:
18
+ * measured `$top=5 → 2 matches`, `$top=50 → 13 matches`. This means you
19
+ * cannot rely on `$filter` to find old chats without paginating.
20
+ * Confirmed by Microsoft on
21
+ * https://learn.microsoft.com/en-us/answers/questions/1660492 :
22
+ * "the API selects top records first and then applies the given filter".
23
+ *
24
+ * - **`$orderby` only accepts ONE value:**
25
+ * `lastMessagePreview/createdDateTime desc`. Ascending order is rejected,
26
+ * every other field (`lastUpdatedDateTime`, `createdDateTime`, `topic`,
27
+ * `chatType`, `id`) is rejected. WITHOUT explicit `$orderby` the default
28
+ * order is approximately recency-based but has many monotonicity
29
+ * violations (verified empirically). Always pass `$orderby` if you care
30
+ * about ordering.
31
+ *
32
+ * - **`members/any(o: contains(tolower(o/displayname), 'X')) + chatType eq
33
+ * 'oneOnOne'` returns 0 results.** This is a Graph bug specific to the
34
+ * displayName predicate. Combining `memberUserId` (the `userId eq …` form)
35
+ * with `chatType eq 'oneOnOne'` works correctly. Use `memberUserId` if
36
+ * you have an AAD ID; resolve names to IDs first.
37
+ *
38
+ * - **`$expand=members` silently truncates at 25 members per chat,**
39
+ * regardless of `$top`. The server still evaluates `members/any()` against
40
+ * the full membership list, but the returned `members` array is capped.
41
+ * Documented as a "known issue" on the official chat-list page.
42
+ *
43
+ * - **`$search` is not allowed** on `/me/chats`.
44
+ * - **`$count=true` is not allowed** on `/me/chats`.
45
+ *
46
+ * For deep background and all the empirical measurements, see
47
+ * `packages/clis/msgraph-cli/CHAT_SEARCH_INVESTIGATION.md` in this repo.
5
48
  */
6
49
  export declare class ChatsApi extends BaseApi {
7
50
  /**
8
51
  * Get a chat by ID with members expanded.
52
+ *
53
+ * Note: due to the documented `$expand=members` 25-cap, the `members` array
54
+ * may be incomplete for chats with more than 25 members. The server
55
+ * correctly counts all members for filter evaluation, but the response is
56
+ * truncated.
9
57
  */
10
58
  get(params: GetChatParams): Promise<Chat>;
59
+ /**
60
+ * Find the 1:1 chat between the signed-in user and another user.
61
+ *
62
+ * Why this exists as a primitive: Microsoft Graph has no `/me/chats/with/
63
+ * {userId}` endpoint, and the obvious workaround
64
+ * (`/me/chats?$filter=members/any(...) and chatType eq 'oneOnOne'`) is
65
+ * subject to the recency-window post-filter described in the class doc —
66
+ * older 1:1 chats are unreachable without paginating the entire chat list.
67
+ *
68
+ * Workaround: 1:1 chat IDs follow the deterministic format
69
+ *
70
+ * 19:{userA-guid}_{userB-guid}@unq.gbl.spaces
71
+ *
72
+ * but the order of the two GUIDs is **not** deterministic. Verified
73
+ * empirically against ~12 1:1 chats in an active account: about 75% have
74
+ * the signed-in user's GUID first, the rest have the other user's GUID
75
+ * first. The order likely depends on who initiated the conversation, but
76
+ * we can't tell without trying.
77
+ *
78
+ * So we issue both candidate URLs in parallel. Exactly one returns 200,
79
+ * the other returns 404. Round-trip latency is ~250-700ms total because
80
+ * the calls go in parallel.
81
+ *
82
+ * **This sidesteps `/me/chats` entirely.** It works for any 1:1 chat
83
+ * regardless of how long ago the last message was sent — there is no
84
+ * recency window. It is also strictly read-only with no side effects on
85
+ * Teams (unlike `POST /chats` which would create a new thread if the
86
+ * chat didn't already exist).
87
+ *
88
+ * Returns the existing 1:1 chat, or `null` if no DM exists between the
89
+ * signed-in user and the target user.
90
+ *
91
+ * @example
92
+ * const chat = await client.chats.findDmByUserId({ userId: 'de720d1a-...' });
93
+ * if (chat) console.log(`DM exists: ${chat.id}`);
94
+ * else console.log('No DM with this user yet');
95
+ */
96
+ findDmByUserId(params: FindDmParams): Promise<Chat | null>;
11
97
  /**
12
98
  * List chats for the current user.
13
- * Builds OData $filter from searchTerm, chatTypes, and memberName.
14
- * Returns a single page of results with nextLink for pagination.
99
+ *
100
+ * Builds an OData query from the typed params. Returns a single page of
101
+ * results with `nextLink` for caller-driven pagination — this method does
102
+ * NOT loop through pages.
103
+ *
104
+ * **Important caveats** (see also the class-level doc above):
105
+ *
106
+ * - Filters are post-filtered by Graph against a recency window of
107
+ * `$top` chats. Pagination via `nextLink` advances the window forward.
108
+ * A single page returns `0..top` matches. Pagination ends only when
109
+ * the window has scanned every chat the user has — for power users
110
+ * that may be 50+ pages.
111
+ *
112
+ * - Always pass `orderByLastMessage: true` for monotonic recency order.
113
+ * The default order has gaps and violations.
114
+ *
115
+ * - For finding 1:1 chats with a specific person, prefer
116
+ * {@link findDmByUserId} which sidesteps this whole mess.
117
+ *
118
+ * - For combining a member predicate with `chatType eq 'oneOnOne'`, use
119
+ * the `memberUserId` param (not `memberName` / `memberEmail`) — the
120
+ * displayName form hits a known Graph bug.
121
+ *
122
+ * @example
123
+ * // Active named chats with "morning" in the topic, recency-sorted:
124
+ * const result = await client.chats.list({
125
+ * searchTerm: 'morning',
126
+ * orderByLastMessage: true,
127
+ * top: 50,
128
+ * });
129
+ *
130
+ * @example
131
+ * // Group/meeting chats containing a specific user, recency-sorted:
132
+ * const result = await client.chats.list({
133
+ * memberUserId: '0379926e-96c3-4c2a-800e-45d1b2a9b06c',
134
+ * chatTypes: ['group', 'meeting'],
135
+ * orderByLastMessage: true,
136
+ * top: 50,
137
+ * });
15
138
  */
16
139
  list(params?: ListChatsParams): Promise<ListChatsResult>;
17
140
  /**
18
141
  * Create a new chat (1:1 or group).
142
+ *
143
+ * For 1:1 chats, Microsoft documents that "if a one-on-one chat already
144
+ * exists between the specified members, the existing chat is returned
145
+ * instead of creating a new one." However we still treat this as a
146
+ * write operation because (a) it has visible side effects on the Teams
147
+ * UI when the chat doesn't exist, and (b) the dedup behavior isn't
148
+ * something we want to rely on for read paths. For "find an existing
149
+ * 1:1", use {@link findDmByUserId} instead.
19
150
  */
20
151
  create(params: CreateChatParams): Promise<Chat>;
21
152
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/api/chats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EACV,mBAAmB,EACnB,IAAI,EACJ,gBAAgB,EAChB,aAAa,EAEb,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;OAEG;IACU,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD;;;;OAIG;IACU,IAAI,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAuDrE;;OAEG;IACU,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5D;;OAEG;IACU,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjE;;OAEG;IACU,SAAS,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlE;;OAEG;IACU,YAAY,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;CAGzE"}
1
+ {"version":3,"file":"chats.d.ts","sourceRoot":"","sources":["../../src/api/chats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EACV,mBAAmB,EACnB,IAAI,EACJ,gBAAgB,EAChB,YAAY,EACZ,aAAa,EAEb,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;;;;;OAOG;IACU,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;IACU,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAoBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACU,IAAI,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IA6ErE;;;;;;;;;;OAUG;IACU,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5D;;OAEG;IACU,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjE;;OAEG;IACU,SAAS,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlE;;OAEG;IACU,YAAY,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;CAGzE"}
package/dist/api/chats.js CHANGED
@@ -1,53 +1,211 @@
1
1
  import { BaseApi } from './base.js';
2
- import { escapeODataString } from '../utils/odata.js';
2
+ import { odataFilterValue } from '../utils/odata.js';
3
3
  /**
4
4
  * API for chat operations.
5
+ *
6
+ * Microsoft Graph's `/me/chats` is unusually limited compared to other Graph
7
+ * resources. Several quirks documented below shape every method here:
8
+ *
9
+ * - **`$top` is hard-capped at 50.** Values above 50 return HTTP 400.
10
+ * Source: https://learn.microsoft.com/en-us/graph/api/chat-list (Optional
11
+ * query parameters table).
12
+ *
13
+ * - **All `$filter` predicates are post-filtered, not indexed lookups.**
14
+ * Graph applies `$filter` AFTER taking the next `$top` chats from the
15
+ * recency-ordered chat list. So a single page returns "matches found
16
+ * within the next 50 chats by recency", and `@odata.nextLink` advances
17
+ * the scan window. Even `chatType eq 'oneOnOne'` behaves this way:
18
+ * measured `$top=5 → 2 matches`, `$top=50 → 13 matches`. This means you
19
+ * cannot rely on `$filter` to find old chats without paginating.
20
+ * Confirmed by Microsoft on
21
+ * https://learn.microsoft.com/en-us/answers/questions/1660492 :
22
+ * "the API selects top records first and then applies the given filter".
23
+ *
24
+ * - **`$orderby` only accepts ONE value:**
25
+ * `lastMessagePreview/createdDateTime desc`. Ascending order is rejected,
26
+ * every other field (`lastUpdatedDateTime`, `createdDateTime`, `topic`,
27
+ * `chatType`, `id`) is rejected. WITHOUT explicit `$orderby` the default
28
+ * order is approximately recency-based but has many monotonicity
29
+ * violations (verified empirically). Always pass `$orderby` if you care
30
+ * about ordering.
31
+ *
32
+ * - **`members/any(o: contains(tolower(o/displayname), 'X')) + chatType eq
33
+ * 'oneOnOne'` returns 0 results.** This is a Graph bug specific to the
34
+ * displayName predicate. Combining `memberUserId` (the `userId eq …` form)
35
+ * with `chatType eq 'oneOnOne'` works correctly. Use `memberUserId` if
36
+ * you have an AAD ID; resolve names to IDs first.
37
+ *
38
+ * - **`$expand=members` silently truncates at 25 members per chat,**
39
+ * regardless of `$top`. The server still evaluates `members/any()` against
40
+ * the full membership list, but the returned `members` array is capped.
41
+ * Documented as a "known issue" on the official chat-list page.
42
+ *
43
+ * - **`$search` is not allowed** on `/me/chats`.
44
+ * - **`$count=true` is not allowed** on `/me/chats`.
45
+ *
46
+ * For deep background and all the empirical measurements, see
47
+ * `packages/clis/msgraph-cli/CHAT_SEARCH_INVESTIGATION.md` in this repo.
5
48
  */
6
49
  export class ChatsApi extends BaseApi {
7
50
  /**
8
51
  * Get a chat by ID with members expanded.
52
+ *
53
+ * Note: due to the documented `$expand=members` 25-cap, the `members` array
54
+ * may be incomplete for chats with more than 25 members. The server
55
+ * correctly counts all members for filter evaluation, but the response is
56
+ * truncated.
9
57
  */
10
58
  async get(params) {
11
59
  return this.client.api(`/chats/${params.chatId}`).expand('members').get();
12
60
  }
61
+ /**
62
+ * Find the 1:1 chat between the signed-in user and another user.
63
+ *
64
+ * Why this exists as a primitive: Microsoft Graph has no `/me/chats/with/
65
+ * {userId}` endpoint, and the obvious workaround
66
+ * (`/me/chats?$filter=members/any(...) and chatType eq 'oneOnOne'`) is
67
+ * subject to the recency-window post-filter described in the class doc —
68
+ * older 1:1 chats are unreachable without paginating the entire chat list.
69
+ *
70
+ * Workaround: 1:1 chat IDs follow the deterministic format
71
+ *
72
+ * 19:{userA-guid}_{userB-guid}@unq.gbl.spaces
73
+ *
74
+ * but the order of the two GUIDs is **not** deterministic. Verified
75
+ * empirically against ~12 1:1 chats in an active account: about 75% have
76
+ * the signed-in user's GUID first, the rest have the other user's GUID
77
+ * first. The order likely depends on who initiated the conversation, but
78
+ * we can't tell without trying.
79
+ *
80
+ * So we issue both candidate URLs in parallel. Exactly one returns 200,
81
+ * the other returns 404. Round-trip latency is ~250-700ms total because
82
+ * the calls go in parallel.
83
+ *
84
+ * **This sidesteps `/me/chats` entirely.** It works for any 1:1 chat
85
+ * regardless of how long ago the last message was sent — there is no
86
+ * recency window. It is also strictly read-only with no side effects on
87
+ * Teams (unlike `POST /chats` which would create a new thread if the
88
+ * chat didn't already exist).
89
+ *
90
+ * Returns the existing 1:1 chat, or `null` if no DM exists between the
91
+ * signed-in user and the target user.
92
+ *
93
+ * @example
94
+ * const chat = await client.chats.findDmByUserId({ userId: 'de720d1a-...' });
95
+ * if (chat) console.log(`DM exists: ${chat.id}`);
96
+ * else console.log('No DM with this user yet');
97
+ */
98
+ async findDmByUserId(params) {
99
+ // We need the signed-in user's id to construct the candidates.
100
+ const me = (await this.client.api('/me').select('id').get());
101
+ const candidates = [`19:${me.id}_${params.userId}@unq.gbl.spaces`, `19:${params.userId}_${me.id}@unq.gbl.spaces`];
102
+ // Issue both GETs in parallel. Exactly one will succeed (or zero, if no
103
+ // DM exists). We don't care which order — the first fulfilled wins.
104
+ // Expand `lastMessagePreview` so callers get recency info without an
105
+ // extra round trip.
106
+ const results = await Promise.allSettled(candidates.map((cid) => this.client.api(`/chats/${cid}`).expand('members,lastMessagePreview').get()));
107
+ const winner = results.find((r) => r.status === 'fulfilled');
108
+ return winner ? winner.value : null;
109
+ }
13
110
  /**
14
111
  * List chats for the current user.
15
- * Builds OData $filter from searchTerm, chatTypes, and memberName.
16
- * Returns a single page of results with nextLink for pagination.
112
+ *
113
+ * Builds an OData query from the typed params. Returns a single page of
114
+ * results with `nextLink` for caller-driven pagination — this method does
115
+ * NOT loop through pages.
116
+ *
117
+ * **Important caveats** (see also the class-level doc above):
118
+ *
119
+ * - Filters are post-filtered by Graph against a recency window of
120
+ * `$top` chats. Pagination via `nextLink` advances the window forward.
121
+ * A single page returns `0..top` matches. Pagination ends only when
122
+ * the window has scanned every chat the user has — for power users
123
+ * that may be 50+ pages.
124
+ *
125
+ * - Always pass `orderByLastMessage: true` for monotonic recency order.
126
+ * The default order has gaps and violations.
127
+ *
128
+ * - For finding 1:1 chats with a specific person, prefer
129
+ * {@link findDmByUserId} which sidesteps this whole mess.
130
+ *
131
+ * - For combining a member predicate with `chatType eq 'oneOnOne'`, use
132
+ * the `memberUserId` param (not `memberName` / `memberEmail`) — the
133
+ * displayName form hits a known Graph bug.
134
+ *
135
+ * @example
136
+ * // Active named chats with "morning" in the topic, recency-sorted:
137
+ * const result = await client.chats.list({
138
+ * searchTerm: 'morning',
139
+ * orderByLastMessage: true,
140
+ * top: 50,
141
+ * });
142
+ *
143
+ * @example
144
+ * // Group/meeting chats containing a specific user, recency-sorted:
145
+ * const result = await client.chats.list({
146
+ * memberUserId: '0379926e-96c3-4c2a-800e-45d1b2a9b06c',
147
+ * chatTypes: ['group', 'meeting'],
148
+ * orderByLastMessage: true,
149
+ * top: 50,
150
+ * });
17
151
  */
18
152
  async list(params) {
19
153
  let query;
20
154
  if (params?.nextLink) {
155
+ // When following a nextLink, all query params are already baked in.
156
+ // Just GET it directly.
21
157
  query = this.client.api(params.nextLink);
22
158
  }
23
159
  else {
24
160
  const top = params?.top ?? 50;
25
161
  query = this.client.api('/me/chats').top(top);
26
162
  const filters = [];
163
+ const expand = new Set(params?.expand ?? []);
27
164
  if (params?.searchTerm) {
28
- filters.push(`contains(tolower(topic), '${escapeODataString(params.searchTerm.toLowerCase())}')`);
165
+ // We must URL-encode the value here because the SDK's `.filter()` builder
166
+ // URL-encodes the parameter NAME but not the VALUE. Reserved characters
167
+ // in topics like "FM & FD" would otherwise be parsed as query param
168
+ // separators on the server. odataFilterValue() does both layers:
169
+ // OData literal escape (' → '') AND URL encode. The OData syntax around
170
+ // the value (`contains(...)`, the surrounding quotes) is NOT encoded —
171
+ // it's part of the filter expression that the SDK passes through.
172
+ // Verified empirically with `test/probe-encoding.mts`.
173
+ const value = odataFilterValue(params.searchTerm.toLowerCase());
174
+ filters.push(`contains(tolower(topic), '${value}')`);
29
175
  }
30
176
  if (params?.chatTypes && params.chatTypes.length > 0) {
31
177
  const typeFilters = params.chatTypes.map((t) => `chatType eq '${t}'`);
32
- filters.push(`(${typeFilters.join(' or ')})`);
178
+ filters.push(typeFilters.length === 1 ? typeFilters[0] : `(${typeFilters.join(' or ')})`);
33
179
  }
34
180
  if (params?.memberName) {
35
- filters.push(`members/any(o: contains(tolower(o/displayname), '${escapeODataString(params.memberName.toLowerCase())}'))`);
36
- if (!params.expand?.includes('members')) {
37
- params.expand = [...(params.expand || []), 'members'];
38
- }
181
+ // KNOWN GRAPH BUG: this combined with `chatType eq 'oneOnOne'` returns
182
+ // 0. Caller is responsible for not passing that combination, OR for
183
+ // using `memberUserId` instead (which is bug-free).
184
+ const value = odataFilterValue(params.memberName.toLowerCase());
185
+ filters.push(`members/any(o: contains(tolower(o/displayname), '${value}'))`);
186
+ // members/any() silently returns false unless members are expanded.
187
+ // Documented in this package's CLAUDE.md.
188
+ expand.add('members');
39
189
  }
40
190
  if (params?.memberEmail) {
41
- filters.push(`members/any(o: o/microsoft.graph.aadUserConversationMember/email eq '${escapeODataString(params.memberEmail)}')`);
42
- if (!params.expand?.includes('members')) {
43
- params.expand = [...(params.expand || []), 'members'];
44
- }
191
+ const value = odataFilterValue(params.memberEmail);
192
+ filters.push(`members/any(o: o/microsoft.graph.aadUserConversationMember/email eq '${value}')`);
193
+ expand.add('members');
194
+ }
195
+ if (params?.memberUserId) {
196
+ // Equality on userId is the bug-free form. Combining this with
197
+ // `chatType eq 'oneOnOne'` works correctly server-side.
198
+ filters.push(`members/any(o: o/microsoft.graph.aadUserConversationMember/userId eq '${params.memberUserId}')`);
199
+ expand.add('members');
45
200
  }
46
201
  if (filters.length > 0) {
47
202
  query = query.filter(filters.join(' and '));
48
203
  }
49
- if (params?.expand && params.expand.length > 0) {
50
- query = query.expand(params.expand.join(','));
204
+ if (expand.size > 0) {
205
+ query = query.expand([...expand].join(','));
206
+ }
207
+ if (params?.orderByLastMessage) {
208
+ query = query.orderby('lastMessagePreview/createdDateTime desc');
51
209
  }
52
210
  }
53
211
  const response = (await query.get());
@@ -58,6 +216,14 @@ export class ChatsApi extends BaseApi {
58
216
  }
59
217
  /**
60
218
  * Create a new chat (1:1 or group).
219
+ *
220
+ * For 1:1 chats, Microsoft documents that "if a one-on-one chat already
221
+ * exists between the specified members, the existing chat is returned
222
+ * instead of creating a new one." However we still treat this as a
223
+ * write operation because (a) it has visible side effects on the Teams
224
+ * UI when the chat doesn't exist, and (b) the dedup behavior isn't
225
+ * something we want to rely on for read paths. For "find an existing
226
+ * 1:1", use {@link findDmByUserId} instead.
61
227
  */
62
228
  async create(params) {
63
229
  const payload = {
@@ -1 +1 @@
1
- {"version":3,"file":"chats.js","sourceRoot":"","sources":["../../src/api/chats.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chats.js","sourceRoot":"","sources":["../../src/api/chats.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { BaseApi } from './base.js';
2
- import type { ChatMessage, DeleteChatMessageParams, DownloadHostedContentParams, DownloadHostedContentResult, GetChatMessagesParams, GetMessageParams, SearchMessagesParams, SearchResponse, SendChatMessageParams, SetMessageReactionParams, UnsetMessageReactionParams, UpdateChatMessageParams } from '../types/index.js';
2
+ import type { ChatMessage, DeleteChatMessageParams, DownloadHostedContentParams, DownloadHostedContentResult, GetChatMessagesParams, GetMessageParams, ListMessagesParams, ListMessagesResult, SearchMessagesParams, SearchResponse, SendChatMessageParams, SetMessageReactionParams, UnsetMessageReactionParams, UpdateChatMessageParams } from '../types/index.js';
3
3
  /**
4
4
  * API for message operations.
5
5
  */
@@ -14,9 +14,69 @@ export declare class MessagesApi extends BaseApi {
14
14
  */
15
15
  get(params: GetMessageParams): Promise<ChatMessage>;
16
16
  /**
17
- * Get messages from a chat.
17
+ * Get messages from a chat. Returns a flat array of `ChatMessage`.
18
+ *
19
+ * Backward-compat method: prefer `listMessages` for new code, which exposes
20
+ * pagination metadata and a richer return shape.
21
+ *
22
+ * **Bug fix history**: this method previously built the OData filter
23
+ * `from/user/id eq '<id>'` for the `fromUser` param. Graph rejects this
24
+ * with "The entity property 'user/id' and operationKind 'Equal' is not
25
+ * allowed in $filter query." (HTTP 400). The filter is now applied
26
+ * client-side after fetching the page — see the doc on `listMessages`
27
+ * for the full reasoning.
18
28
  */
19
29
  getChatMessages(params: GetChatMessagesParams): Promise<ChatMessage[]>;
30
+ /**
31
+ * List messages in a chat with caller-driven pagination.
32
+ *
33
+ * Returns one page plus a `nextLink` token. The caller passes the token
34
+ * back as `nextLink` on a follow-up call to fetch the next page. This
35
+ * method does NOT loop through pages.
36
+ *
37
+ * **Server-side capabilities of `/chats/{id}/messages`** (verified
38
+ * empirically — Microsoft's docs are vague on most of this):
39
+ *
40
+ * - `$top` ✓ (works, max ~50)
41
+ * - `$orderby=createdDateTime desc` ✓ (default)
42
+ * - `$filter=lastModifiedDateTime gt|lt <iso>` ✓ — the only content-ish
43
+ * filter that works
44
+ * - `$search` ✗ — "Query option 'Search' is not allowed"
45
+ * - `$filter=contains(body/content, 'X')` ✗ — "Only binary operation
46
+ * expressions are allowed"
47
+ * - `$filter=from/user/id eq 'X'` ✗ — "operationKind 'Equal' is not
48
+ * allowed"
49
+ *
50
+ * Microsoft's recommended approach for keyword search within a chat is:
51
+ * use the global `/search/query` endpoint and filter `chatId` client-side.
52
+ * That global path is implemented in `messages.search()`. This local path
53
+ * is for chronological reading of a chat with optional date filter.
54
+ *
55
+ * **The `containing` and `fromUser` params are client-side filters** —
56
+ * they keep only messages from the returned page that match. The
57
+ * `scanned` and `matched` fields in the result tell the caller how many
58
+ * messages were inspected vs how many matched, so the agent can paginate
59
+ * forward if it wants more.
60
+ *
61
+ * @example
62
+ * // Read the most recent 50 messages from a chat:
63
+ * const r = await client.messages.listMessages({ chatId, limit: 50 });
64
+ * console.log(r.messages, r.nextLink);
65
+ *
66
+ * @example
67
+ * // Find messages containing "ticket" in the most recent 50:
68
+ * const r = await client.messages.listMessages({
69
+ * chatId, limit: 50, containing: 'ticket'
70
+ * });
71
+ * // r.scanned === 50, r.matched === r.messages.length
72
+ *
73
+ * @example
74
+ * // Page forward:
75
+ * const r2 = await client.messages.listMessages({
76
+ * chatId, nextLink: r.nextLink
77
+ * });
78
+ */
79
+ listMessages(params: ListMessagesParams): Promise<ListMessagesResult>;
20
80
  /**
21
81
  * Send a message to a chat.
22
82
  */
@@ -26,7 +86,66 @@ export declare class MessagesApi extends BaseApi {
26
86
  */
27
87
  updateChatMessage(params: UpdateChatMessageParams): Promise<void>;
28
88
  /**
29
- * Search messages across chats and channels.
89
+ * Search chat messages across the signed-in user's chats and channels.
90
+ *
91
+ * Uses the BETA `/search/query` endpoint with `entityTypes: ['chatMessage']`.
92
+ * Beta is the canonical example in Microsoft's docs and is functionally
93
+ * equivalent to v1.0 (verified empirically — same results, same latency)
94
+ * but is the documented forward path. See:
95
+ * https://learn.microsoft.com/en-us/graph/search-concept-chat-messages
96
+ *
97
+ * **What this method DOES support:**
98
+ *
99
+ * - Free-text full-text search across message body and attachments.
100
+ * Microsoft Search indexes all messages the user has access to —
101
+ * NOT recency-windowed, unlike `/me/chats` filters.
102
+ * - The full set of documented KQL operators (`from:`, `to:`, `mentions:`,
103
+ * `IsRead:`, `hasAttachment:`, `sent>`, `sent<`) via typed params.
104
+ * - Real pagination via `from_offset` (skip N hits) and `size` (page size).
105
+ * Caller drives pagination — this method does NOT loop.
106
+ * - Up to 500 hits per call (Graph hard cap is 501).
107
+ *
108
+ * **What this method does NOT support, and why:**
109
+ *
110
+ * - **No `chatId` / `channelId` / `scope` filter.** Microsoft has not built
111
+ * server-side filtering by chat or channel for `chatMessage` search.
112
+ * Verified exhaustively against ~12 KQL operator variants and request
113
+ * body shapes (`stringInputs`, `sourceFilters`, etc.) — none filter.
114
+ * Confirmed by Microsoft on
115
+ * https://learn.microsoft.com/en-us/answers/questions/5510799 :
116
+ * "All scoping beyond keyword/KQL must be done client-side."
117
+ *
118
+ * - **`from:` does NOT accept user IDs.** Per docs and verified empirically,
119
+ * `from:` accepts a display name (`from:Bob`, `from:"Bob Smith"`) or an
120
+ * email (`from:bob@contoso.com`). Passing a GUID returns 0 hits silently.
121
+ * Resolve a user ID to a name/email before passing it here.
122
+ *
123
+ * - **`mentions:` is the inverse:** it ONLY accepts the user ID, and the
124
+ * GUID must have dashes stripped. Per docs.
125
+ *
126
+ * **About `total` in the response:** Microsoft's docs say total is "the
127
+ * number of results on the page, not the total number of matching results."
128
+ * That documentation is wrong (or outdated). Verified empirically: `total`
129
+ * IS the grand total of matching messages across all pages, regardless of
130
+ * `size`. For very common terms total can be in the thousands.
131
+ *
132
+ * @example
133
+ * // Find messages I sent containing "delivery", page 1:
134
+ * const r = await client.messages.search({
135
+ * query: 'delivery',
136
+ * from: 'evrim.a@first.bet',
137
+ * size: 25,
138
+ * });
139
+ * // r.value[0].hitsContainers[0]: { total, moreResultsAvailable, hits[] }
140
+ *
141
+ * @example
142
+ * // Page 2:
143
+ * const r2 = await client.messages.search({
144
+ * query: 'delivery',
145
+ * from: 'evrim.a@first.bet',
146
+ * size: 25,
147
+ * from_offset: 25,
148
+ * });
30
149
  */
31
150
  search(params: SearchMessagesParams): Promise<SearchResponse>;
32
151
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/api/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EACV,WAAW,EAGX,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,qBAAqB,EACrB,gBAAgB,EAGhB,oBAAoB,EAEpB,cAAc,EACd,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAG3B;;GAEG;AACH,qBAAa,WAAY,SAAQ,OAAO;IACtC;;;OAGG;IACU,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAW7G;;OAEG;IACU,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAIhE;;OAEG;IACU,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAkCnF;;OAEG;IACU,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;IA6DjF;;OAEG;IACU,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC9E;;OAEG;IACU,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IA0C1E;;OAEG;IACU,WAAW,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzE;;OAEG;IACU,UAAU,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;OAEG;IACU,cAAc,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E;;OAEG;IACU,aAAa,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7E;;OAEG;YACW,qBAAqB;CAgEpC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/api/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EACV,WAAW,EAGX,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,qBAAqB,EACrB,gBAAgB,EAGhB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EAEpB,cAAc,EACd,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAG3B;;GAEG;AACH,qBAAa,WAAY,SAAQ,OAAO;IACtC;;;OAGG;IACU,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAW7G;;OAEG;IACU,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAIhE;;;;;;;;;;;;OAYG;IACU,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAyBnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACU,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgDlF;;OAEG;IACU,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;IA6DjF;;OAEG;IACU,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6DG;IACU,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAoD1E;;OAEG;IACU,WAAW,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzE;;OAEG;IACU,UAAU,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;OAEG;IACU,cAAc,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E;;OAEG;IACU,aAAa,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7E;;OAEG;YACW,qBAAqB;CAgEpC"}