@introspection-ai/recipes 0.24.0 → 0.25.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.
Files changed (100) hide show
  1. package/README.md +3 -3
  2. package/dist/channels/tools.js +1 -1
  3. package/dist/channels/tools.js.map +1 -1
  4. package/dist/mcp-chunks/{auth-command-4OEOMU2V.js → auth-command-4WFRNU2I.js} +24 -24
  5. package/dist/mcp-chunks/call-arguments-4DWPBLQP.js +15 -0
  6. package/dist/mcp-chunks/{call-command-AUEKSBMD.js → call-command-JBIKXOGC.js} +36 -36
  7. package/dist/mcp-chunks/{chunk-L4CUJJI5.js → chunk-36VIJRYY.js} +4 -4
  8. package/dist/mcp-chunks/{chunk-PPIXUCYQ.js → chunk-3JGS7LQB.js} +2 -2
  9. package/dist/mcp-chunks/{chunk-4NDR45CX.js → chunk-3R2WK3NB.js} +28 -9
  10. package/dist/mcp-chunks/{chunk-YX2NKW6O.js → chunk-3Z7MFS6K.js} +23 -6
  11. package/dist/mcp-chunks/{chunk-ACTRQW5L.js → chunk-4ZNBWL65.js} +2 -2
  12. package/dist/mcp-chunks/chunk-53NRFMB3.js +990 -0
  13. package/dist/mcp-chunks/{chunk-6QH47GNE.js → chunk-6YZW3XAE.js} +68 -6
  14. package/dist/mcp-chunks/{chunk-X3FOKZ5C.js → chunk-7WOKCV6Q.js} +1 -1
  15. package/dist/mcp-chunks/{chunk-MOML5C2E.js → chunk-AD3FQ73K.js} +1 -1
  16. package/dist/mcp-chunks/{chunk-HDUKEFBI.js → chunk-AIKLVBYU.js} +2 -2
  17. package/dist/mcp-chunks/{chunk-SQTXZR56.js → chunk-ASG4OY3M.js} +21 -604
  18. package/dist/mcp-chunks/{chunk-V4RYLZM5.js → chunk-B2LNXGAP.js} +1 -1
  19. package/dist/mcp-chunks/{chunk-XVJAASVZ.js → chunk-BWW4XRUC.js} +16 -16
  20. package/dist/mcp-chunks/{chunk-MRXSXBZT.js → chunk-C2KNLFZR.js} +2 -2
  21. package/dist/mcp-chunks/{chunk-KPXFBRTG.js → chunk-CZKDJZER.js} +1 -1
  22. package/dist/mcp-chunks/{chunk-6CYJ6RN3.js → chunk-DTZHEVKC.js} +1 -1
  23. package/dist/mcp-chunks/{chunk-PLSS6TQZ.js → chunk-ED2WN5BI.js} +3 -3
  24. package/dist/mcp-chunks/{chunk-OGFFBNIC.js → chunk-ELA77TDC.js} +4 -4
  25. package/dist/mcp-chunks/{chunk-5WGJPYOR.js → chunk-EMSNQHZZ.js} +1 -1
  26. package/dist/mcp-chunks/{chunk-AB7MHBEG.js → chunk-EPT4MYOF.js} +11 -11
  27. package/dist/mcp-chunks/{chunk-HHMWZ2FZ.js → chunk-FAJPJTOC.js} +1 -1
  28. package/dist/mcp-chunks/{chunk-TGJOZDKG.js → chunk-FS5JIKT6.js} +2 -2
  29. package/dist/mcp-chunks/{chunk-IPH6U7SE.js → chunk-FX5NYWBH.js} +3 -3
  30. package/dist/mcp-chunks/{chunk-SCGMRUKI.js → chunk-G6OMDUNG.js} +5 -5
  31. package/dist/mcp-chunks/{chunk-47N2EELW.js → chunk-GQ6NSIDS.js} +30 -30
  32. package/dist/mcp-chunks/{chunk-PPOHGQKM.js → chunk-GUXMP7QB.js} +2 -2
  33. package/dist/mcp-chunks/{chunk-NMFI6AUD.js → chunk-H3JCYHGS.js} +25 -25
  34. package/dist/mcp-chunks/{chunk-3VLPWGJL.js → chunk-HCOKLSOB.js} +4 -4
  35. package/dist/mcp-chunks/{chunk-J6VOMOKI.js → chunk-HLRCUHNO.js} +1 -1
  36. package/dist/mcp-chunks/{chunk-LWVFSQYX.js → chunk-HN7WPMCA.js} +7806 -3454
  37. package/dist/mcp-chunks/chunk-I5GI2A2D.js +92 -0
  38. package/dist/mcp-chunks/{chunk-7KEDX7SE.js → chunk-IME7DGLJ.js} +2 -2
  39. package/dist/mcp-chunks/{chunk-E4YYMOT2.js → chunk-IPNSPKQK.js} +33 -21
  40. package/dist/mcp-chunks/{chunk-ZKFG37TB.js → chunk-IRTJXFWA.js} +2 -2
  41. package/dist/mcp-chunks/{chunk-KMH3PHLA.js → chunk-ITCCROID.js} +13 -7
  42. package/dist/mcp-chunks/{chunk-ADINDBOF.js → chunk-ITR7FQM3.js} +2 -2
  43. package/dist/mcp-chunks/{chunk-JILBFEBD.js → chunk-IYWYVHHD.js} +1 -1
  44. package/dist/mcp-chunks/{chunk-RO2Y34XX.js → chunk-JG4TRUPF.js} +1 -1
  45. package/dist/mcp-chunks/{chunk-DEYKPG4K.js → chunk-KW3ANJ36.js} +4 -4
  46. package/dist/mcp-chunks/{chunk-NWLOPQT7.js → chunk-MOEZ43ZL.js} +1 -1
  47. package/dist/mcp-chunks/{chunk-AFKE4BTR.js → chunk-NTHUNCXJ.js} +21 -21
  48. package/dist/mcp-chunks/{chunk-J3J3NQ4X.js → chunk-OD3MSMXY.js} +1 -1
  49. package/dist/mcp-chunks/{chunk-PRZCYXVO.js → chunk-OP3IW2V6.js} +2 -2
  50. package/dist/mcp-chunks/{chunk-K56RW4HB.js → chunk-PZ323CXI.js} +1 -1
  51. package/dist/mcp-chunks/{chunk-US57PK4B.js → chunk-QZUC2T72.js} +59 -4
  52. package/dist/mcp-chunks/{chunk-Z7O6NF7X.js → chunk-RD7NHCRK.js} +19 -19
  53. package/dist/mcp-chunks/{chunk-756YH7S4.js → chunk-RSTKSBVF.js} +2 -2
  54. package/dist/mcp-chunks/{chunk-6DL2C6V5.js → chunk-SCOMDV54.js} +1 -1
  55. package/dist/mcp-chunks/{chunk-SAK5KCLR.js → chunk-SNKXMWDB.js} +1 -1
  56. package/dist/mcp-chunks/{chunk-LC2CCTQN.js → chunk-TF2YTYE4.js} +1 -1
  57. package/dist/mcp-chunks/chunk-TPHPAEDH.js +3769 -0
  58. package/dist/mcp-chunks/{chunk-AF74TOWM.js → chunk-V5AYEKSL.js} +5 -5
  59. package/dist/mcp-chunks/{chunk-HBDCHBJP.js → chunk-WTMJMM3B.js} +12 -1
  60. package/dist/mcp-chunks/{chunk-ZZSD2JT7.js → chunk-WYLHHXI6.js} +1 -1
  61. package/dist/mcp-chunks/{chunk-MFFE5QSH.js → chunk-Y3EDWN2P.js} +1 -1
  62. package/dist/mcp-chunks/{chunk-ZRZ7C6L3.js → chunk-YIRGLKDA.js} +8 -8
  63. package/dist/mcp-chunks/{chunk-RE4EVQNC.js → chunk-ZOAQDFAO.js} +62 -7
  64. package/dist/mcp-chunks/{cli-B7WQQUME.js → cli-XU26MUCN.js} +67 -67
  65. package/dist/mcp-chunks/client-OT34CKRH.js +21 -0
  66. package/dist/mcp-chunks/{config-command-FF3JPMOP.js → config-command-UQMMIK2U.js} +37 -30
  67. package/dist/mcp-chunks/daemon-command-YCIOZGPZ.js +35 -0
  68. package/dist/mcp-chunks/{dist-V4UB7RTR.js → dist-DM2RXZMU.js} +47 -44
  69. package/dist/mcp-chunks/{emit-ts-command-4X56IZ32.js → emit-ts-command-KAOL6DAN.js} +16 -16
  70. package/dist/mcp-chunks/{generate-cli-runner-MIPF73SJ.js → generate-cli-runner-AK6XNRTK.js} +70 -50
  71. package/dist/mcp-chunks/{inspect-cli-command-GX54ZXKR.js → inspect-cli-command-6FVJO7H2.js} +10 -10
  72. package/dist/mcp-chunks/{launch-E2LWGPZS.js → launch-EIT73HX4.js} +1 -1
  73. package/dist/mcp-chunks/{lifecycle-TONHXXXJ.js → lifecycle-QH4TUI3K.js} +1 -1
  74. package/dist/mcp-chunks/{list-command-YUGRZO4G.js → list-command-UOB2XZK7.js} +30 -30
  75. package/dist/mcp-chunks/{output-utils-AZY6N2VQ.js → output-utils-6YXH23T7.js} +3 -3
  76. package/dist/mcp-chunks/{prompt-CH6TK0bC-NSBYYJZH.js → prompt-CH6TK0bC-ZB6RFAXR.js} +1 -1
  77. package/dist/mcp-chunks/{record-command-25DLELA2.js → record-command-FO5TTERC.js} +5 -5
  78. package/dist/mcp-chunks/{replay-command-6SLDG6PC.js → replay-command-SCBPCGQ7.js} +6 -6
  79. package/dist/mcp-chunks/{resource-command-YVOB4JCU.js → resource-command-S2J7XEMV.js} +10 -10
  80. package/dist/mcp-chunks/{result-utils-ZXB5DM36.js → result-utils-OME6HGS6.js} +4 -4
  81. package/dist/mcp-chunks/runtime-QIPMLIJI.js +39 -0
  82. package/dist/mcp-chunks/runtime-wrapper-X4YFKMJI.js +16 -0
  83. package/dist/mcp-chunks/{serve-command-QYGM2AMB.js → serve-command-DDBZZSG6.js} +28 -28
  84. package/dist/mcp-chunks/{timeouts-P3TBB3AX.js → timeouts-HNGNKDQN.js} +3 -3
  85. package/dist/mcp-chunks/{vault-command-VDMPATIX.js → vault-command-TJZYS3YI.js} +8 -7
  86. package/dist/mcp-chunks/{webapi-BLTNWSB2.js → webapi-4GWO2UBA.js} +887 -703
  87. package/dist/mcp-daemon.js +31 -31
  88. package/dist/mcp-run-worker.js +31 -31
  89. package/docs/channels.md +6 -5
  90. package/docs/recipe-format.md +6 -3
  91. package/docs/slack.md +14 -11
  92. package/package.json +11 -11
  93. package/dist/mcp-chunks/call-arguments-RPXZJOXL.js +0 -15
  94. package/dist/mcp-chunks/chunk-7CS27CWE.js +0 -431
  95. package/dist/mcp-chunks/chunk-LJCZWKGJ.js +0 -372
  96. package/dist/mcp-chunks/chunk-Q7ESBNJG.js +0 -57
  97. package/dist/mcp-chunks/client-4ZHIBB67.js +0 -21
  98. package/dist/mcp-chunks/daemon-command-FKW6YELL.js +0 -35
  99. package/dist/mcp-chunks/runtime-NOWGTHZ5.js +0 -39
  100. package/dist/mcp-chunks/runtime-wrapper-ZZPAFQE4.js +0 -14
@@ -0,0 +1,990 @@
1
+ import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
+ import {
3
+ readJsonFile,
4
+ withFileLock,
5
+ writeJsonFile,
6
+ writeTextFileAtomic
7
+ } from "./chunk-ITR7FQM3.js";
8
+ import {
9
+ legacyMcporterDir,
10
+ mcporterDir
11
+ } from "./chunk-FS5JIKT6.js";
12
+
13
+ // node_modules/.pnpm/mcporter@0.13.8/node_modules/mcporter/dist/oauth-vault.js
14
+ import crypto from "node:crypto";
15
+ import path from "node:path";
16
+
17
+ // node_modules/.pnpm/mcporter@0.13.8/node_modules/mcporter/dist/oauth-credential-validation.js
18
+ function isRecord(value) {
19
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
20
+ }
21
+ function isOptionalString(record, key) {
22
+ return record[key] === void 0 || typeof record[key] === "string";
23
+ }
24
+ function isOptionalFiniteNumber(record, key) {
25
+ return record[key] === void 0 || typeof record[key] === "number" && Number.isFinite(record[key]);
26
+ }
27
+ function isStoredOAuthTokens(value) {
28
+ if (!isRecord(value))
29
+ return false;
30
+ return typeof value.access_token === "string" && value.access_token.length > 0 && typeof value.token_type === "string" && value.token_type.length > 0 && isOptionalString(value, "refresh_token") && isOptionalString(value, "scope") && isOptionalString(value, "issuer") && isOptionalFiniteNumber(value, "expires_in") && isOptionalFiniteNumber(value, "expires_at") && isOptionalFiniteNumber(value, "expiresAt");
31
+ }
32
+ function isStoredOAuthClientInformation(value) {
33
+ if (!isRecord(value))
34
+ return false;
35
+ return isOptionalString(value, "issuer");
36
+ }
37
+
38
+ // node_modules/.pnpm/mcporter@0.13.8/node_modules/mcporter/dist/oauth-token-generation.js
39
+ import { randomUUID } from "node:crypto";
40
+ import { isDeepStrictEqual } from "node:util";
41
+ var TOKEN_GENERATION_FIELD = "__mcporter_generation";
42
+ var CLIENT_GENERATION_FIELD = "__mcporter_client_generation";
43
+ function tokenGenerationOf(tokens) {
44
+ const generation = tokens[TOKEN_GENERATION_FIELD];
45
+ return typeof generation === "string" && generation.length > 0 ? generation : void 0;
46
+ }
47
+ function clientGenerationOf(info) {
48
+ const generation = info[CLIENT_GENERATION_FIELD];
49
+ return typeof generation === "string" && generation.length > 0 ? generation : void 0;
50
+ }
51
+ function withoutTokenGeneration(tokens) {
52
+ const copy = { ...tokens };
53
+ delete copy[TOKEN_GENERATION_FIELD];
54
+ return copy;
55
+ }
56
+ function withoutClientGeneration(info) {
57
+ const copy = { ...info };
58
+ delete copy[CLIENT_GENERATION_FIELD];
59
+ return copy;
60
+ }
61
+ function withOAuthTokenGeneration(tokens) {
62
+ const generation = tokenGenerationOf(tokens) ?? randomUUID();
63
+ return { ...withoutTokenGeneration(tokens), [TOKEN_GENERATION_FIELD]: generation };
64
+ }
65
+ function withHiddenOAuthTokenGeneration(tokens) {
66
+ const generation = tokenGenerationOf(tokens);
67
+ if (!generation) {
68
+ return tokens;
69
+ }
70
+ const copy = withoutTokenGeneration(tokens);
71
+ Object.defineProperty(copy, TOKEN_GENERATION_FIELD, { value: generation, enumerable: false });
72
+ return copy;
73
+ }
74
+ function withOAuthClientGeneration(info) {
75
+ const generation = clientGenerationOf(info) ?? randomUUID();
76
+ const copy = { ...withoutClientGeneration(info) };
77
+ copy[CLIENT_GENERATION_FIELD] = generation;
78
+ return copy;
79
+ }
80
+ function withHiddenOAuthClientGeneration(info) {
81
+ const generation = clientGenerationOf(info);
82
+ if (!generation) {
83
+ return info;
84
+ }
85
+ const copy = withoutClientGeneration(info);
86
+ Object.defineProperty(copy, CLIENT_GENERATION_FIELD, { value: generation, enumerable: false });
87
+ return copy;
88
+ }
89
+ function sameOAuthTokenGeneration(current, expected) {
90
+ if (!current) {
91
+ return false;
92
+ }
93
+ const currentGeneration = tokenGenerationOf(current);
94
+ const expectedGeneration = tokenGenerationOf(expected);
95
+ if (currentGeneration || expectedGeneration) {
96
+ return currentGeneration !== void 0 && currentGeneration === expectedGeneration && sameOAuthTokenValue(current, expected);
97
+ }
98
+ return isDeepStrictEqual(current, expected);
99
+ }
100
+ function sameOAuthTokenValue(left, right) {
101
+ return isDeepStrictEqual(withoutTokenGeneration(left), withoutTokenGeneration(right));
102
+ }
103
+ function sameOAuthClientGeneration(current, expected) {
104
+ if (!current) {
105
+ return false;
106
+ }
107
+ const currentGeneration = clientGenerationOf(current);
108
+ const expectedGeneration = clientGenerationOf(expected);
109
+ if (currentGeneration || expectedGeneration) {
110
+ return currentGeneration !== void 0 && currentGeneration === expectedGeneration && sameOAuthClientValue(current, expected);
111
+ }
112
+ return isDeepStrictEqual(current, expected);
113
+ }
114
+ function sameOAuthClientValue(left, right) {
115
+ return isDeepStrictEqual(withoutClientGeneration(left), withoutClientGeneration(right));
116
+ }
117
+
118
+ // node_modules/.pnpm/mcporter@0.13.8/node_modules/mcporter/dist/oauth-vault.js
119
+ function getOAuthVaultPath() {
120
+ return path.join(mcporterDir("data"), "credentials.json");
121
+ }
122
+ async function readVaultState() {
123
+ try {
124
+ const existing = await readJsonFile(getOAuthVaultPath());
125
+ if (existing && (existing.version === 1 || existing.version === 2) && existing.entries && typeof existing.entries === "object") {
126
+ return {
127
+ vault: { ...existing, version: 2 },
128
+ needsRepair: existing.version !== 2
129
+ };
130
+ }
131
+ if (existing !== void 0) {
132
+ return { vault: emptyVault(), needsRepair: true };
133
+ }
134
+ } catch (error) {
135
+ if (!(error instanceof SyntaxError)) {
136
+ throw error;
137
+ }
138
+ return { vault: emptyVault(), needsRepair: true };
139
+ }
140
+ return { vault: emptyVault(), needsRepair: false };
141
+ }
142
+ async function readVault() {
143
+ return (await readVaultState()).vault;
144
+ }
145
+ function emptyVault() {
146
+ return { version: 2, entries: {} };
147
+ }
148
+ async function writeVault(contents) {
149
+ await writeJsonFile(getOAuthVaultPath(), contents);
150
+ }
151
+ function vaultKeyForDefinition(definition) {
152
+ const descriptor = {
153
+ name: definition.name,
154
+ url: definition.command.kind === "http" ? definition.command.url.toString() : null,
155
+ command: definition.command.kind === "stdio" ? { command: definition.command.command, args: definition.command.args ?? [] } : null
156
+ };
157
+ const digest = crypto.hash("sha256", JSON.stringify(descriptor), "hex").slice(0, 16);
158
+ return `${definition.name}|${digest}`;
159
+ }
160
+ async function reconcileVaultServerUrl(definition) {
161
+ if (definition.command.kind !== "http") {
162
+ return;
163
+ }
164
+ const serverUrl = definition.command.url.toString();
165
+ await withFileLock(getOAuthVaultPath(), async () => {
166
+ const { vault, needsRepair } = await readVaultState();
167
+ const serverUrls = stringRecord(vault.serverUrls);
168
+ const previousUrl = serverUrls[definition.name];
169
+ const namedEntryUrls = Object.values(vault.entries).filter((entry) => isVaultEntry(entry) && entry.serverName === definition.name).flatMap((entry) => typeof entry.serverUrl === "string" ? [entry.serverUrl] : []);
170
+ const urlChanged = previousUrl !== void 0 && previousUrl !== serverUrl || namedEntryUrls.some((url) => url !== serverUrl);
171
+ if (urlChanged) {
172
+ const invalidatedUrls = new Set([serverUrl, previousUrl, ...namedEntryUrls].filter((url) => url !== void 0));
173
+ for (const [key, entry] of Object.entries(vault.entries)) {
174
+ if (isVaultEntry(entry) && (entry.serverName === definition.name || isLegacyOAuthRenameCandidate(definition, entry) && entry.serverUrl !== void 0 && invalidatedUrls.has(entry.serverUrl))) {
175
+ delete vault.entries[key];
176
+ }
177
+ }
178
+ }
179
+ if (previousUrl === serverUrl && !urlChanged && !needsRepair) {
180
+ return;
181
+ }
182
+ vault.serverUrls = { ...serverUrls, [definition.name]: serverUrl };
183
+ await writeVault(vault);
184
+ });
185
+ }
186
+ function stringRecord(value) {
187
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
188
+ return {};
189
+ }
190
+ return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
191
+ }
192
+ async function vaultCredentialKeys(definition) {
193
+ const key = vaultKeyForDefinition(definition);
194
+ if (definition.command.kind !== "http") {
195
+ return [key];
196
+ }
197
+ const vault = await readVault();
198
+ return [.../* @__PURE__ */ new Set([key, ...legacyOAuthRenameKeys(vault, definition, key)])];
199
+ }
200
+ async function loadVaultEntryForRecovery(definition) {
201
+ const vault = await readVault();
202
+ const key = vaultKeyForDefinition(definition);
203
+ const resolved = resolveVaultEntry(vault, definition);
204
+ const tokenSnapshots = /* @__PURE__ */ new Map();
205
+ const clientSnapshots = /* @__PURE__ */ new Map();
206
+ for (const targetKey of [key, ...legacyOAuthRenameKeys(vault, definition, key)]) {
207
+ const candidate = isVaultEntry(vault.entries[targetKey]) ? vault.entries[targetKey] : void 0;
208
+ if (candidate?.tokens && resolved?.tokens && sameOAuthTokenValue(candidate.tokens, resolved.tokens)) {
209
+ tokenSnapshots.set(targetKey, candidate.tokens);
210
+ }
211
+ if (candidate?.clientInfo && resolved?.clientInfo && sameOAuthClientValue(candidate.clientInfo, resolved.clientInfo)) {
212
+ clientSnapshots.set(targetKey, candidate.clientInfo);
213
+ }
214
+ }
215
+ return {
216
+ entry: externalVaultEntry(resolved),
217
+ tokenSnapshots,
218
+ clientSnapshots
219
+ };
220
+ }
221
+ function resolveVaultEntry(vault, definition) {
222
+ const key = vaultKeyForDefinition(definition);
223
+ const exact = isVaultEntry(vault.entries[key]) ? vault.entries[key] : void 0;
224
+ const fallback = findSameUrlCredentials(vault, definition, key, exact);
225
+ if (!fallback.tokens && !fallback.clientInfo) {
226
+ return exact;
227
+ }
228
+ if (!exact) {
229
+ return {
230
+ serverName: definition.name,
231
+ serverUrl: definition.command.kind === "http" ? definition.command.url.toString() : void 0,
232
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
233
+ tokens: fallback.tokens,
234
+ clientInfo: fallback.clientInfo
235
+ };
236
+ }
237
+ return {
238
+ ...exact,
239
+ tokens: exact.tokens ?? fallback.tokens,
240
+ clientInfo: exact.clientInfo ?? (exact.tokens ? void 0 : fallback.clientInfo)
241
+ };
242
+ }
243
+ function externalVaultEntry(entry) {
244
+ if (!entry) {
245
+ return entry;
246
+ }
247
+ const { tokens, clientInfo, ...metadata } = entry;
248
+ return {
249
+ ...metadata,
250
+ ...isStoredOAuthTokens(tokens) ? { tokens: withHiddenOAuthTokenGeneration(tokens) } : {},
251
+ ...isStoredOAuthClientInformation(clientInfo) ? { clientInfo: withHiddenOAuthClientGeneration(clientInfo) } : {}
252
+ };
253
+ }
254
+ function findSameUrlCredentials(vault, definition, exactKey, exact) {
255
+ if (definition.command.kind !== "http") {
256
+ return { sourceKeys: [] };
257
+ }
258
+ const serverUrl = definition.command.url.toString();
259
+ const candidates = Object.entries(vault.entries).filter(([key, entry]) => key !== exactKey && isVaultEntry(entry) && entry.serverUrl === serverUrl && isLegacyOAuthRenameCandidate(definition, entry) && (entry.tokens || entry.clientInfo)).map(([key, entry]) => ({ key, entry })).toSorted((a, b) => Date.parse(b.entry.updatedAt) - Date.parse(a.entry.updatedAt));
260
+ const requiredClientId = definition.oauthClientId ?? clientIdFromEntry(exact);
261
+ if (requiredClientId) {
262
+ const tokenSource = candidates.find(({ entry }) => (entry.tokens || entry.clientInfo) && clientIdFromEntry(entry) === requiredClientId);
263
+ return {
264
+ tokens: tokenSource?.entry.tokens,
265
+ clientInfo: exact?.clientInfo ? void 0 : tokenSource?.entry.clientInfo,
266
+ sourceKeys: tokenSource ? [tokenSource.key] : []
267
+ };
268
+ }
269
+ const source = candidates.find(({ entry }) => entry.clientInfo && clientIdFromEntry(entry));
270
+ return {
271
+ tokens: source?.entry.tokens,
272
+ clientInfo: source?.entry.clientInfo,
273
+ sourceKeys: source ? [source.key] : []
274
+ };
275
+ }
276
+ function isLegacyOAuthRenameCandidate(definition, entry) {
277
+ return entry.serverName === `${definition.name}-oauth`;
278
+ }
279
+ function legacyOAuthRenameKeys(vault, definition, exactKey) {
280
+ if (definition.command.kind !== "http") {
281
+ return [];
282
+ }
283
+ const serverUrl = definition.command.url.toString();
284
+ return Object.entries(vault.entries).filter(([key, entry]) => key !== exactKey && isVaultEntry(entry) && entry.serverUrl === serverUrl && isLegacyOAuthRenameCandidate(definition, entry)).map(([key]) => key);
285
+ }
286
+ function isVaultEntry(entry) {
287
+ return Boolean(entry && typeof entry === "object" && typeof entry.serverName === "string" && typeof entry.updatedAt === "string");
288
+ }
289
+ function clientIdFromEntry(entry) {
290
+ const clientId = entry?.clientInfo?.client_id;
291
+ return typeof clientId === "string" && clientId.length > 0 ? clientId : void 0;
292
+ }
293
+ async function saveVaultEntry(definition, patch) {
294
+ await withFileLock(getOAuthVaultPath(), async () => {
295
+ const vault = await readVault();
296
+ const key = vaultKeyForDefinition(definition);
297
+ const existing = isVaultEntry(vault.entries[key]) ? vault.entries[key] : void 0;
298
+ const fallback = findSameUrlCredentials(vault, definition, key, existing);
299
+ const current = existing ?? {
300
+ serverName: definition.name,
301
+ serverUrl: definition.command.kind === "http" ? definition.command.url.toString() : void 0,
302
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
303
+ };
304
+ vault.entries[key] = {
305
+ ...current,
306
+ ...patch,
307
+ ...patch.tokens ? { tokens: withOAuthTokenGeneration(patch.tokens) } : {},
308
+ clientInfo: (patch.clientInfo ? withOAuthClientGeneration(patch.clientInfo) : void 0) ?? current.clientInfo ?? (patch.tokens && !current.tokens ? fallback.clientInfo : void 0),
309
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
310
+ };
311
+ await writeVault(vault);
312
+ });
313
+ }
314
+ function tokensMatch(tokens, expected) {
315
+ return expected !== void 0 && sameOAuthTokenGeneration(tokens, expected);
316
+ }
317
+ async function clearVaultTokensIfMatching(definition, expectedTokens, expectedClientInfo, tokenSnapshots, clientSnapshots) {
318
+ const key = vaultKeyForDefinition(definition);
319
+ await withFileLock(getOAuthVaultPath(), async () => {
320
+ const { vault, needsRepair } = await readVaultState();
321
+ const exact = isVaultEntry(vault.entries[key]) ? vault.entries[key] : void 0;
322
+ const fallbackKeys = findSameUrlCredentials(vault, definition, key, exact).sourceKeys;
323
+ const targetKeys = tokenSnapshots || clientSnapshots ? [.../* @__PURE__ */ new Set([...tokenSnapshots?.keys() ?? [], ...clientSnapshots?.keys() ?? []])] : [key, ...fallbackKeys];
324
+ let mutated = false;
325
+ for (const targetKey of targetKeys) {
326
+ const entry = isVaultEntry(vault.entries[targetKey]) ? vault.entries[targetKey] : void 0;
327
+ if (!entry) {
328
+ continue;
329
+ }
330
+ const updated = { ...entry };
331
+ let entryMutated = false;
332
+ const tokenSnapshot = tokenSnapshots ? tokenSnapshots.get(targetKey) : expectedTokens;
333
+ const clientSnapshot = clientSnapshots ? clientSnapshots.get(targetKey) : expectedClientInfo;
334
+ const ownTokensRejected = tokensMatch(entry.tokens, tokenSnapshot);
335
+ if (ownTokensRejected) {
336
+ delete updated.tokens;
337
+ entryMutated = true;
338
+ }
339
+ if (clientSnapshot && sameOAuthClientGeneration(updated.clientInfo, clientSnapshot)) {
340
+ delete updated.clientInfo;
341
+ entryMutated = true;
342
+ }
343
+ if (!entryMutated) {
344
+ continue;
345
+ }
346
+ updated.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
347
+ vault.entries[targetKey] = updated;
348
+ mutated = true;
349
+ }
350
+ if (mutated || needsRepair) {
351
+ await writeVault(vault);
352
+ }
353
+ });
354
+ }
355
+ async function clearVaultEntry(definition, scope) {
356
+ const key = vaultKeyForDefinition(definition);
357
+ await withFileLock(getOAuthVaultPath(), async () => {
358
+ const { vault, needsRepair } = await readVaultState();
359
+ const existing = isVaultEntry(vault.entries[key]) ? vault.entries[key] : void 0;
360
+ const fallback = findSameUrlCredentials(vault, definition, key, existing);
361
+ const inheritedKeys = scope === "all" ? legacyOAuthRenameKeys(vault, definition, key) : fallback.sourceKeys;
362
+ if (!existing && inheritedKeys.length === 0) {
363
+ if (needsRepair) {
364
+ await writeVault(vault);
365
+ }
366
+ return;
367
+ }
368
+ if (scope === "all") {
369
+ delete vault.entries[key];
370
+ } else if (existing) {
371
+ const updated = { ...existing };
372
+ if (scope === "tokens") {
373
+ delete updated.tokens;
374
+ }
375
+ if (scope === "client") {
376
+ delete updated.clientInfo;
377
+ }
378
+ if (scope === "verifier") {
379
+ delete updated.codeVerifier;
380
+ }
381
+ if (scope === "state") {
382
+ delete updated.state;
383
+ }
384
+ if (scope === "discovery") {
385
+ delete updated.discoveryState;
386
+ delete updated.authorizationServerUrl;
387
+ delete updated.resourceUrl;
388
+ }
389
+ updated.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
390
+ vault.entries[key] = updated;
391
+ }
392
+ for (const fallbackKey of inheritedKeys) {
393
+ const inherited = vault.entries[fallbackKey];
394
+ if (!inherited) {
395
+ continue;
396
+ }
397
+ if (scope === "all") {
398
+ delete vault.entries[fallbackKey];
399
+ continue;
400
+ }
401
+ const updated = { ...inherited };
402
+ if (scope === "tokens") {
403
+ delete updated.tokens;
404
+ }
405
+ if (scope === "client") {
406
+ delete updated.clientInfo;
407
+ }
408
+ updated.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
409
+ vault.entries[fallbackKey] = updated;
410
+ }
411
+ await writeVault(vault);
412
+ });
413
+ }
414
+
415
+ // node_modules/.pnpm/mcporter@0.13.8/node_modules/mcporter/dist/oauth-persistence-stores.js
416
+ import fs from "node:fs/promises";
417
+ import os from "node:os";
418
+ import path2 from "node:path";
419
+ function withStoredExpiry(tokens) {
420
+ const stored = tokens;
421
+ if (typeof stored.expires_at === "number" || typeof stored.expiresAt === "number") {
422
+ return tokens;
423
+ }
424
+ if (typeof tokens.expires_in === "number" && Number.isFinite(tokens.expires_in)) {
425
+ return {
426
+ ...tokens,
427
+ expires_at: Math.floor(Date.now() / 1e3) + tokens.expires_in
428
+ };
429
+ }
430
+ return tokens;
431
+ }
432
+ function prepareStoredTokens(tokens) {
433
+ return withStoredExpiry(withOAuthTokenGeneration(tokens));
434
+ }
435
+ var DirectoryPersistence = class {
436
+ root;
437
+ logger;
438
+ serverUrl;
439
+ skipUrlMarkerWhenMissing;
440
+ tokenPath;
441
+ clientInfoPath;
442
+ codeVerifierPath;
443
+ statePath;
444
+ serverUrlPath;
445
+ discoveryStatePath;
446
+ authorizationServerUrlPath;
447
+ resourceUrlPath;
448
+ constructor(root, logger, serverUrl, skipUrlMarkerWhenMissing = false) {
449
+ this.root = root;
450
+ this.logger = logger;
451
+ this.serverUrl = serverUrl;
452
+ this.skipUrlMarkerWhenMissing = skipUrlMarkerWhenMissing;
453
+ this.tokenPath = path2.join(root, "tokens.json");
454
+ this.clientInfoPath = path2.join(root, "client.json");
455
+ this.codeVerifierPath = path2.join(root, "code_verifier.txt");
456
+ this.statePath = path2.join(root, "state.txt");
457
+ this.serverUrlPath = path2.join(root, "server_url.txt");
458
+ this.discoveryStatePath = path2.join(root, "discovery.json");
459
+ this.authorizationServerUrlPath = path2.join(root, "authorization_server_url.txt");
460
+ this.resourceUrlPath = path2.join(root, "resource_url.txt");
461
+ }
462
+ describe() {
463
+ return this.root;
464
+ }
465
+ async ensureDir() {
466
+ await fs.mkdir(this.root, { recursive: true });
467
+ }
468
+ async reconcileServerUrl() {
469
+ if (!this.serverUrl) {
470
+ return;
471
+ }
472
+ const serverUrl = this.serverUrl;
473
+ if (this.skipUrlMarkerWhenMissing) {
474
+ try {
475
+ await fs.access(this.root);
476
+ } catch (error) {
477
+ if (error.code === "ENOENT") {
478
+ return;
479
+ }
480
+ throw error;
481
+ }
482
+ }
483
+ await this.ensureDir();
484
+ await withFileLock(this.tokenPath, async () => {
485
+ let previousUrl;
486
+ try {
487
+ previousUrl = (await fs.readFile(this.serverUrlPath, "utf8")).trim();
488
+ } catch (error) {
489
+ if (error.code !== "ENOENT") {
490
+ throw error;
491
+ }
492
+ }
493
+ if (previousUrl === serverUrl) {
494
+ return;
495
+ }
496
+ if (previousUrl !== void 0) {
497
+ await this.clearFiles("all");
498
+ }
499
+ await writeTextFileAtomic(this.serverUrlPath, serverUrl);
500
+ });
501
+ }
502
+ async readSnapshot() {
503
+ await this.reconcileServerUrl();
504
+ const [tokens, clientInfo, codeVerifier, state, discoveryState, authorizationServerUrl, resourceUrl] = await Promise.all([
505
+ this.readTokensAfterReconcile(),
506
+ this.readClientInfoAfterReconcile(),
507
+ this.readCodeVerifierAfterReconcile(),
508
+ this.readStateAfterReconcile(),
509
+ this.readDiscoveryStateAfterReconcile(),
510
+ this.readTextAfterReconcile(this.authorizationServerUrlPath),
511
+ this.readTextAfterReconcile(this.resourceUrlPath)
512
+ ]);
513
+ return { tokens, clientInfo, codeVerifier, state, discoveryState, authorizationServerUrl, resourceUrl };
514
+ }
515
+ async readTokens() {
516
+ await this.reconcileServerUrl();
517
+ return await this.readTokensAfterReconcile();
518
+ }
519
+ async readTokensAfterReconcile() {
520
+ const tokens = await this.readJsonOrUndefined(this.tokenPath);
521
+ return isStoredOAuthTokens(tokens) ? withHiddenOAuthTokenGeneration(tokens) : void 0;
522
+ }
523
+ async saveTokens(tokens) {
524
+ await this.reconcileServerUrl();
525
+ await this.ensureDir();
526
+ await withFileLock(this.tokenPath, async () => {
527
+ await writeJsonFile(this.tokenPath, prepareStoredTokens(tokens));
528
+ });
529
+ this.logger?.debug?.(`Saved tokens to ${this.tokenPath}`);
530
+ }
531
+ async clearRejectedCredentials(expectedTokens, expectedClientInfo) {
532
+ await this.reconcileServerUrl();
533
+ await withFileLock(this.tokenPath, async () => {
534
+ if (expectedTokens) {
535
+ const current = await this.readJsonOrUndefined(this.tokenPath);
536
+ if (sameOAuthTokenGeneration(current, expectedTokens)) {
537
+ await this.unlinkIfPresent(this.tokenPath);
538
+ }
539
+ }
540
+ if (expectedClientInfo) {
541
+ const currentClientInfo = await this.readJsonOrUndefined(this.clientInfoPath);
542
+ if (sameOAuthClientGeneration(currentClientInfo, expectedClientInfo)) {
543
+ await this.unlinkIfPresent(this.clientInfoPath);
544
+ }
545
+ }
546
+ });
547
+ }
548
+ async unlinkIfPresent(file) {
549
+ try {
550
+ await fs.unlink(file);
551
+ } catch (error) {
552
+ if (error.code !== "ENOENT") {
553
+ throw error;
554
+ }
555
+ }
556
+ }
557
+ async readClientInfo() {
558
+ await this.reconcileServerUrl();
559
+ return await this.readClientInfoAfterReconcile();
560
+ }
561
+ async readClientInfoAfterReconcile() {
562
+ const info = await this.readJsonOrUndefined(this.clientInfoPath);
563
+ return isStoredOAuthClientInformation(info) ? withHiddenOAuthClientGeneration(info) : void 0;
564
+ }
565
+ async saveClientInfo(info) {
566
+ await this.reconcileServerUrl();
567
+ await this.ensureDir();
568
+ await withFileLock(this.tokenPath, async () => {
569
+ await writeJsonFile(this.clientInfoPath, withOAuthClientGeneration(info));
570
+ });
571
+ }
572
+ async readCodeVerifier() {
573
+ await this.reconcileServerUrl();
574
+ return await this.readCodeVerifierAfterReconcile();
575
+ }
576
+ async readCodeVerifierAfterReconcile() {
577
+ try {
578
+ return (await fs.readFile(this.codeVerifierPath, "utf8")).trim();
579
+ } catch (error) {
580
+ if (error.code === "ENOENT") {
581
+ return void 0;
582
+ }
583
+ throw error;
584
+ }
585
+ }
586
+ async saveCodeVerifier(value) {
587
+ await this.reconcileServerUrl();
588
+ await this.ensureDir();
589
+ await writeTextFileAtomic(this.codeVerifierPath, value);
590
+ }
591
+ async readState() {
592
+ await this.reconcileServerUrl();
593
+ return await this.readStateAfterReconcile();
594
+ }
595
+ async readStateAfterReconcile() {
596
+ return readJsonFile(this.statePath);
597
+ }
598
+ // A present-but-corrupt credential cache (tokens/client) means "no usable
599
+ // credentials": degrade to re-auth instead of crashing the connection,
600
+ // mirroring VaultPersistence and the daemon/server-proxy readers. Genuine I/O
601
+ // faults still propagate (readJsonFile re-throws everything except ENOENT).
602
+ // OAuth state is intentionally excluded so its CSRF check still fails closed.
603
+ async readJsonOrUndefined(filePath) {
604
+ try {
605
+ return await readJsonFile(filePath);
606
+ } catch (error) {
607
+ if (!(error instanceof SyntaxError)) {
608
+ throw error;
609
+ }
610
+ this.logger?.debug?.(`Ignoring corrupt OAuth cache file ${filePath}: ${error.message}`);
611
+ return void 0;
612
+ }
613
+ }
614
+ async saveState(value) {
615
+ await this.reconcileServerUrl();
616
+ await this.ensureDir();
617
+ await writeJsonFile(this.statePath, value);
618
+ }
619
+ async readDiscoveryState() {
620
+ await this.reconcileServerUrl();
621
+ return this.readDiscoveryStateAfterReconcile();
622
+ }
623
+ async readDiscoveryStateAfterReconcile() {
624
+ return readJsonFile(this.discoveryStatePath);
625
+ }
626
+ async saveDiscoveryState(value) {
627
+ await this.reconcileServerUrl();
628
+ await this.ensureDir();
629
+ await writeJsonFile(this.discoveryStatePath, value);
630
+ }
631
+ async readAuthorizationServerUrl() {
632
+ await this.reconcileServerUrl();
633
+ return this.readTextAfterReconcile(this.authorizationServerUrlPath);
634
+ }
635
+ async saveAuthorizationServerUrl(value) {
636
+ await this.reconcileServerUrl();
637
+ await this.ensureDir();
638
+ await writeTextFileAtomic(this.authorizationServerUrlPath, value);
639
+ }
640
+ async readResourceUrl() {
641
+ await this.reconcileServerUrl();
642
+ return this.readTextAfterReconcile(this.resourceUrlPath);
643
+ }
644
+ async saveResourceUrl(value) {
645
+ await this.reconcileServerUrl();
646
+ await this.ensureDir();
647
+ await writeTextFileAtomic(this.resourceUrlPath, value);
648
+ }
649
+ async readTextAfterReconcile(filePath) {
650
+ try {
651
+ return (await fs.readFile(filePath, "utf8")).trim() || void 0;
652
+ } catch (error) {
653
+ if (error.code === "ENOENT")
654
+ return void 0;
655
+ throw error;
656
+ }
657
+ }
658
+ async clear(scope) {
659
+ await this.reconcileServerUrl();
660
+ await this.clearFiles(scope);
661
+ }
662
+ async clearFiles(scope) {
663
+ const files = [];
664
+ if (scope === "all" || scope === "tokens") {
665
+ files.push(this.tokenPath);
666
+ }
667
+ if (scope === "all" || scope === "client") {
668
+ files.push(this.clientInfoPath);
669
+ }
670
+ if (scope === "all" || scope === "verifier") {
671
+ files.push(this.codeVerifierPath);
672
+ }
673
+ if (scope === "all" || scope === "state") {
674
+ files.push(this.statePath);
675
+ }
676
+ if (scope === "all" || scope === "discovery") {
677
+ files.push(this.discoveryStatePath, this.authorizationServerUrlPath, this.resourceUrlPath);
678
+ }
679
+ await Promise.all(files.map((file) => this.unlinkIfPresent(file)));
680
+ }
681
+ };
682
+ var VaultPersistence = class {
683
+ definition;
684
+ tokenSnapshots;
685
+ clientSnapshots;
686
+ constructor(definition) {
687
+ this.definition = definition;
688
+ }
689
+ describe() {
690
+ return `${getOAuthVaultPath()} (vault)`;
691
+ }
692
+ async reconcileServerUrl() {
693
+ await reconcileVaultServerUrl(this.definition);
694
+ }
695
+ async readSnapshot() {
696
+ await this.reconcileServerUrl();
697
+ const recovery = await loadVaultEntryForRecovery(this.definition);
698
+ this.tokenSnapshots = recovery.tokenSnapshots;
699
+ this.clientSnapshots = recovery.clientSnapshots;
700
+ return {
701
+ tokens: recovery.entry?.tokens,
702
+ clientInfo: recovery.entry?.clientInfo,
703
+ codeVerifier: recovery.entry?.codeVerifier,
704
+ state: recovery.entry?.state,
705
+ discoveryState: recovery.entry?.discoveryState,
706
+ authorizationServerUrl: recovery.entry?.authorizationServerUrl,
707
+ resourceUrl: recovery.entry?.resourceUrl
708
+ };
709
+ }
710
+ async readTokens() {
711
+ const snapshot = await this.readSnapshot();
712
+ return snapshot.tokens;
713
+ }
714
+ async saveTokens(tokens) {
715
+ await this.reconcileServerUrl();
716
+ await saveVaultEntry(this.definition, { tokens: prepareStoredTokens(tokens) });
717
+ }
718
+ async readClientInfo() {
719
+ const snapshot = await this.readSnapshot();
720
+ return snapshot.clientInfo;
721
+ }
722
+ async saveClientInfo(info) {
723
+ await this.reconcileServerUrl();
724
+ await saveVaultEntry(this.definition, { clientInfo: info });
725
+ }
726
+ async readCodeVerifier() {
727
+ const snapshot = await this.readSnapshot();
728
+ return snapshot.codeVerifier;
729
+ }
730
+ async saveCodeVerifier(value) {
731
+ await this.reconcileServerUrl();
732
+ await saveVaultEntry(this.definition, { codeVerifier: value });
733
+ }
734
+ async readState() {
735
+ const snapshot = await this.readSnapshot();
736
+ return snapshot.state;
737
+ }
738
+ async saveState(value) {
739
+ await this.reconcileServerUrl();
740
+ await saveVaultEntry(this.definition, { state: value });
741
+ }
742
+ async readDiscoveryState() {
743
+ return (await this.readSnapshot()).discoveryState;
744
+ }
745
+ async saveDiscoveryState(value) {
746
+ await this.reconcileServerUrl();
747
+ await saveVaultEntry(this.definition, { discoveryState: value });
748
+ }
749
+ async readAuthorizationServerUrl() {
750
+ return (await this.readSnapshot()).authorizationServerUrl;
751
+ }
752
+ async saveAuthorizationServerUrl(value) {
753
+ await this.reconcileServerUrl();
754
+ await saveVaultEntry(this.definition, { authorizationServerUrl: value });
755
+ }
756
+ async readResourceUrl() {
757
+ return (await this.readSnapshot()).resourceUrl;
758
+ }
759
+ async saveResourceUrl(value) {
760
+ await this.reconcileServerUrl();
761
+ await saveVaultEntry(this.definition, { resourceUrl: value });
762
+ }
763
+ async clear(scope) {
764
+ await this.reconcileServerUrl();
765
+ await clearVaultEntry(this.definition, scope);
766
+ }
767
+ async clearRejectedCredentials(expectedTokens, expectedClientInfo) {
768
+ await this.reconcileServerUrl();
769
+ await clearVaultTokensIfMatching(this.definition, expectedTokens, expectedClientInfo, expectedTokens ? this.tokenSnapshots : void 0, expectedClientInfo ? this.clientSnapshots : void 0);
770
+ }
771
+ };
772
+ var CompositePersistence = class {
773
+ stores;
774
+ recoveryTokenSnapshots = /* @__PURE__ */ new Map();
775
+ recoveryClientSnapshots = /* @__PURE__ */ new Map();
776
+ recoveryTokenSource;
777
+ recoveryClientSource;
778
+ constructor(stores) {
779
+ this.stores = stores;
780
+ }
781
+ describe() {
782
+ return this.stores.map((store) => store.describe()).join(" + ");
783
+ }
784
+ async readSnapshot() {
785
+ const snapshots = await Promise.all(this.stores.map((store) => store.readSnapshot()));
786
+ const tokens = this.firstSnapshotValue(snapshots, "tokens");
787
+ const clientInfo = this.firstSnapshotValue(snapshots, "clientInfo");
788
+ this.recoveryTokenSnapshots.clear();
789
+ this.recoveryClientSnapshots.clear();
790
+ for (const [index, snapshot] of snapshots.entries()) {
791
+ const store = this.stores[index];
792
+ this.recoveryTokenSnapshots.set(store, snapshot.tokens);
793
+ this.recoveryClientSnapshots.set(store, snapshot.clientInfo);
794
+ }
795
+ this.recoveryTokenSource = tokens.source;
796
+ this.recoveryClientSource = clientInfo.source;
797
+ return {
798
+ tokens: tokens.value,
799
+ clientInfo: clientInfo.value,
800
+ codeVerifier: this.firstSnapshotValue(snapshots, "codeVerifier").value,
801
+ state: this.firstSnapshotValue(snapshots, "state").value,
802
+ discoveryState: this.firstSnapshotValue(snapshots, "discoveryState").value,
803
+ authorizationServerUrl: this.firstSnapshotValue(snapshots, "authorizationServerUrl").value,
804
+ resourceUrl: this.firstSnapshotValue(snapshots, "resourceUrl").value
805
+ };
806
+ }
807
+ firstSnapshotValue(snapshots, field) {
808
+ for (const [index, snapshot] of snapshots.entries()) {
809
+ if (snapshot[field] !== void 0) {
810
+ return { value: snapshot[field], source: this.stores[index] };
811
+ }
812
+ }
813
+ return { value: void 0, source: void 0 };
814
+ }
815
+ async readTokens() {
816
+ const result = await this.readRecoveryValues((store) => store.readTokens(), this.recoveryTokenSnapshots);
817
+ this.recoveryTokenSource = result.source;
818
+ return result.value;
819
+ }
820
+ async readTokensPerStore() {
821
+ const perStore = await Promise.all(this.stores.map((store) => store.readTokens()));
822
+ return perStore.filter((tokens) => tokens !== void 0);
823
+ }
824
+ async saveTokens(tokens) {
825
+ const stored = prepareStoredTokens(tokens);
826
+ await Promise.all(this.stores.map((store) => store.saveTokens(stored)));
827
+ }
828
+ async clearRejectedCredentials(expectedTokens, expectedClientInfo) {
829
+ await Promise.all(this.stores.map((store) => {
830
+ const storedTokenSnapshot = expectedTokens ? this.recoveryTokenSnapshots.get(store) : void 0;
831
+ const tokenSnapshot = expectedTokens && storedTokenSnapshot && (store === this.recoveryTokenSource || sameOAuthTokenValue(storedTokenSnapshot, expectedTokens)) ? storedTokenSnapshot : void 0;
832
+ const storedClientSnapshot = expectedClientInfo ? this.recoveryClientSnapshots.get(store) : void 0;
833
+ const clientSnapshot = expectedClientInfo && storedClientSnapshot && (store === this.recoveryClientSource || sameOAuthClientValue(storedClientSnapshot, expectedClientInfo)) ? storedClientSnapshot : void 0;
834
+ return tokenSnapshot || clientSnapshot ? store.clearRejectedCredentials(tokenSnapshot, clientSnapshot) : Promise.resolve();
835
+ }));
836
+ }
837
+ async readClientInfo() {
838
+ const result = await this.readRecoveryValues((store) => store.readClientInfo(), this.recoveryClientSnapshots);
839
+ this.recoveryClientSource = result.source;
840
+ return result.value;
841
+ }
842
+ async readRecoveryValues(read, snapshots) {
843
+ const results = await Promise.allSettled(this.stores.map((store) => read(store)));
844
+ snapshots.clear();
845
+ let value;
846
+ let source;
847
+ for (const [index, result] of results.entries()) {
848
+ const store = this.stores[index];
849
+ if (result.status === "rejected") {
850
+ if (!source) {
851
+ throw result.reason;
852
+ }
853
+ continue;
854
+ }
855
+ snapshots.set(store, result.value);
856
+ if (!source && result.value !== void 0) {
857
+ source = store;
858
+ value = result.value;
859
+ }
860
+ }
861
+ return { value, source };
862
+ }
863
+ async saveClientInfo(info) {
864
+ const stored = withOAuthClientGeneration(info);
865
+ await Promise.all(this.stores.map((store) => store.saveClientInfo(stored)));
866
+ }
867
+ async readCodeVerifier() {
868
+ for (const store of this.stores) {
869
+ const result = await store.readCodeVerifier();
870
+ if (result) {
871
+ return result;
872
+ }
873
+ }
874
+ return void 0;
875
+ }
876
+ async saveCodeVerifier(value) {
877
+ await Promise.all(this.stores.map((store) => store.saveCodeVerifier(value)));
878
+ }
879
+ async readState() {
880
+ for (const store of this.stores) {
881
+ const result = await store.readState();
882
+ if (result) {
883
+ return result;
884
+ }
885
+ }
886
+ return void 0;
887
+ }
888
+ async saveState(value) {
889
+ await Promise.all(this.stores.map((store) => store.saveState(value)));
890
+ }
891
+ async readDiscoveryState() {
892
+ return this.readFirst((store) => store.readDiscoveryState());
893
+ }
894
+ async saveDiscoveryState(value) {
895
+ await Promise.all(this.stores.map((store) => store.saveDiscoveryState(value)));
896
+ }
897
+ async readAuthorizationServerUrl() {
898
+ return this.readFirst((store) => store.readAuthorizationServerUrl());
899
+ }
900
+ async saveAuthorizationServerUrl(value) {
901
+ await Promise.all(this.stores.map((store) => store.saveAuthorizationServerUrl(value)));
902
+ }
903
+ async readResourceUrl() {
904
+ return this.readFirst((store) => store.readResourceUrl());
905
+ }
906
+ async saveResourceUrl(value) {
907
+ await Promise.all(this.stores.map((store) => store.saveResourceUrl(value)));
908
+ }
909
+ async readFirst(read) {
910
+ for (const store of this.stores) {
911
+ const value = await read(store);
912
+ if (value !== void 0)
913
+ return value;
914
+ }
915
+ return void 0;
916
+ }
917
+ async clear(scope) {
918
+ await Promise.all(this.stores.map((store) => store.clear(scope)));
919
+ }
920
+ };
921
+ async function createOAuthPersistenceStores(definition, logger) {
922
+ const vault = new VaultPersistence(definition);
923
+ const stores = [vault];
924
+ const serverUrl = definition.command.kind === "http" ? definition.command.url.toString() : void 0;
925
+ if (definition.tokenCacheDir) {
926
+ stores.unshift(new DirectoryPersistence(definition.tokenCacheDir, logger, serverUrl));
927
+ }
928
+ const legacyDir = path2.join(legacyMcporterDir(), definition.name);
929
+ if (!definition.tokenCacheDir) {
930
+ const legacy = new DirectoryPersistence(legacyDir, logger, serverUrl, true);
931
+ const snapshot = await legacy.readSnapshot();
932
+ if (snapshot.tokens || snapshot.clientInfo || snapshot.codeVerifier || snapshot.state || snapshot.discoveryState || snapshot.authorizationServerUrl || snapshot.resourceUrl) {
933
+ if (snapshot.tokens) {
934
+ await vault.saveTokens(snapshot.tokens);
935
+ }
936
+ if (snapshot.clientInfo) {
937
+ await vault.saveClientInfo(snapshot.clientInfo);
938
+ }
939
+ if (snapshot.codeVerifier) {
940
+ await vault.saveCodeVerifier(snapshot.codeVerifier);
941
+ }
942
+ if (snapshot.state) {
943
+ await vault.saveState(snapshot.state);
944
+ }
945
+ if (snapshot.discoveryState) {
946
+ await vault.saveDiscoveryState(snapshot.discoveryState);
947
+ }
948
+ if (snapshot.authorizationServerUrl) {
949
+ await vault.saveAuthorizationServerUrl(snapshot.authorizationServerUrl);
950
+ }
951
+ if (snapshot.resourceUrl) {
952
+ await vault.saveResourceUrl(snapshot.resourceUrl);
953
+ }
954
+ logger?.info?.(`Migrated legacy OAuth cache for '${definition.name}' into vault.`);
955
+ }
956
+ }
957
+ return stores.length === 1 ? vault : new CompositePersistence(stores);
958
+ }
959
+ async function clearLegacyOAuthArtifacts(definition, logger, scope) {
960
+ const legacyDir = path2.join(legacyMcporterDir(), definition.name);
961
+ if (!definition.tokenCacheDir || legacyDir !== definition.tokenCacheDir) {
962
+ const legacy = new DirectoryPersistence(legacyDir, logger);
963
+ await legacy.clear(scope);
964
+ }
965
+ const legacyFiles = [];
966
+ if (definition.name.toLowerCase() === "gmail") {
967
+ legacyFiles.push(path2.join(os.homedir(), ".gmail-mcp", "credentials.json"));
968
+ }
969
+ await Promise.all(legacyFiles.map(async (file) => {
970
+ try {
971
+ await fs.unlink(file);
972
+ logger?.info?.(`Cleared legacy OAuth cache file ${file}`);
973
+ } catch (error) {
974
+ if (error.code !== "ENOENT") {
975
+ throw error;
976
+ }
977
+ }
978
+ }));
979
+ }
980
+
981
+ export {
982
+ sameOAuthTokenGeneration,
983
+ getOAuthVaultPath,
984
+ vaultCredentialKeys,
985
+ saveVaultEntry,
986
+ clearVaultEntry,
987
+ prepareStoredTokens,
988
+ createOAuthPersistenceStores,
989
+ clearLegacyOAuthArtifacts
990
+ };