@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.
- package/README.md +5 -1
- package/dist/{bot-JSIREVQD.js → bot-Y6A47LEZ.js} +3 -3
- package/dist/{chunk-4RFOJSJL.js → chunk-DGKNXMK4.js} +2 -2
- package/dist/{chunk-DPTR2FNH.js → chunk-OZFXD5IG.js} +495 -130
- package/dist/{chunk-L745IWNK.js → chunk-RFUE5VBK.js} +854 -346
- package/dist/{chunk-RTQMRGZD.js → chunk-TEQ3UIS7.js} +1 -1
- package/dist/{chunk-SP6LV35L.js → chunk-Z5E25LRN.js} +173 -56
- package/dist/cli/snapshot-warmup.js +2 -2
- package/dist/handlers/queue-callback.js +4 -4
- package/dist/handlers/router.js +90 -40
- package/dist/handlers/webhooks.js +1 -1
- package/dist/next-config.js +33 -27
- package/package.json +1 -1
|
@@ -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-
|
|
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 {
|
|
132
|
+
import { readFileSync, readdirSync as readdirSync2 } from "fs";
|
|
133
133
|
import path2 from "path";
|
|
134
|
-
|
|
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
|
|
150
|
+
function pathForTracingInclude(cwd, targetPath) {
|
|
151
151
|
const relative = path2.relative(cwd, targetPath);
|
|
152
|
-
if (!relative ||
|
|
152
|
+
if (!relative || path2.isAbsolute(relative)) {
|
|
153
153
|
return null;
|
|
154
154
|
}
|
|
155
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
175
|
+
return [];
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
|
-
function
|
|
178
|
-
let current = path2.resolve(
|
|
178
|
+
function findWorkspaceRoot(cwd) {
|
|
179
|
+
let current = path2.resolve(cwd);
|
|
179
180
|
while (true) {
|
|
180
|
-
|
|
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
|
-
|
|
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(
|
|
221
|
-
|
|
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
|
-
|
|
303
|
+
const packageDir = resolved?.dir ?? workspaceDir;
|
|
304
|
+
if (seenPackageNames.has(packageName) || seenPackageDirs.has(packageDir)) {
|
|
225
305
|
continue;
|
|
226
306
|
}
|
|
227
|
-
const
|
|
228
|
-
|
|
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(
|
|
312
|
+
seenPackageDirs.add(packageDir);
|
|
235
313
|
discovered.push({
|
|
236
314
|
name: packageName,
|
|
237
|
-
dir:
|
|
238
|
-
nodeModulesDir: resolved
|
|
239
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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 (
|
|
299
|
-
tracingIncludes.push(`${
|
|
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 (
|
|
305
|
-
tracingIncludes.push(`${
|
|
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 (
|
|
311
|
-
tracingIncludes.push(`${
|
|
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(
|
|
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-
|
|
4
|
+
} from "../chunk-OZFXD5IG.js";
|
|
5
5
|
import "../chunk-PY4AI2GZ.js";
|
|
6
|
-
import "../chunk-
|
|
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-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-DGKNXMK4.js";
|
|
4
|
+
import "../chunk-RFUE5VBK.js";
|
|
5
|
+
import "../chunk-OZFXD5IG.js";
|
|
6
6
|
import "../chunk-PY4AI2GZ.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-Z5E25LRN.js";
|
|
8
8
|
export {
|
|
9
9
|
POST
|
|
10
10
|
};
|
package/dist/handlers/router.js
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
2
|
POST as POST2
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-TEQ3UIS7.js";
|
|
4
4
|
import {
|
|
5
5
|
POST
|
|
6
|
-
} from "../chunk-
|
|
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-
|
|
16
|
+
} from "../chunk-RFUE5VBK.js";
|
|
17
17
|
import {
|
|
18
18
|
GET
|
|
19
19
|
} from "../chunk-4RBEYCOG.js";
|
|
20
20
|
import {
|
|
21
21
|
botConfig,
|
|
22
|
-
|
|
23
|
-
|
|
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-
|
|
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({
|
|
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({
|
|
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
|
-
|
|
100
|
-
|
|
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 =
|
|
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(
|
|
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 =
|
|
211
|
+
const providerConfig = getPluginOAuthConfig(provider);
|
|
195
212
|
if (!providerConfig) {
|
|
196
|
-
return htmlErrorResponse(
|
|
213
|
+
return htmlErrorResponse(
|
|
214
|
+
"Unknown provider",
|
|
215
|
+
"The OAuth provider in this link is not recognized.",
|
|
216
|
+
404
|
|
217
|
+
);
|
|
197
218
|
}
|
|
198
|
-
const providerLabel =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
269
|
-
|
|
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);
|