@sentry/junior 0.2.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 +8 -1
- package/dist/{bot-T73QBC4J.js → bot-Y6A47LEZ.js} +3 -2
- package/dist/{chunk-TQSDLJVE.js → chunk-DGKNXMK4.js} +2 -2
- package/dist/{chunk-QHDDCUTN.js → chunk-OZFXD5IG.js} +552 -261
- package/dist/{chunk-RXNMJQPY.js → chunk-RFUE5VBK.js} +854 -346
- package/dist/{chunk-JDBWDYGR.js → chunk-TEQ3UIS7.js} +1 -1
- package/dist/chunk-Z5E25LRN.js +445 -0
- package/dist/cli/snapshot-warmup.js +2 -1
- package/dist/handlers/queue-callback.js +4 -3
- package/dist/handlers/router.js +90 -39
- package/dist/handlers/webhooks.js +1 -1
- package/dist/next-config.d.ts +2 -2
- package/dist/next-config.js +82 -77
- package/package.json +1 -1
package/dist/handlers/router.js
CHANGED
|
@@ -1,30 +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";
|
|
31
|
+
import "../chunk-Z5E25LRN.js";
|
|
28
32
|
|
|
29
33
|
// src/handlers/oauth-callback.ts
|
|
30
34
|
import { after } from "next/server";
|
|
@@ -49,13 +53,21 @@ function htmlErrorResponse(title, message, status) {
|
|
|
49
53
|
}
|
|
50
54
|
async function postSlackMessage(channelId, threadTs, text) {
|
|
51
55
|
try {
|
|
52
|
-
await getSlackClient().chat.postMessage({
|
|
56
|
+
await getSlackClient().chat.postMessage({
|
|
57
|
+
channel: channelId,
|
|
58
|
+
thread_ts: threadTs,
|
|
59
|
+
text
|
|
60
|
+
});
|
|
53
61
|
} catch {
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
async function setAssistantStatus(channelId, threadTs, status) {
|
|
57
65
|
try {
|
|
58
|
-
await getSlackClient().assistant.threads.setStatus({
|
|
66
|
+
await getSlackClient().assistant.threads.setStatus({
|
|
67
|
+
channel_id: channelId,
|
|
68
|
+
thread_ts: threadTs,
|
|
69
|
+
status
|
|
70
|
+
});
|
|
59
71
|
} catch {
|
|
60
72
|
}
|
|
61
73
|
}
|
|
@@ -94,9 +106,12 @@ function createDebouncedStatusPoster(channelId, threadTs) {
|
|
|
94
106
|
}
|
|
95
107
|
pendingStatus = truncated;
|
|
96
108
|
if (!pendingTimer) {
|
|
97
|
-
pendingTimer = setTimeout(
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
pendingTimer = setTimeout(
|
|
110
|
+
() => {
|
|
111
|
+
void flush();
|
|
112
|
+
},
|
|
113
|
+
Math.max(1, STATUS_DEBOUNCE_MS - elapsed)
|
|
114
|
+
);
|
|
100
115
|
}
|
|
101
116
|
};
|
|
102
117
|
post.stop = () => {
|
|
@@ -137,13 +152,16 @@ function createReadOnlyConfigService(values) {
|
|
|
137
152
|
}
|
|
138
153
|
async function resumePendingMessage(stored) {
|
|
139
154
|
if (!stored.pendingMessage || !stored.channelId || !stored.threadTs) return;
|
|
140
|
-
const providerLabel =
|
|
155
|
+
const providerLabel = formatProviderLabel(stored.provider);
|
|
141
156
|
await postSlackMessage(
|
|
142
157
|
stored.channelId,
|
|
143
158
|
stored.threadTs,
|
|
144
159
|
`Your ${providerLabel} account is now connected. Processing your request...`
|
|
145
160
|
);
|
|
146
|
-
const postStatus = createDebouncedStatusPoster(
|
|
161
|
+
const postStatus = createDebouncedStatusPoster(
|
|
162
|
+
stored.channelId,
|
|
163
|
+
stored.threadTs
|
|
164
|
+
);
|
|
147
165
|
await setAssistantStatus(stored.channelId, stored.threadTs, "Thinking...");
|
|
148
166
|
try {
|
|
149
167
|
const reply = await generateAssistantReply(stored.pendingMessage, {
|
|
@@ -190,11 +208,15 @@ async function resumePendingMessage(stored) {
|
|
|
190
208
|
}
|
|
191
209
|
async function GET2(request, context) {
|
|
192
210
|
const { provider } = await context.params;
|
|
193
|
-
const providerConfig =
|
|
211
|
+
const providerConfig = getPluginOAuthConfig(provider);
|
|
194
212
|
if (!providerConfig) {
|
|
195
|
-
return htmlErrorResponse(
|
|
213
|
+
return htmlErrorResponse(
|
|
214
|
+
"Unknown provider",
|
|
215
|
+
"The OAuth provider in this link is not recognized.",
|
|
216
|
+
404
|
|
217
|
+
);
|
|
196
218
|
}
|
|
197
|
-
const providerLabel =
|
|
219
|
+
const providerLabel = formatProviderLabel(provider);
|
|
198
220
|
const url = new URL(request.url);
|
|
199
221
|
const errorParam = url.searchParams.get("error");
|
|
200
222
|
const code = url.searchParams.get("code");
|
|
@@ -218,7 +240,11 @@ async function GET2(request, context) {
|
|
|
218
240
|
);
|
|
219
241
|
}
|
|
220
242
|
if (!code || !state) {
|
|
221
|
-
return htmlErrorResponse(
|
|
243
|
+
return htmlErrorResponse(
|
|
244
|
+
"Invalid request",
|
|
245
|
+
"This authorization link is missing required parameters.",
|
|
246
|
+
400
|
|
247
|
+
);
|
|
222
248
|
}
|
|
223
249
|
const stateAdapter = getStateAdapter();
|
|
224
250
|
const stateKey = `oauth-state:${state}`;
|
|
@@ -231,51 +257,76 @@ async function GET2(request, context) {
|
|
|
231
257
|
);
|
|
232
258
|
}
|
|
233
259
|
if (stored.provider !== provider) {
|
|
234
|
-
return htmlErrorResponse(
|
|
260
|
+
return htmlErrorResponse(
|
|
261
|
+
"Provider mismatch",
|
|
262
|
+
"This authorization link does not match the expected provider.",
|
|
263
|
+
400
|
|
264
|
+
);
|
|
235
265
|
}
|
|
236
266
|
await stateAdapter.delete(stateKey);
|
|
237
267
|
const clientId = process.env[providerConfig.clientIdEnv]?.trim();
|
|
238
268
|
const clientSecret = process.env[providerConfig.clientSecretEnv]?.trim();
|
|
239
269
|
if (!clientId || !clientSecret) {
|
|
240
|
-
return htmlErrorResponse(
|
|
270
|
+
return htmlErrorResponse(
|
|
271
|
+
"Configuration error",
|
|
272
|
+
"OAuth client credentials are not configured on the server.",
|
|
273
|
+
500
|
|
274
|
+
);
|
|
241
275
|
}
|
|
242
276
|
const baseUrl = resolveBaseUrl();
|
|
243
277
|
if (!baseUrl) {
|
|
244
|
-
return htmlErrorResponse(
|
|
278
|
+
return htmlErrorResponse(
|
|
279
|
+
"Configuration error",
|
|
280
|
+
"The server cannot determine its base URL.",
|
|
281
|
+
500
|
|
282
|
+
);
|
|
245
283
|
}
|
|
246
284
|
const redirectUri = `${baseUrl}${providerConfig.callbackPath}`;
|
|
247
285
|
let tokenResponse;
|
|
248
286
|
try {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
287
|
+
const tokenRequest = buildOAuthTokenRequest({
|
|
288
|
+
clientId,
|
|
289
|
+
clientSecret,
|
|
290
|
+
payload: {
|
|
253
291
|
grant_type: "authorization_code",
|
|
254
292
|
code,
|
|
255
|
-
client_id: clientId,
|
|
256
|
-
client_secret: clientSecret,
|
|
257
293
|
redirect_uri: redirectUri
|
|
258
|
-
}
|
|
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
|
|
259
302
|
});
|
|
260
303
|
} catch {
|
|
261
|
-
return htmlErrorResponse(
|
|
304
|
+
return htmlErrorResponse(
|
|
305
|
+
"Connection failed",
|
|
306
|
+
"Failed to exchange the authorization code. Please try again.",
|
|
307
|
+
500
|
|
308
|
+
);
|
|
262
309
|
}
|
|
263
310
|
if (!tokenResponse.ok) {
|
|
264
|
-
return htmlErrorResponse(
|
|
311
|
+
return htmlErrorResponse(
|
|
312
|
+
"Connection failed",
|
|
313
|
+
"The token exchange with the provider failed. Please try again.",
|
|
314
|
+
500
|
|
315
|
+
);
|
|
265
316
|
}
|
|
266
317
|
const tokenData = await tokenResponse.json();
|
|
267
|
-
|
|
268
|
-
|
|
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
|
+
);
|
|
269
327
|
}
|
|
270
|
-
const accessToken = tokenData.access_token;
|
|
271
|
-
const refreshToken = tokenData.refresh_token;
|
|
272
|
-
const expiresAt = Date.now() + tokenData.expires_in * 1e3;
|
|
273
328
|
const userTokenStore = getUserTokenStore();
|
|
274
|
-
await userTokenStore.set(stored.userId, provider,
|
|
275
|
-
accessToken,
|
|
276
|
-
refreshToken,
|
|
277
|
-
expiresAt
|
|
278
|
-
});
|
|
329
|
+
await userTokenStore.set(stored.userId, provider, parsedTokenResponse);
|
|
279
330
|
after(async () => {
|
|
280
331
|
try {
|
|
281
332
|
await publishAppHomeView(getSlackClient(), stored.userId, userTokenStore);
|
package/dist/next-config.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ interface JuniorConfigOptions {
|
|
|
7
7
|
dataDir?: string;
|
|
8
8
|
skillsDir?: string;
|
|
9
9
|
pluginsDir?: string;
|
|
10
|
-
|
|
10
|
+
pluginPackages?: string[];
|
|
11
11
|
}
|
|
12
12
|
type NextConfigFactory = (phase: string, ctx: {
|
|
13
13
|
defaultConfig: NextConfig;
|
|
@@ -17,6 +17,6 @@ type NextConfigFactory = (phase: string, ctx: {
|
|
|
17
17
|
*
|
|
18
18
|
* Supports both object and function-style Next config exports.
|
|
19
19
|
*/
|
|
20
|
-
declare function withJunior(nextConfig?: NextConfig | NextConfigFactory
|
|
20
|
+
declare function withJunior(options?: JuniorConfigOptions, nextConfig?: NextConfig | NextConfigFactory): NextConfig | NextConfigFactory;
|
|
21
21
|
|
|
22
22
|
export { type JuniorConfigOptions, withJunior };
|
package/dist/next-config.js
CHANGED
|
@@ -1,102 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
discoverInstalledPluginPackageContent,
|
|
3
|
+
discoverNodeModulesDirs,
|
|
4
|
+
isDirectory
|
|
5
|
+
} from "./chunk-Z5E25LRN.js";
|
|
6
|
+
|
|
1
7
|
// src/next-config.ts
|
|
2
8
|
import { createRequire } from "module";
|
|
3
|
-
import { readFileSync, statSync } from "fs";
|
|
4
9
|
import path from "path";
|
|
5
10
|
var require2 = createRequire(import.meta.url);
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
return statSync(targetPath).isDirectory();
|
|
9
|
-
} catch {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
11
|
+
function unique(values) {
|
|
12
|
+
return [...new Set(values)];
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
return statSync(targetPath).isFile();
|
|
16
|
-
} catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
14
|
+
function sentryConfigured() {
|
|
15
|
+
return Boolean(process.env.NEXT_PUBLIC_SENTRY_DSN || process.env.SENTRY_DSN);
|
|
19
16
|
}
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} catch {
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
28
|
-
const dependencies = [
|
|
29
|
-
...Object.keys(rootPackageJson.dependencies ?? {}),
|
|
30
|
-
...Object.keys(rootPackageJson.optionalDependencies ?? {})
|
|
31
|
-
];
|
|
32
|
-
const tracingIncludes = [];
|
|
33
|
-
for (const dependency of dependencies) {
|
|
34
|
-
const packageDir = path.join(cwd, "node_modules", ...dependency.split("/"));
|
|
35
|
-
if (!isDirectory(packageDir)) {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
const base = `./node_modules/${dependency}`;
|
|
39
|
-
if (isFile(path.join(packageDir, "plugin.yaml"))) {
|
|
40
|
-
tracingIncludes.push(`${base}/plugin.yaml`);
|
|
41
|
-
}
|
|
42
|
-
if (isDirectory(path.join(packageDir, "plugins"))) {
|
|
43
|
-
tracingIncludes.push(`${base}/plugins/**/*`);
|
|
44
|
-
}
|
|
45
|
-
if (isDirectory(path.join(packageDir, "skills"))) {
|
|
46
|
-
tracingIncludes.push(`${base}/skills/**/*`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return [...new Set(tracingIncludes)].sort((left, right) => left.localeCompare(right));
|
|
17
|
+
function isPackageInstalled(cwd, packageName) {
|
|
18
|
+
const nodeModulesDirs = discoverNodeModulesDirs(cwd);
|
|
19
|
+
return nodeModulesDirs.some(
|
|
20
|
+
(nodeModulesDir) => isDirectory(path.join(nodeModulesDir, ...packageName.split("/")))
|
|
21
|
+
);
|
|
50
22
|
}
|
|
51
23
|
function applyJuniorConfig(nextConfig, options) {
|
|
24
|
+
const existingEnv = nextConfig?.env ?? {};
|
|
52
25
|
const dataDir = options?.dataDir ?? "./app/data";
|
|
53
26
|
const skillsDir = options?.skillsDir ?? "./app/skills";
|
|
54
27
|
const pluginsDir = options?.pluginsDir ?? "./app/plugins";
|
|
28
|
+
const configuredPluginPackages = unique(options?.pluginPackages ?? []);
|
|
29
|
+
const discoveredPlugins = discoverInstalledPluginPackageContent(
|
|
30
|
+
process.cwd(),
|
|
31
|
+
{ packageNames: configuredPluginPackages }
|
|
32
|
+
);
|
|
33
|
+
const unresolvedConfiguredPackages = configuredPluginPackages.filter(
|
|
34
|
+
(packageName) => !discoveredPlugins.packageNames.includes(packageName)
|
|
35
|
+
);
|
|
36
|
+
const invalidPluginPackages = unresolvedConfiguredPackages.filter(
|
|
37
|
+
(packageName) => isPackageInstalled(process.cwd(), packageName)
|
|
38
|
+
);
|
|
39
|
+
const missingPluginPackages = unresolvedConfiguredPackages.filter(
|
|
40
|
+
(packageName) => !invalidPluginPackages.includes(packageName)
|
|
41
|
+
);
|
|
42
|
+
if (invalidPluginPackages.length > 0) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`withJunior pluginPackages contains installed packages that are not valid Junior plugins: ${invalidPluginPackages.join(", ")}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (missingPluginPackages.length > 0) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`withJunior pluginPackages contains unresolved packages: ${missingPluginPackages.join(", ")}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
55
52
|
const defaultDataTracingIncludes = options?.dataDir ? [`${dataDir}/**/*`] : ["./app/SOUL.md", "./app/ABOUT.md"];
|
|
56
|
-
const pluginPackageTracingIncludes =
|
|
57
|
-
const tracingIncludes = Array.from(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
const pluginPackageTracingIncludes = discoveredPlugins.tracingIncludes;
|
|
54
|
+
const tracingIncludes = Array.from(
|
|
55
|
+
/* @__PURE__ */ new Set([
|
|
56
|
+
...defaultDataTracingIncludes,
|
|
57
|
+
`${skillsDir}/**/*`,
|
|
58
|
+
`${pluginsDir}/**/*`,
|
|
59
|
+
...pluginPackageTracingIncludes
|
|
60
|
+
])
|
|
61
|
+
);
|
|
63
62
|
const existingGlobalTracingIncludes = nextConfig?.outputFileTracingIncludes?.["/*"] ?? [];
|
|
64
|
-
const mergedGlobalTracingIncludes = Array.from(
|
|
65
|
-
...existingGlobalTracingIncludes,
|
|
66
|
-
|
|
67
|
-
]));
|
|
63
|
+
const mergedGlobalTracingIncludes = Array.from(
|
|
64
|
+
/* @__PURE__ */ new Set([...existingGlobalTracingIncludes, ...tracingIncludes])
|
|
65
|
+
);
|
|
68
66
|
const config = {
|
|
69
67
|
...nextConfig,
|
|
70
|
-
serverExternalPackages: Array.from(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
serverExternalPackages: Array.from(
|
|
69
|
+
/* @__PURE__ */ new Set([
|
|
70
|
+
...nextConfig?.serverExternalPackages ?? [],
|
|
71
|
+
"@vercel/queue",
|
|
72
|
+
"@vercel/sandbox",
|
|
73
|
+
"bash-tool",
|
|
74
|
+
"just-bash",
|
|
75
|
+
"@mariozechner/pi-agent-core",
|
|
76
|
+
"@mariozechner/pi-ai",
|
|
77
|
+
"@chat-adapter/slack",
|
|
78
|
+
"@slack/web-api"
|
|
79
|
+
])
|
|
80
|
+
),
|
|
80
81
|
outputFileTracingIncludes: {
|
|
81
82
|
...nextConfig?.outputFileTracingIncludes,
|
|
82
83
|
"/*": mergedGlobalTracingIncludes
|
|
84
|
+
},
|
|
85
|
+
env: {
|
|
86
|
+
...existingEnv,
|
|
87
|
+
JUNIOR_PLUGIN_PACKAGES: JSON.stringify(configuredPluginPackages)
|
|
83
88
|
}
|
|
84
89
|
};
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
return withSentryConfig(config, {
|
|
88
|
-
org: process.env.SENTRY_ORG,
|
|
89
|
-
project: process.env.SENTRY_PROJECT,
|
|
90
|
-
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
91
|
-
silent: !process.env.CI,
|
|
92
|
-
sourcemaps: {
|
|
93
|
-
disable: false
|
|
94
|
-
}
|
|
95
|
-
});
|
|
90
|
+
if (!sentryConfigured()) {
|
|
91
|
+
return config;
|
|
96
92
|
}
|
|
97
|
-
|
|
93
|
+
const { withSentryConfig } = require2("@sentry/nextjs");
|
|
94
|
+
return withSentryConfig(config, {
|
|
95
|
+
org: process.env.SENTRY_ORG,
|
|
96
|
+
project: process.env.SENTRY_PROJECT,
|
|
97
|
+
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
98
|
+
silent: !process.env.CI,
|
|
99
|
+
sourcemaps: {
|
|
100
|
+
disable: false
|
|
101
|
+
}
|
|
102
|
+
});
|
|
98
103
|
}
|
|
99
|
-
function withJunior(
|
|
104
|
+
function withJunior(options, nextConfig) {
|
|
100
105
|
if (typeof nextConfig === "function") {
|
|
101
106
|
return async (phase, ctx) => {
|
|
102
107
|
const resolved = await nextConfig(phase, ctx);
|