@aligndottech/connector-core 0.5.0 → 0.6.1

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.
Files changed (59) hide show
  1. package/dist/fetchers/confluence.d.ts +2 -1
  2. package/dist/fetchers/confluence.d.ts.map +1 -1
  3. package/dist/fetchers/confluence.js +14 -9
  4. package/dist/fetchers/confluence.js.map +1 -1
  5. package/dist/fetchers/errors.d.ts +43 -5
  6. package/dist/fetchers/errors.d.ts.map +1 -1
  7. package/dist/fetchers/errors.js +115 -6
  8. package/dist/fetchers/errors.js.map +1 -1
  9. package/dist/fetchers/git.d.ts +2 -1
  10. package/dist/fetchers/git.d.ts.map +1 -1
  11. package/dist/fetchers/git.js +8 -1
  12. package/dist/fetchers/git.js.map +1 -1
  13. package/dist/fetchers/github.d.ts +2 -1
  14. package/dist/fetchers/github.d.ts.map +1 -1
  15. package/dist/fetchers/github.js +12 -2
  16. package/dist/fetchers/github.js.map +1 -1
  17. package/dist/fetchers/gitlab.d.ts +4 -2
  18. package/dist/fetchers/gitlab.d.ts.map +1 -1
  19. package/dist/fetchers/gitlab.js +35 -5
  20. package/dist/fetchers/gitlab.js.map +1 -1
  21. package/dist/fetchers/index.d.ts +1 -1
  22. package/dist/fetchers/index.d.ts.map +1 -1
  23. package/dist/fetchers/index.js +1 -1
  24. package/dist/fetchers/index.js.map +1 -1
  25. package/dist/fetchers/jira.d.ts +2 -1
  26. package/dist/fetchers/jira.d.ts.map +1 -1
  27. package/dist/fetchers/jira.js +14 -11
  28. package/dist/fetchers/jira.js.map +1 -1
  29. package/dist/fetchers/linear.d.ts +2 -1
  30. package/dist/fetchers/linear.d.ts.map +1 -1
  31. package/dist/fetchers/linear.js +22 -4
  32. package/dist/fetchers/linear.js.map +1 -1
  33. package/dist/fetchers/notion.d.ts +4 -1
  34. package/dist/fetchers/notion.d.ts.map +1 -1
  35. package/dist/fetchers/notion.js +64 -30
  36. package/dist/fetchers/notion.js.map +1 -1
  37. package/dist/fetchers/slack.d.ts +12 -3
  38. package/dist/fetchers/slack.d.ts.map +1 -1
  39. package/dist/fetchers/slack.js +232 -30
  40. package/dist/fetchers/slack.js.map +1 -1
  41. package/dist/fetchers/teams.d.ts +2 -1
  42. package/dist/fetchers/teams.d.ts.map +1 -1
  43. package/dist/fetchers/teams.js +21 -4
  44. package/dist/fetchers/teams.js.map +1 -1
  45. package/dist/fetchers/util/time.d.ts +15 -0
  46. package/dist/fetchers/util/time.d.ts.map +1 -0
  47. package/dist/fetchers/util/time.js +24 -0
  48. package/dist/fetchers/util/time.js.map +1 -0
  49. package/dist/fetchers/zoom.d.ts +6 -1
  50. package/dist/fetchers/zoom.d.ts.map +1 -1
  51. package/dist/fetchers/zoom.js +105 -35
  52. package/dist/fetchers/zoom.js.map +1 -1
  53. package/dist/index.d.ts +2 -2
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +1 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/types/fetcher.d.ts +54 -0
  58. package/dist/types/fetcher.d.ts.map +1 -1
  59. package/package.json +1 -1
@@ -1,14 +1,129 @@
1
1
  import { fetch } from 'undici';
2
+ import { toIsoOrUndefined } from './util/time.js';
3
+ import { FetcherAuthError } from './errors.js';
2
4
  async function slackGet(endpoint, token, params = {}) {
3
5
  const qs = new URLSearchParams(params);
4
6
  const res = await fetch(`https://slack.com/api/${endpoint}?${qs}`, {
5
7
  headers: { Authorization: `Bearer ${token}` },
6
8
  });
7
9
  const data = (await res.json());
8
- if (!data.ok)
9
- throw new Error(`Slack API error on ${endpoint}: ${data.error}`);
10
+ if (!data.ok) {
11
+ // Slack answers HTTP 200 with ok:false and an error code; these codes are its 401.
12
+ const code = String(data.error);
13
+ if (SLACK_AUTH_ERRORS.has(code))
14
+ throw new FetcherAuthError('Slack', code);
15
+ throw new Error(`Slack API error on ${endpoint}: ${code}`);
16
+ }
10
17
  return data;
11
18
  }
19
+ /** Slack's error codes that mean the token itself was refused (its documented auth family). */
20
+ const SLACK_AUTH_ERRORS = new Set(['invalid_auth', 'not_authed', 'token_revoked', 'token_expired', 'account_inactive']);
21
+ /**
22
+ * Bounds, every one overridable through opts so tests never sleep and a large
23
+ * workspace can be widened deliberately. Each one, when it fires, becomes a line
24
+ * the user reads in the fetch report - a cap nobody is told about is
25
+ * indistinguishable from a thin tool (ALI-828).
26
+ *
27
+ * The numbers are derived, not measured: 200 channels at the 3-second Tier-2
28
+ * delay is 10 minutes of sleeping on its own, and 8 minutes is what the 15-minute
29
+ * `align setup --local` budget leaves for Slack once the other sources are paid
30
+ * for. The reference workspace (61 channels) reaches neither.
31
+ */
32
+ const SLACK_MAX_CHANNELS = 200;
33
+ const SLACK_MAX_HISTORY_PAGES = 5; // ~5,000 messages inside the daysBack window
34
+ const SLACK_MAX_REPLY_PAGES = 3; // ~3,000 messages in one thread
35
+ /**
36
+ * Page sizes at each endpoint's documented maximum: "under 1000" for list and
37
+ * history, 1000 (the default and the max) for replies. 0.5.0 sent
38
+ * conversations.replies with no limit, so a thread of up to 1000 messages came
39
+ * back in one call; a smaller page here would cut a KEPT thread at
40
+ * maxReplyPages and move its bytes, which the golden contract forbids. Slack's
41
+ * 2025 15-object cap applies only to commercially distributed non-Marketplace
42
+ * apps; a user's own app, which is what the CLI token belongs to, is exempt.
43
+ */
44
+ const SLACK_LIST_PAGE_SIZE = 999;
45
+ const SLACK_HISTORY_PAGE_SIZE = 999;
46
+ const SLACK_REPLIES_PAGE_SIZE = 1000;
47
+ const SLACK_TIME_BUDGET_MS = 8 * 60_000;
48
+ /**
49
+ * Message subtypes that are the WORKSPACE talking, not a person: joins, leaves,
50
+ * topic changes, pins, and app output. A thread made only of these is machinery,
51
+ * and on the Align demo workspace 35 of 39 captured "threads" were exactly that -
52
+ * a tombstone root under the Align app's own replies (ALI-828).
53
+ *
54
+ * A closed denylist rather than "any subtype at all": `thread_broadcast` is a
55
+ * human reply that was also posted to the channel, and `file_share` is a human
56
+ * sharing a file with a comment. Both are decision content and both carry a
57
+ * subtype. Every member here has its own case in fetchers.slack.test.ts.
58
+ */
59
+ const SYSTEM_SUBTYPES = new Set([
60
+ 'bot_message',
61
+ 'tombstone',
62
+ 'channel_join',
63
+ 'channel_leave',
64
+ 'channel_topic',
65
+ 'channel_purpose',
66
+ 'channel_name',
67
+ 'channel_archive',
68
+ 'channel_unarchive',
69
+ 'group_join',
70
+ 'group_leave',
71
+ 'pinned_item',
72
+ 'unpinned_item',
73
+ 'bot_add',
74
+ 'bot_remove',
75
+ 'reminder_add',
76
+ 'group_topic',
77
+ 'group_purpose',
78
+ 'group_name',
79
+ 'group_archive',
80
+ 'group_unarchive',
81
+ 'channel_convert_to_private',
82
+ 'channel_convert_to_public',
83
+ 'channel_posting_permissions',
84
+ 'ekm_access_denied',
85
+ ]);
86
+ /**
87
+ * A message a person wrote. `bot_id` catches an app posting AS a user (which
88
+ * carries no subtype at all), and a message with no `user` has nobody to
89
+ * attribute it to.
90
+ *
91
+ * Deliberately not "is this the Align bot": the CLI's Slack path uses a user
92
+ * token, whose `auth.test` names the HUMAN, so an identity filter would delete
93
+ * the user's own messages. The shape test catches Align's bot as one member of
94
+ * the class of all bots, and stays vendor-neutral.
95
+ */
96
+ function isHumanMessage(m) {
97
+ if (m.bot_id)
98
+ return false;
99
+ // A fired /remind or a Slackbot reply carries no bot_id and no subtype, only this user.
100
+ if (m.user === 'USLACKBOT')
101
+ return false;
102
+ if (m.subtype && SYSTEM_SUBTYPES.has(m.subtype))
103
+ return false;
104
+ return Boolean(m.user);
105
+ }
106
+ /**
107
+ * Follow `response_metadata.next_cursor` for up to `maxPages` pages, or until
108
+ * `enough(rows)` says to stop. `truncated` is true when a cursor was still there
109
+ * when paging stopped, which is the fact the report needs: rows exist that this
110
+ * read did not see.
111
+ */
112
+ async function slackPaged(endpoint, token, params, rowsKey, maxPages, enough = () => false) {
113
+ const rows = [];
114
+ let cursor;
115
+ let pages = 0;
116
+ for (;;) {
117
+ const data = await slackGet(endpoint, token, { ...params, ...(cursor ? { cursor } : {}) });
118
+ rows.push(...(data[rowsKey] ?? []));
119
+ pages += 1;
120
+ cursor = data.response_metadata?.next_cursor || undefined;
121
+ if (!cursor)
122
+ return { rows, truncated: false };
123
+ if (enough(rows) || pages >= maxPages)
124
+ return { rows, truncated: true };
125
+ }
126
+ }
12
127
  /** Resolve a Slack user id to a display name (cached - one users.info call per unique user). */
13
128
  function makeUserResolver(token) {
14
129
  const cache = new Map();
@@ -37,67 +152,154 @@ function makeUserResolver(token) {
37
152
  }
38
153
  /**
39
154
  * Read-only personal Slack fetcher: threaded conversations (>=2 replies) the
40
- * token can see, within `daysBack`. Author = the thread starter. A delay between
41
- * channels keeps under Slack's Tier-2 rate limit (override via `interChannelDelayMs`).
155
+ * token can see, within `daysBack`, that hold at least one HUMAN message. Title
156
+ * and author come from the first human message, so a thread whose root was
157
+ * deleted or posted by a bot is still captured when a person spoke in it, and a
158
+ * thread made only of bot and system output is not captured at all.
159
+ *
160
+ * Channels, history and replies are all paged. Every bound (`maxChannels`,
161
+ * `maxHistoryPages`, `maxReplyPages`, `timeBudgetMs`) and every filter that
162
+ * fires is counted into the fetch report, so a thin result comes with its
163
+ * reason. A delay between channels keeps under Slack's Tier-2 rate limit
164
+ * (override via `interChannelDelayMs`).
42
165
  */
43
166
  export class SlackFetcher {
44
167
  async fetch(opts) {
168
+ return (await this.fetchWithReport(opts)).items;
169
+ }
170
+ async fetchWithReport(opts) {
45
171
  const limit = opts.limit ?? 50;
46
172
  const daysBack = opts.daysBack ?? 90;
47
173
  const delayMs = opts.interChannelDelayMs ?? 3000;
48
- const oldest = String(Math.floor(Date.now() / 1000) - daysBack * 86400);
174
+ const maxChannels = opts.maxChannels ?? SLACK_MAX_CHANNELS;
175
+ const maxHistoryPages = opts.maxHistoryPages ?? SLACK_MAX_HISTORY_PAGES;
176
+ const maxReplyPages = opts.maxReplyPages ?? SLACK_MAX_REPLY_PAGES;
177
+ const timeBudgetMs = opts.timeBudgetMs ?? SLACK_TIME_BUDGET_MS;
178
+ const startedAt = Date.now();
179
+ const oldest = String(Math.floor(startedAt / 1000) - daysBack * 86400);
49
180
  await slackGet('auth.test', opts.token);
50
- const chanData = await slackGet('conversations.list', opts.token, {
51
- types: 'public_channel,private_channel',
52
- exclude_archived: 'true',
53
- limit: '100',
54
- });
55
- const channels = chanData.channels ?? [];
181
+ // Read list pages until one shows MORE channels than the cap, so the report
182
+ // can name the surplus it saw rather than "some". At most one page past the
183
+ // cap is read, and a cursor left after that means the surplus is a floor.
184
+ const list = await slackPaged('conversations.list', opts.token, { types: 'public_channel,private_channel', exclude_archived: 'true', limit: String(SLACK_LIST_PAGE_SIZE) }, 'channels', Number.POSITIVE_INFINITY, (rows) => rows.length > maxChannels);
185
+ const channels = list.rows.slice(0, maxChannels);
186
+ const channelSurplus = list.rows.length - channels.length;
56
187
  const resolveUser = makeUserResolver(opts.token);
57
188
  const items = [];
189
+ let threadsScanned = 0;
190
+ let shortMessages = 0;
191
+ let noHumanThreads = 0;
192
+ let historyCut = 0;
193
+ let repliesCut = 0;
194
+ let channelsUnreadable = 0;
195
+ let threadsUnreadable = 0;
196
+ let channelsOutOfTime = 0;
58
197
  for (let channelIndex = 0; channelIndex < channels.length; channelIndex++) {
59
198
  const channel = channels[channelIndex];
60
199
  if (items.length >= limit)
61
200
  break;
62
- try {
63
- if (channelIndex > 0 && delayMs > 0)
201
+ if (channelIndex > 0) {
202
+ // Checked BEFORE paying the delay: the budget bounds the loop, not the sleep.
203
+ if (Date.now() - startedAt > timeBudgetMs) {
204
+ channelsOutOfTime = channels.length - channelIndex;
205
+ break;
206
+ }
207
+ if (delayMs > 0)
64
208
  await new Promise((r) => setTimeout(r, delayMs));
65
- const hist = await slackGet('conversations.history', opts.token, {
66
- channel: channel.id,
67
- oldest,
68
- limit: '100',
69
- });
70
- const messages = hist.messages ?? [];
71
- const threads = messages.filter((m) => (m.reply_count ?? 0) >= 2);
209
+ }
210
+ try {
211
+ const hist = await slackPaged('conversations.history', opts.token, { channel: channel.id, oldest, limit: String(SLACK_HISTORY_PAGE_SIZE) }, 'messages', maxHistoryPages);
212
+ if (hist.truncated)
213
+ historyCut += 1;
214
+ const threads = hist.rows.filter((m) => (m.reply_count ?? 0) >= 2);
215
+ shortMessages += hist.rows.length - threads.length;
72
216
  for (const thread of threads) {
73
217
  if (items.length >= limit)
74
218
  break;
219
+ threadsScanned += 1;
75
220
  try {
76
- const replies = await slackGet('conversations.replies', opts.token, {
77
- channel: channel.id,
78
- ts: thread.ts,
79
- });
80
- const allMsgs = replies.messages ?? [];
221
+ const replies = await slackPaged('conversations.replies', opts.token, { channel: channel.id, ts: thread.ts, limit: String(SLACK_REPLIES_PAGE_SIZE) }, 'messages', maxReplyPages);
222
+ // A truncated thread is still an item; dropping it would lose the
223
+ // decision to protect a byte count. The truncation is reported instead.
224
+ if (replies.truncated)
225
+ repliesCut += 1;
226
+ // Dedupe by ts: Slack does not say whether a cursor page of replies carries
227
+ // the parent again, and a repeated root would double its text.
228
+ const seenTs = new Set();
229
+ const allMsgs = [];
230
+ for (const m of replies.rows) {
231
+ if (seenTs.has(m.ts))
232
+ continue;
233
+ seenTs.add(m.ts);
234
+ allMsgs.push(m);
235
+ }
236
+ // The thread's identity comes from the first HUMAN message: a deleted or
237
+ // bot root has no title and nobody to attribute, but the conversation
238
+ // under it may be entirely real.
239
+ const firstHuman = allMsgs.find(isHumanMessage);
240
+ if (!firstHuman) {
241
+ noHumanThreads += 1; // machinery, not a conversation
242
+ continue;
243
+ }
244
+ // Every fetched message, bot replies included: a bot reply inside a human
245
+ // thread is often the CI output being discussed.
81
246
  const text = allMsgs.map((m) => m.text ?? '').join('\n');
82
- const author = await resolveUser(allMsgs[0]?.user ?? thread.user);
247
+ const author = await resolveUser(firstHuman.user);
248
+ // The root's ts: epoch seconds with microseconds, so the thread is dated by when it started.
249
+ const createdAt = toIsoOrUndefined(Number(thread.ts) * 1000);
83
250
  items.push({
84
251
  source_url: `https://slack.com/archives/${channel.id}/p${thread.ts.replace('.', '')}`,
85
252
  platform: 'slack',
86
253
  raw_text: `[#${channel.name}] Thread:\n${text}`,
87
- title: (thread.text ?? `Thread in #${channel.name}`).slice(0, 80),
254
+ title: (firstHuman.text ?? `Thread in #${channel.name}`).slice(0, 80),
255
+ ...(createdAt ? { created_at: createdAt } : {}),
88
256
  ...(author ? { author } : {}),
89
257
  });
90
258
  }
91
259
  catch {
92
- /* skip individual thread errors */
260
+ threadsUnreadable += 1;
93
261
  }
94
262
  }
95
263
  }
96
264
  catch {
97
- /* skip channels that are inaccessible */
265
+ channelsUnreadable += 1;
98
266
  }
99
267
  }
100
- return items;
268
+ // A fixed order, so two runs over the same workspace print the same report.
269
+ const skips = [];
270
+ if (shortMessages > 0) {
271
+ skips.push({ kind: 'shape', count: shortMessages, detail: 'messages with fewer than 2 replies (this fetcher reads threads only)' });
272
+ }
273
+ if (noHumanThreads > 0) {
274
+ skips.push({ kind: 'shape', count: noHumanThreads, detail: 'threads with no human message (bot or system output only)' });
275
+ }
276
+ if (channelSurplus > 0) {
277
+ skips.push({
278
+ kind: 'page_cap',
279
+ count: channelSurplus,
280
+ detail: `${list.truncated ? 'or more ' : ''}channels not scanned (the first ${maxChannels} were; raise maxChannels)`,
281
+ });
282
+ }
283
+ if (historyCut > 0) {
284
+ skips.push({ kind: 'page_cap', count: historyCut, detail: `channels whose history was cut at ${maxHistoryPages} page(s) (raise maxHistoryPages)` });
285
+ }
286
+ if (repliesCut > 0) {
287
+ skips.push({ kind: 'page_cap', count: repliesCut, detail: `threads whose replies were cut at ${maxReplyPages} page(s) (raise maxReplyPages)` });
288
+ }
289
+ if (channelsOutOfTime > 0) {
290
+ skips.push({
291
+ kind: 'time_budget',
292
+ count: channelsOutOfTime,
293
+ detail: `channels not scanned (the ${Math.round(timeBudgetMs / 60_000)} minute Slack time budget ran out)`,
294
+ });
295
+ }
296
+ if (channelsUnreadable > 0) {
297
+ skips.push({ kind: 'error', count: channelsUnreadable, detail: 'channels the token could not read' });
298
+ }
299
+ if (threadsUnreadable > 0) {
300
+ skips.push({ kind: 'error', count: threadsUnreadable, detail: 'threads whose replies could not be read' });
301
+ }
302
+ return { items, report: { platform: 'slack', scanned: threadsScanned, requested: limit, skips } };
101
303
  }
102
304
  }
103
305
  //# sourceMappingURL=slack.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/fetchers/slack.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/fetchers/slack.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem, FetchResult } from '../types/fetcher.js';
2
2
  /**
3
3
  * Read-only personal Teams fetcher: recent channel messages (+replies) across the
4
4
  * caller's joined teams. Author = the message author. Needs admin-consented
@@ -6,5 +6,6 @@ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../
6
6
  */
7
7
  export declare class TeamsFetcher implements ConnectorFetcher {
8
8
  fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
9
+ fetchWithReport(opts: ConnectorFetcherOptions): Promise<FetchResult>;
9
10
  }
10
11
  //# sourceMappingURL=teams.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../../src/fetchers/teams.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAmDlG;;;;GAIG;AACH,qBAAa,YAAa,YAAW,gBAAgB;IAC7C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CA6CnE"}
1
+ {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../../src/fetchers/teams.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AA6D/G;;;;GAIG;AACH,qBAAa,YAAa,YAAW,gBAAgB;IAC7C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI5D,eAAe,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC;CAiD3E"}
@@ -1,4 +1,6 @@
1
1
  import { fetch } from 'undici';
2
+ import { toIsoOrUndefined } from './util/time.js';
3
+ import { providerError, refusedBody } from './errors.js';
2
4
  function stripHtml(html) {
3
5
  return html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
4
6
  }
@@ -7,14 +9,22 @@ async function graphGet(path, token) {
7
9
  headers: { Authorization: `Bearer ${token}` },
8
10
  });
9
11
  if (!res.ok) {
10
- const err = (await res.json().catch(() => ({})));
11
- const code = err.error?.code ?? '';
12
+ // Read the body once: the consent branch needs Graph's error code, and providerError
13
+ // needs the same bytes for the message.
14
+ const raw = await refusedBody(res);
15
+ let code = '';
16
+ try {
17
+ code = (JSON.parse(raw).error?.code) ?? '';
18
+ }
19
+ catch {
20
+ /* not JSON; no code to read */
21
+ }
12
22
  if (res.status === 403 || code.includes('Authorization') || code.includes('Consent')) {
13
23
  throw new Error('Teams requires admin consent for ChannelMessage.Read.All. ' +
14
24
  'Ask your Microsoft 365 admin to grant consent, or see: ' +
15
25
  'https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade');
16
26
  }
17
- throw new Error(`Microsoft Graph API error ${res.status} on ${path}: ${err.error?.message ?? 'unknown'}`);
27
+ throw await providerError('Teams', { status: res.status, text: async () => raw });
18
28
  }
19
29
  return res.json();
20
30
  }
@@ -30,9 +40,13 @@ function extractText(body) {
30
40
  */
31
41
  export class TeamsFetcher {
32
42
  async fetch(opts) {
43
+ return (await this.fetchWithReport(opts)).items;
44
+ }
45
+ async fetchWithReport(opts) {
33
46
  const limit = opts.limit ?? 50;
34
47
  const teams = await graphGet('/me/joinedTeams', opts.token);
35
48
  const items = [];
49
+ let scanned = 0;
36
50
  for (const team of teams.value) {
37
51
  if (items.length >= limit)
38
52
  break;
@@ -45,6 +59,7 @@ export class TeamsFetcher {
45
59
  for (const msg of msgs.value) {
46
60
  if (items.length >= limit)
47
61
  break;
62
+ scanned += 1;
48
63
  const mainText = extractText(msg.body);
49
64
  const replyTexts = (msg.replies ?? []).map((r) => extractText(r.body)).filter(Boolean);
50
65
  const raw_text = [
@@ -56,11 +71,13 @@ export class TeamsFetcher {
56
71
  .filter(Boolean)
57
72
  .join('\n');
58
73
  const fromName = msg.from?.user?.displayName;
74
+ const createdAt = toIsoOrUndefined(msg.createdDateTime);
59
75
  items.push({
60
76
  source_url: msg.webUrl ?? 'https://teams.microsoft.com',
61
77
  platform: 'teams',
62
78
  raw_text,
63
79
  title: (msg.subject ?? mainText).slice(0, 80) || `Message in ${team.displayName}`,
80
+ ...(createdAt ? { created_at: createdAt } : {}),
64
81
  ...(fromName ? { author: { name: fromName } } : {}),
65
82
  });
66
83
  }
@@ -70,7 +87,7 @@ export class TeamsFetcher {
70
87
  }
71
88
  }
72
89
  }
73
- return items;
90
+ return { items, report: { platform: 'teams', scanned, requested: limit, skips: [] } };
74
91
  }
75
92
  }
76
93
  //# sourceMappingURL=teams.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"teams.js","sourceRoot":"","sources":["../../src/fetchers/teams.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"teams.js","sourceRoot":"","sources":["../../src/fetchers/teams.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Normalise a source timestamp to ISO-8601 Z, or undefined.
3
+ *
4
+ * Undefined rather than a fallback: a null date says "unknown", and a plausible
5
+ * wrong date is indistinguishable from a measurement to everything downstream.
6
+ * NaN is checked explicitly because every comparison against NaN is false in
7
+ * both directions, so an unchecked bad date does not error, it silently vacates
8
+ * whatever filter reads it later.
9
+ *
10
+ * One writer for the normalisation, so ten fetchers cannot disagree about what
11
+ * "ISO" means. Accepts epoch milliseconds as a number for sources that hand out
12
+ * a numeric timestamp (Slack's `ts` is epoch seconds; callers multiply).
13
+ */
14
+ export declare function toIsoOrUndefined(value: string | number | undefined | null): string | undefined;
15
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../../src/fetchers/util/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAO9F"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Normalise a source timestamp to ISO-8601 Z, or undefined.
3
+ *
4
+ * Undefined rather than a fallback: a null date says "unknown", and a plausible
5
+ * wrong date is indistinguishable from a measurement to everything downstream.
6
+ * NaN is checked explicitly because every comparison against NaN is false in
7
+ * both directions, so an unchecked bad date does not error, it silently vacates
8
+ * whatever filter reads it later.
9
+ *
10
+ * One writer for the normalisation, so ten fetchers cannot disagree about what
11
+ * "ISO" means. Accepts epoch milliseconds as a number for sources that hand out
12
+ * a numeric timestamp (Slack's `ts` is epoch seconds; callers multiply).
13
+ */
14
+ export function toIsoOrUndefined(value) {
15
+ if (value === undefined || value === null || value === '')
16
+ return undefined;
17
+ const ms = typeof value === 'number' ? value : Date.parse(value);
18
+ // A zero or negative instant is not a source date either: Number('') is 0, and
19
+ // an epoch stamp in a decision graph is a fabrication with a plausible face.
20
+ if (Number.isNaN(ms) || ms <= 0)
21
+ return undefined;
22
+ return new Date(ms).toISOString();
23
+ }
24
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../../src/fetchers/util/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAyC;IACxE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5E,MAAM,EAAE,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjE,+EAA+E;IAC/E,6EAA6E;IAC7E,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAClD,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC"}
@@ -1,9 +1,14 @@
1
- import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem, FetchResult } from '../types/fetcher.js';
2
2
  /**
3
3
  * Read-only personal Zoom fetcher: cloud-recording transcripts (VTT), parsed to
4
4
  * plain text. Author = the meeting host. `uuid` (single meeting) rides on opts.
5
+ * Lists `/users/me/recordings` in 30-day windows back through `daysBack`
6
+ * (default 90), paging each with `next_page_token` up to `limit`; a meeting
7
+ * with no completed transcript, or one whose transcript will not download, is
8
+ * counted into the report rather than dropped in silence.
5
9
  */
6
10
  export declare class ZoomFetcher implements ConnectorFetcher {
7
11
  fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
12
+ fetchWithReport(opts: ConnectorFetcherOptions): Promise<FetchResult>;
8
13
  }
9
14
  //# sourceMappingURL=zoom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../src/fetchers/zoom.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgDlG;;;GAGG;AACH,qBAAa,WAAY,YAAW,gBAAgB;IAC5C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAyCnE"}
1
+ {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../src/fetchers/zoom.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,WAAW,EAAa,MAAM,qBAAqB,CAAC;AA4E1H;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,gBAAgB;IAC5C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI5D,eAAe,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC;CA8E3E"}