@manudota/artist-mcp 0.8.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Calling the provider APIs directly from this machine.
3
+ *
4
+ * Ported from the edge function, which held the credentials and made these
5
+ * calls on the user's behalf. The logic is deliberately unchanged: the retry
6
+ * shape, the error surfacing and the scope diagnosis below were each learned
7
+ * from a specific failure, and a port is the wrong moment to second-guess them.
8
+ */
9
+ import { GraphError } from './client.js';
10
+ export const GRAPH = 'https://graph.microsoft.com/v1.0';
11
+ export const GMAIL = 'https://gmail.googleapis.com/gmail/v1';
12
+ export const CALENDAR = 'https://www.googleapis.com/calendar/v3';
13
+ /** Two retries, backing off. Beyond that the caller learns more than a longer wait would tell it. */
14
+ const DELAYS = [400, 1200];
15
+ export const getWithRetry = async (url, token, api) => {
16
+ for (let attempt = 0;; attempt++) {
17
+ const res = await fetch(url, { headers: { authorization: `Bearer ${token}` } });
18
+ if (res.ok)
19
+ return res;
20
+ const retryable = res.status >= 500 || res.status === 429;
21
+ if (!retryable || attempt >= DELAYS.length) {
22
+ // Both APIs explain their 4xx in the body. Without it every failure looks
23
+ // the same and the only debugging tool left is guesswork — the 20266
24
+ // outage read as an auth problem until the body was surfaced.
25
+ const detail = (await res.text().catch(() => '')).slice(0, 300);
26
+ // A refresh token carries the scopes it was granted with, and adding a
27
+ // scope later does not widen it. A connection made before Calendar
28
+ // existed here therefore authenticates fine and is refused per call, so
29
+ // this has to read as "reconnect", not as a broken integration.
30
+ if (res.status === 403 && /insufficient|ACCESS_TOKEN_SCOPE/i.test(detail)) {
31
+ throw new GraphError(`This connection predates ${api} access. Run \`artist-mcp connect google\` to grant it.`, true);
32
+ }
33
+ throw new GraphError(`${api} returned ${res.status}.${detail ? ` ${detail}` : ''}`, false);
34
+ }
35
+ await new Promise((resolve) => setTimeout(resolve, DELAYS[attempt]));
36
+ }
37
+ };
38
+ /**
39
+ * Paths are built by the callers from fixed literals, and any value that came
40
+ * from outside is shape-checked and encoded before it reaches one. Nothing from
41
+ * a caller is concatenated into a URL raw.
42
+ */
43
+ export const graphGet = (path, token) => getWithRetry(`${GRAPH}${path}`, token, 'Microsoft Graph');
44
+ export const gmailGet = (path, token) => getWithRetry(`${GMAIL}${path}`, token, 'Gmail');
45
+ export const calendarGet = (path, token) => getWithRetry(`${CALENDAR}${path}`, token, 'Google Calendar');