@sentry/junior 0.3.0 → 0.4.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.
@@ -12,7 +12,7 @@ import {
12
12
  import { after } from "next/server";
13
13
  import * as Sentry from "@sentry/nextjs";
14
14
  async function loadBot() {
15
- const { bot } = await import("./bot-JSIREVQD.js");
15
+ const { bot } = await import("./bot-Y6A47LEZ.js");
16
16
  return bot;
17
17
  }
18
18
  async function POST(request, context) {
@@ -129,9 +129,9 @@ function listTopLevelPackages(nodeModulesDir) {
129
129
  }
130
130
 
131
131
  // src/chat/plugins/package-discovery.ts
132
- import { createRequire } from "module";
132
+ import { readFileSync, readdirSync as readdirSync2 } from "fs";
133
133
  import path2 from "path";
134
- var require2 = createRequire(import.meta.url);
134
+ import { parse as parseYaml } from "yaml";
135
135
  function normalizeForGlob(targetPath) {
136
136
  return targetPath.split(path2.sep).join("/");
137
137
  }
@@ -147,37 +147,39 @@ function uniqueStringsInOrder(values) {
147
147
  }
148
148
  return resolved;
149
149
  }
150
- function pathWithinCwd(cwd, targetPath) {
150
+ function pathForTracingInclude(cwd, targetPath) {
151
151
  const relative = path2.relative(cwd, targetPath);
152
- if (!relative || relative.startsWith("..") || path2.isAbsolute(relative)) {
152
+ if (!relative || path2.isAbsolute(relative)) {
153
153
  return null;
154
154
  }
155
- return `./${normalizeForGlob(relative)}`;
155
+ const normalized = normalizeForGlob(relative);
156
+ return normalized.startsWith(".") ? normalized : `./${normalized}`;
156
157
  }
157
158
  function parseRuntimeConfiguredPackageNames(value) {
158
159
  if (!Array.isArray(value)) {
159
160
  return null;
160
161
  }
161
- const parsed = value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
162
+ const parsed = value.filter(
163
+ (entry) => typeof entry === "string" && entry.trim().length > 0
164
+ );
162
165
  return uniqueStringsInOrder(parsed.map((entry) => entry.trim()));
163
166
  }
164
167
  function readNextRuntimeConfiguredPackageNames() {
168
+ const raw = process.env.JUNIOR_PLUGIN_PACKAGES;
169
+ if (raw === void 0) {
170
+ return null;
171
+ }
165
172
  try {
166
- const nextConfigModule = require2("next/config");
167
- const getConfig = nextConfigModule.default;
168
- if (typeof getConfig !== "function") {
169
- return null;
170
- }
171
- const runtimeConfig = getConfig();
172
- return parseRuntimeConfiguredPackageNames(runtimeConfig?.serverRuntimeConfig?.juniorPluginPackages) ?? [];
173
+ return parseRuntimeConfiguredPackageNames(JSON.parse(raw)) ?? [];
173
174
  } catch {
174
- return null;
175
+ return [];
175
176
  }
176
177
  }
177
- function findContainingNodeModulesDir(targetPath) {
178
- let current = path2.resolve(targetPath);
178
+ function findWorkspaceRoot(cwd) {
179
+ let current = path2.resolve(cwd);
179
180
  while (true) {
180
- if (path2.basename(current) === "node_modules") {
181
+ const candidate = path2.join(current, "pnpm-workspace.yaml");
182
+ if (isFile(candidate)) {
181
183
  return current;
182
184
  }
183
185
  const parent = path2.dirname(current);
@@ -187,6 +189,92 @@ function findContainingNodeModulesDir(targetPath) {
187
189
  current = parent;
188
190
  }
189
191
  }
192
+ function listWorkspacePackageDirs(cwd) {
193
+ const workspaceRoot = findWorkspaceRoot(cwd);
194
+ if (!workspaceRoot) {
195
+ return [];
196
+ }
197
+ let packagePatterns = [];
198
+ try {
199
+ const raw = readFileSync(
200
+ path2.join(workspaceRoot, "pnpm-workspace.yaml"),
201
+ "utf8"
202
+ );
203
+ const parsed = parseYaml(raw);
204
+ packagePatterns = Array.isArray(parsed.packages) ? parsed.packages.filter(
205
+ (entry) => typeof entry === "string" && entry.trim().length > 0
206
+ ) : [];
207
+ } catch {
208
+ return [];
209
+ }
210
+ const discovered = [];
211
+ const seen = /* @__PURE__ */ new Set();
212
+ const addDir = (candidate) => {
213
+ const normalized = path2.resolve(candidate);
214
+ if (seen.has(normalized) || !isDirectory(normalized)) {
215
+ return;
216
+ }
217
+ seen.add(normalized);
218
+ discovered.push(normalized);
219
+ };
220
+ for (const pattern of packagePatterns) {
221
+ const trimmed = pattern.trim();
222
+ if (!trimmed) {
223
+ continue;
224
+ }
225
+ if (trimmed.endsWith("/*")) {
226
+ const baseDir = path2.join(workspaceRoot, trimmed.slice(0, -2));
227
+ if (!isDirectory(baseDir)) {
228
+ continue;
229
+ }
230
+ for (const entry of readdirSync2(baseDir)) {
231
+ addDir(path2.join(baseDir, entry));
232
+ }
233
+ continue;
234
+ }
235
+ addDir(path2.join(workspaceRoot, trimmed));
236
+ }
237
+ return discovered;
238
+ }
239
+ function readPluginPackageFlags(dir) {
240
+ const hasRootPluginManifest = isFile(path2.join(dir, "plugin.yaml"));
241
+ const hasPluginsDir = isDirectory(path2.join(dir, "plugins"));
242
+ const hasSkillsDir = isDirectory(path2.join(dir, "skills"));
243
+ if (!hasRootPluginManifest && !hasPluginsDir && !hasSkillsDir) {
244
+ return null;
245
+ }
246
+ return {
247
+ hasRootPluginManifest,
248
+ hasPluginsDir,
249
+ hasSkillsDir
250
+ };
251
+ }
252
+ function discoverWorkspacePluginPackageDirs(cwd, packageNames) {
253
+ if (packageNames !== null) {
254
+ return [];
255
+ }
256
+ return listWorkspacePackageDirs(cwd).filter(
257
+ (candidate) => readPluginPackageFlags(candidate) !== null
258
+ );
259
+ }
260
+ function readWorkspacePackageName(dir) {
261
+ try {
262
+ const raw = readFileSync(path2.join(dir, "package.json"), "utf8");
263
+ const name = JSON.parse(raw).name;
264
+ return typeof name === "string" && name.trim().length > 0 ? name : null;
265
+ } catch {
266
+ return null;
267
+ }
268
+ }
269
+ function resolveWorkspacePackageDirFromName(cwd, packageName) {
270
+ for (const candidate of listWorkspacePackageDirs(cwd)) {
271
+ if (readWorkspacePackageName(candidate) !== packageName) {
272
+ continue;
273
+ }
274
+ return candidate;
275
+ }
276
+ return null;
277
+ }
190
278
  function resolvePackageDirFromName(packageName, candidateNodeModulesDirs) {
191
279
  for (const nodeModulesDir of candidateNodeModulesDirs) {
192
280
  const packageDir = path2.join(nodeModulesDir, ...packageName.split("/"));
@@ -197,48 +285,36 @@ function resolvePackageDirFromName(packageName, candidateNodeModulesDirs) {
197
285
  };
198
286
  }
199
287
  }
200
- try {
201
- const packageJsonPath = require2.resolve(`${packageName}/package.json`);
202
- const dir = path2.dirname(packageJsonPath);
203
- const nodeModulesDir = findContainingNodeModulesDir(dir);
204
- if (!nodeModulesDir) {
205
- return null;
206
- }
207
- return {
208
- dir: path2.resolve(dir),
209
- nodeModulesDir: path2.resolve(nodeModulesDir)
210
- };
211
- } catch {
212
- return null;
213
- }
288
+ return null;
214
289
  }
215
- function discoverDeclaredPackages(packageNames, candidateNodeModulesDirs) {
290
+ function discoverDeclaredPackages(cwd, packageNames, candidateNodeModulesDirs) {
216
291
  const discovered = [];
217
292
  const seenPackageNames = /* @__PURE__ */ new Set();
218
293
  const seenPackageDirs = /* @__PURE__ */ new Set();
219
294
  for (const packageName of packageNames) {
220
- const resolved = resolvePackageDirFromName(packageName, candidateNodeModulesDirs);
221
- if (!resolved) {
295
+ const resolved = resolvePackageDirFromName(
296
+ packageName,
297
+ candidateNodeModulesDirs
298
+ );
299
+ const workspaceDir = resolved ? null : resolveWorkspacePackageDirFromName(cwd, packageName);
300
+ if (!resolved && !workspaceDir) {
222
301
  continue;
223
302
  }
224
- if (seenPackageNames.has(packageName) || seenPackageDirs.has(resolved.dir)) {
303
+ const packageDir = resolved?.dir ?? workspaceDir;
304
+ if (seenPackageNames.has(packageName) || seenPackageDirs.has(packageDir)) {
225
305
  continue;
226
306
  }
227
- const hasRootPluginManifest = isFile(path2.join(resolved.dir, "plugin.yaml"));
228
- const hasPluginsDir = isDirectory(path2.join(resolved.dir, "plugins"));
229
- const hasSkillsDir = isDirectory(path2.join(resolved.dir, "skills"));
230
- if (!hasRootPluginManifest && !hasPluginsDir && !hasSkillsDir) {
307
+ const pluginFlags = readPluginPackageFlags(packageDir);
308
+ if (!pluginFlags) {
231
309
  continue;
232
310
  }
233
311
  seenPackageNames.add(packageName);
234
- seenPackageDirs.add(resolved.dir);
312
+ seenPackageDirs.add(packageDir);
235
313
  discovered.push({
236
314
  name: packageName,
237
- dir: resolved.dir,
238
- nodeModulesDir: resolved.nodeModulesDir,
239
- hasRootPluginManifest,
240
- hasPluginsDir,
241
- hasSkillsDir
315
+ dir: packageDir,
316
+ nodeModulesDir: resolved?.nodeModulesDir ?? null,
317
+ ...pluginFlags
242
318
  });
243
319
  }
244
320
  return discovered;
@@ -247,7 +323,11 @@ function discoverInstalledJuniorContentPackages(cwd = process.cwd(), nodeModules
247
323
  const resolvedCwd = path2.resolve(cwd);
248
324
  const candidateNodeModulesDirs = nodeModulesDirs ?? discoverNodeModulesDirs(resolvedCwd);
249
325
  const configuredPackageNames = packageNames ?? readNextRuntimeConfiguredPackageNames();
250
- const declaredPackages = discoverDeclaredPackages(configuredPackageNames ?? [], candidateNodeModulesDirs);
326
+ const declaredPackages = discoverDeclaredPackages(
327
+ resolvedCwd,
328
+ configuredPackageNames ?? [],
329
+ candidateNodeModulesDirs
330
+ );
251
331
  const useFallbackScan = configuredPackageNames === null;
252
332
  const discovered = [...declaredPackages];
253
333
  const seenPackageNames = /* @__PURE__ */ new Set();
@@ -267,7 +347,9 @@ function discoverInstalledJuniorContentPackages(cwd = process.cwd(), nodeModules
267
347
  }
268
348
  seenPackageNames.add(pkg.name);
269
349
  seenPackageDirs.add(resolvedDir);
270
- const hasRootPluginManifest = isFile(path2.join(resolvedDir, "plugin.yaml"));
350
+ const hasRootPluginManifest = isFile(
351
+ path2.join(resolvedDir, "plugin.yaml")
352
+ );
271
353
  const hasPluginsDir = isDirectory(path2.join(resolvedDir, "plugins"));
272
354
  const hasSkillsDir = isDirectory(path2.join(resolvedDir, "skills"));
273
355
  if (!hasRootPluginManifest && !hasPluginsDir && !hasSkillsDir) {
@@ -287,33 +369,68 @@ function discoverInstalledJuniorContentPackages(cwd = process.cwd(), nodeModules
287
369
  }
288
370
  function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
289
371
  const resolvedCwd = path2.resolve(cwd);
290
- const discoveredPackages = discoverInstalledJuniorContentPackages(resolvedCwd, options?.nodeModulesDirs, options?.packageNames);
372
+ const configuredPackageNames = options?.packageNames ?? readNextRuntimeConfiguredPackageNames();
373
+ const discoveredPackages = discoverInstalledJuniorContentPackages(
374
+ resolvedCwd,
375
+ options?.nodeModulesDirs,
376
+ configuredPackageNames
377
+ );
378
+ const workspacePluginDirs = discoverWorkspacePluginPackageDirs(
379
+ resolvedCwd,
380
+ configuredPackageNames
381
+ );
291
382
  const manifestRoots = [];
292
383
  const skillRoots = [];
293
384
  const tracingIncludes = [];
294
385
  for (const pkg of discoveredPackages) {
295
- const packagePathFromNodeModules = pathWithinCwd(resolvedCwd, path2.join(pkg.nodeModulesDir, ...pkg.name.split("/")));
386
+ const tracingBasePath = pkg.nodeModulesDir ? pathForTracingInclude(
387
+ resolvedCwd,
388
+ path2.join(pkg.nodeModulesDir, ...pkg.name.split("/"))
389
+ ) : pathForTracingInclude(resolvedCwd, pkg.dir);
296
390
  if (pkg.hasRootPluginManifest) {
297
391
  manifestRoots.push(pkg.dir);
298
- if (packagePathFromNodeModules) {
299
- tracingIncludes.push(`${packagePathFromNodeModules}/plugin.yaml`);
392
+ if (tracingBasePath) {
393
+ tracingIncludes.push(`${tracingBasePath}/plugin.yaml`);
300
394
  }
301
395
  }
302
396
  if (pkg.hasPluginsDir) {
303
397
  manifestRoots.push(path2.join(pkg.dir, "plugins"));
304
- if (packagePathFromNodeModules) {
305
- tracingIncludes.push(`${packagePathFromNodeModules}/plugins/**/*`);
398
+ if (tracingBasePath) {
399
+ tracingIncludes.push(`${tracingBasePath}/plugins/**/*`);
306
400
  }
307
401
  }
308
402
  if (pkg.hasSkillsDir) {
309
403
  skillRoots.push(path2.join(pkg.dir, "skills"));
310
- if (packagePathFromNodeModules) {
311
- tracingIncludes.push(`${packagePathFromNodeModules}/skills/**/*`);
404
+ if (tracingBasePath) {
405
+ tracingIncludes.push(`${tracingBasePath}/skills/**/*`);
406
+ }
407
+ }
408
+ }
409
+ for (const pluginDir of workspacePluginDirs) {
410
+ const tracingBasePath = pathForTracingInclude(resolvedCwd, pluginDir);
411
+ if (isFile(path2.join(pluginDir, "plugin.yaml"))) {
412
+ manifestRoots.push(pluginDir);
413
+ if (tracingBasePath) {
414
+ tracingIncludes.push(`${tracingBasePath}/plugin.yaml`);
415
+ }
416
+ }
417
+ if (isDirectory(path2.join(pluginDir, "plugins"))) {
418
+ manifestRoots.push(path2.join(pluginDir, "plugins"));
419
+ if (tracingBasePath) {
420
+ tracingIncludes.push(`${tracingBasePath}/plugins/**/*`);
421
+ }
422
+ }
423
+ if (isDirectory(path2.join(pluginDir, "skills"))) {
424
+ skillRoots.push(path2.join(pluginDir, "skills"));
425
+ if (tracingBasePath) {
426
+ tracingIncludes.push(`${tracingBasePath}/skills/**/*`);
312
427
  }
313
428
  }
314
429
  }
315
430
  return {
316
- packageNames: uniqueStringsInOrder(discoveredPackages.map((pkg) => pkg.name)),
431
+ packageNames: uniqueStringsInOrder(
432
+ discoveredPackages.map((pkg) => pkg.name)
433
+ ),
317
434
  manifestRoots: uniqueStringsInOrder(manifestRoots),
318
435
  skillRoots: uniqueStringsInOrder(skillRoots),
319
436
  tracingIncludes: uniqueStringsInOrder(tracingIncludes)
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  disconnectStateAdapter,
3
3
  resolveRuntimeDependencySnapshot
4
- } from "../chunk-DPTR2FNH.js";
4
+ } from "../chunk-OZFXD5IG.js";
5
5
  import "../chunk-PY4AI2GZ.js";
6
- import "../chunk-SP6LV35L.js";
6
+ import "../chunk-Z5E25LRN.js";
7
7
 
8
8
  // src/cli/snapshot-warmup.ts
9
9
  var DEFAULT_RUNTIME = "node22";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  POST
3
- } from "../chunk-4RFOJSJL.js";
4
- import "../chunk-L745IWNK.js";
5
- import "../chunk-DPTR2FNH.js";
3
+ } from "../chunk-DGKNXMK4.js";
4
+ import "../chunk-RFUE5VBK.js";
5
+ import "../chunk-OZFXD5IG.js";
6
6
  import "../chunk-PY4AI2GZ.js";
7
- import "../chunk-SP6LV35L.js";
7
+ import "../chunk-Z5E25LRN.js";
8
8
  export {
9
9
  POST
10
10
  };
@@ -1,31 +1,34 @@
1
1
  import {
2
2
  POST as POST2
3
- } from "../chunk-RTQMRGZD.js";
3
+ } from "../chunk-TEQ3UIS7.js";
4
4
  import {
5
5
  POST
6
- } from "../chunk-4RFOJSJL.js";
6
+ } from "../chunk-DGKNXMK4.js";
7
7
  import {
8
8
  escapeXml,
9
+ formatProviderLabel,
9
10
  generateAssistantReply,
10
- getOAuthProviderConfig,
11
11
  getSlackClient,
12
12
  getUserTokenStore,
13
13
  publishAppHomeView,
14
14
  resolveBaseUrl,
15
15
  truncateStatusText
16
- } from "../chunk-L745IWNK.js";
16
+ } from "../chunk-RFUE5VBK.js";
17
17
  import {
18
18
  GET
19
19
  } from "../chunk-4RBEYCOG.js";
20
20
  import {
21
21
  botConfig,
22
- getStateAdapter
23
- } from "../chunk-DPTR2FNH.js";
22
+ buildOAuthTokenRequest,
23
+ getPluginOAuthConfig,
24
+ getStateAdapter,
25
+ parseOAuthTokenResponse
26
+ } from "../chunk-OZFXD5IG.js";
24
27
  import {
25
28
  logException,
26
29
  logInfo
27
30
  } from "../chunk-PY4AI2GZ.js";
28
- import "../chunk-SP6LV35L.js";
31
+ import "../chunk-Z5E25LRN.js";
29
32
 
30
33
  // src/handlers/oauth-callback.ts
31
34
  import { after } from "next/server";
@@ -50,13 +53,21 @@ function htmlErrorResponse(title, message, status) {
50
53
  }
51
54
  async function postSlackMessage(channelId, threadTs, text) {
52
55
  try {
53
- await getSlackClient().chat.postMessage({ channel: channelId, thread_ts: threadTs, text });
56
+ await getSlackClient().chat.postMessage({
57
+ channel: channelId,
58
+ thread_ts: threadTs,
59
+ text
60
+ });
54
61
  } catch {
55
62
  }
56
63
  }
57
64
  async function setAssistantStatus(channelId, threadTs, status) {
58
65
  try {
59
- await getSlackClient().assistant.threads.setStatus({ channel_id: channelId, thread_ts: threadTs, status });
66
+ await getSlackClient().assistant.threads.setStatus({
67
+ channel_id: channelId,
68
+ thread_ts: threadTs,
69
+ status
70
+ });
60
71
  } catch {
61
72
  }
62
73
  }
@@ -95,9 +106,12 @@ function createDebouncedStatusPoster(channelId, threadTs) {
95
106
  }
96
107
  pendingStatus = truncated;
97
108
  if (!pendingTimer) {
98
- pendingTimer = setTimeout(() => {
99
- void flush();
100
- }, Math.max(1, STATUS_DEBOUNCE_MS - elapsed));
109
+ pendingTimer = setTimeout(
110
+ () => {
111
+ void flush();
112
+ },
113
+ Math.max(1, STATUS_DEBOUNCE_MS - elapsed)
114
+ );
101
115
  }
102
116
  };
103
117
  post.stop = () => {
@@ -138,13 +152,16 @@ function createReadOnlyConfigService(values) {
138
152
  }
139
153
  async function resumePendingMessage(stored) {
140
154
  if (!stored.pendingMessage || !stored.channelId || !stored.threadTs) return;
141
- const providerLabel = stored.provider.charAt(0).toUpperCase() + stored.provider.slice(1);
155
+ const providerLabel = formatProviderLabel(stored.provider);
142
156
  await postSlackMessage(
143
157
  stored.channelId,
144
158
  stored.threadTs,
145
159
  `Your ${providerLabel} account is now connected. Processing your request...`
146
160
  );
147
- const postStatus = createDebouncedStatusPoster(stored.channelId, stored.threadTs);
161
+ const postStatus = createDebouncedStatusPoster(
162
+ stored.channelId,
163
+ stored.threadTs
164
+ );
148
165
  await setAssistantStatus(stored.channelId, stored.threadTs, "Thinking...");
149
166
  try {
150
167
  const reply = await generateAssistantReply(stored.pendingMessage, {
@@ -191,11 +208,15 @@ async function resumePendingMessage(stored) {
191
208
  }
192
209
  async function GET2(request, context) {
193
210
  const { provider } = await context.params;
194
- const providerConfig = getOAuthProviderConfig(provider);
211
+ const providerConfig = getPluginOAuthConfig(provider);
195
212
  if (!providerConfig) {
196
- return htmlErrorResponse("Unknown provider", "The OAuth provider in this link is not recognized.", 404);
213
+ return htmlErrorResponse(
214
+ "Unknown provider",
215
+ "The OAuth provider in this link is not recognized.",
216
+ 404
217
+ );
197
218
  }
198
- const providerLabel = provider.charAt(0).toUpperCase() + provider.slice(1);
219
+ const providerLabel = formatProviderLabel(provider);
199
220
  const url = new URL(request.url);
200
221
  const errorParam = url.searchParams.get("error");
201
222
  const code = url.searchParams.get("code");
@@ -219,7 +240,11 @@ async function GET2(request, context) {
219
240
  );
220
241
  }
221
242
  if (!code || !state) {
222
- return htmlErrorResponse("Invalid request", "This authorization link is missing required parameters.", 400);
243
+ return htmlErrorResponse(
244
+ "Invalid request",
245
+ "This authorization link is missing required parameters.",
246
+ 400
247
+ );
223
248
  }
224
249
  const stateAdapter = getStateAdapter();
225
250
  const stateKey = `oauth-state:${state}`;
@@ -232,51 +257,76 @@ async function GET2(request, context) {
232
257
  );
233
258
  }
234
259
  if (stored.provider !== provider) {
235
- return htmlErrorResponse("Provider mismatch", "This authorization link does not match the expected provider.", 400);
260
+ return htmlErrorResponse(
261
+ "Provider mismatch",
262
+ "This authorization link does not match the expected provider.",
263
+ 400
264
+ );
236
265
  }
237
266
  await stateAdapter.delete(stateKey);
238
267
  const clientId = process.env[providerConfig.clientIdEnv]?.trim();
239
268
  const clientSecret = process.env[providerConfig.clientSecretEnv]?.trim();
240
269
  if (!clientId || !clientSecret) {
241
- return htmlErrorResponse("Configuration error", "OAuth client credentials are not configured on the server.", 500);
270
+ return htmlErrorResponse(
271
+ "Configuration error",
272
+ "OAuth client credentials are not configured on the server.",
273
+ 500
274
+ );
242
275
  }
243
276
  const baseUrl = resolveBaseUrl();
244
277
  if (!baseUrl) {
245
- return htmlErrorResponse("Configuration error", "The server cannot determine its base URL.", 500);
278
+ return htmlErrorResponse(
279
+ "Configuration error",
280
+ "The server cannot determine its base URL.",
281
+ 500
282
+ );
246
283
  }
247
284
  const redirectUri = `${baseUrl}${providerConfig.callbackPath}`;
248
285
  let tokenResponse;
249
286
  try {
250
- tokenResponse = await fetch(providerConfig.tokenEndpoint, {
251
- method: "POST",
252
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
253
- body: new URLSearchParams({
287
+ const tokenRequest = buildOAuthTokenRequest({
288
+ clientId,
289
+ clientSecret,
290
+ payload: {
254
291
  grant_type: "authorization_code",
255
292
  code,
256
- client_id: clientId,
257
- client_secret: clientSecret,
258
293
  redirect_uri: redirectUri
259
- })
294
+ },
295
+ tokenAuthMethod: providerConfig.tokenAuthMethod,
296
+ tokenExtraHeaders: providerConfig.tokenExtraHeaders
297
+ });
298
+ tokenResponse = await fetch(providerConfig.tokenEndpoint, {
299
+ method: "POST",
300
+ headers: tokenRequest.headers,
301
+ body: tokenRequest.body
260
302
  });
261
303
  } catch {
262
- return htmlErrorResponse("Connection failed", "Failed to exchange the authorization code. Please try again.", 500);
304
+ return htmlErrorResponse(
305
+ "Connection failed",
306
+ "Failed to exchange the authorization code. Please try again.",
307
+ 500
308
+ );
263
309
  }
264
310
  if (!tokenResponse.ok) {
265
- return htmlErrorResponse("Connection failed", "The token exchange with the provider failed. Please try again.", 500);
311
+ return htmlErrorResponse(
312
+ "Connection failed",
313
+ "The token exchange with the provider failed. Please try again.",
314
+ 500
315
+ );
266
316
  }
267
317
  const tokenData = await tokenResponse.json();
268
- if (!tokenData.access_token || !tokenData.refresh_token || typeof tokenData.expires_in !== "number") {
269
- return htmlErrorResponse("Connection failed", "The provider returned an incomplete token response. Please try again.", 500);
318
+ let parsedTokenResponse;
319
+ try {
320
+ parsedTokenResponse = parseOAuthTokenResponse(tokenData);
321
+ } catch {
322
+ return htmlErrorResponse(
323
+ "Connection failed",
324
+ "The provider returned an incomplete token response. Please try again.",
325
+ 500
326
+ );
270
327
  }
271
- const accessToken = tokenData.access_token;
272
- const refreshToken = tokenData.refresh_token;
273
- const expiresAt = Date.now() + tokenData.expires_in * 1e3;
274
328
  const userTokenStore = getUserTokenStore();
275
- await userTokenStore.set(stored.userId, provider, {
276
- accessToken,
277
- refreshToken,
278
- expiresAt
279
- });
329
+ await userTokenStore.set(stored.userId, provider, parsedTokenResponse);
280
330
  after(async () => {
281
331
  try {
282
332
  await publishAppHomeView(getSlackClient(), stored.userId, userTokenStore);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  POST
3
- } from "../chunk-RTQMRGZD.js";
3
+ } from "../chunk-TEQ3UIS7.js";
4
4
  import "../chunk-PY4AI2GZ.js";
5
5
  export {
6
6
  POST