@sentry/junior 0.1.0 → 0.2.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 +7 -56
- package/bin/junior.mjs +38 -128
- package/dist/app/layout.d.ts +3 -0
- package/dist/bot-T73QBC4J.js +16 -0
- package/dist/{chunk-OD6TOSY4.js → chunk-JDBWDYGR.js} +2 -2
- package/dist/{chunk-BBOVH5RF.js → chunk-PY4AI2GZ.js} +62 -15
- package/dist/chunk-QHDDCUTN.js +1940 -0
- package/dist/{chunk-7E56WM6K.js → chunk-RXNMJQPY.js} +8588 -6108
- package/dist/chunk-TQSDLJVE.js +272 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +105 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.js +30 -0
- package/dist/cli/snapshot-warmup.d.ts +3 -0
- package/dist/cli/snapshot-warmup.js +57 -0
- package/dist/handlers/health.d.ts +3 -0
- package/dist/handlers/queue-callback.d.ts +7 -0
- package/dist/handlers/queue-callback.js +5 -268
- package/dist/handlers/router.d.ts +18 -3
- package/dist/handlers/router.js +320 -13
- package/dist/handlers/webhooks.d.ts +13 -0
- package/dist/handlers/webhooks.js +2 -2
- package/dist/instrumentation.d.ts +6 -0
- package/dist/next-config.d.ts +8 -0
- package/dist/next-config.js +2 -0
- package/package.json +3 -8
- package/dist/bot-DLML4Z7F.js +0 -3108
- package/dist/channel-HJO33DGJ.js +0 -18
- package/dist/chunk-GDNDYMGX.js +0 -333
- package/dist/chunk-MM3YNA4F.js +0 -203
- package/dist/chunk-ZA2IDPVG.js +0 -39
- package/dist/chunk-ZBFSIN6G.js +0 -323
- package/dist/client-3GAEMIQ3.js +0 -10
- package/dist/route-XLYK6CKP.js +0 -309
package/README.md
CHANGED
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
`@sentry/junior` is a Slack bot package for Next.js apps.
|
|
4
4
|
|
|
5
|
-
If you are contributing to this monorepo, use the root docs:
|
|
6
|
-
|
|
7
|
-
- `README.md` for general usage
|
|
8
|
-
- `CONTRIBUTING.md` for development workflows
|
|
9
|
-
|
|
10
5
|
## Install
|
|
11
6
|
|
|
12
7
|
```bash
|
|
@@ -14,18 +9,7 @@ pnpm add @sentry/junior
|
|
|
14
9
|
pnpm add next react react-dom @sentry/nextjs
|
|
15
10
|
```
|
|
16
11
|
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
Add these files under `app/`:
|
|
20
|
-
|
|
21
|
-
```text
|
|
22
|
-
app/SOUL.md
|
|
23
|
-
app/ABOUT.md
|
|
24
|
-
app/skills/
|
|
25
|
-
app/plugins/ (optional)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Next.js Integration
|
|
12
|
+
## Quick usage
|
|
29
13
|
|
|
30
14
|
`app/api/[...path]/route.js`:
|
|
31
15
|
|
|
@@ -48,44 +32,11 @@ import { withJunior } from "@sentry/junior/config";
|
|
|
48
32
|
export default withJunior();
|
|
49
33
|
```
|
|
50
34
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```js
|
|
54
|
-
export { register, onRequestError } from "@sentry/junior/instrumentation";
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
If your app does not already include a root layout:
|
|
35
|
+
## Full docs
|
|
58
36
|
|
|
59
|
-
|
|
37
|
+
Canonical docs: **https://junior.sentry.dev/**
|
|
60
38
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Scaffold a New Bot
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
npx junior init my-bot
|
|
69
|
-
cd my-bot
|
|
70
|
-
pnpm install
|
|
71
|
-
pnpm dev
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Vercel Queue Trigger
|
|
75
|
-
|
|
76
|
-
Add this `vercel.json` function trigger:
|
|
77
|
-
|
|
78
|
-
```json
|
|
79
|
-
{
|
|
80
|
-
"functions": {
|
|
81
|
-
"app/api/queue/callback/route.js": {
|
|
82
|
-
"experimentalTriggers": [
|
|
83
|
-
{
|
|
84
|
-
"type": "queue/v2beta",
|
|
85
|
-
"topic": "junior-thread-message"
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
```
|
|
39
|
+
- Quickstart: https://junior.sentry.dev/start-here/quickstart/
|
|
40
|
+
- Deployment: https://junior.sentry.dev/start-here/deploy/
|
|
41
|
+
- Plugin setup: https://junior.sentry.dev/extend/plugins-overview/
|
|
42
|
+
- API reference: https://junior.sentry.dev/reference/api/
|
package/bin/junior.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import { parseArgs } from "node:util";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
|
|
7
7
|
const { positionals } = parseArgs({
|
|
8
8
|
allowPositionals: true,
|
|
@@ -11,138 +11,48 @@ const { positionals } = parseArgs({
|
|
|
11
11
|
|
|
12
12
|
const command = positionals[0];
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// app/api/queue/callback/route.js
|
|
25
|
-
const queueRouteDir = path.join(targetDir, "app", "api", "queue", "callback");
|
|
26
|
-
fs.mkdirSync(queueRouteDir, { recursive: true });
|
|
27
|
-
fs.writeFileSync(
|
|
28
|
-
path.join(queueRouteDir, "route.js"),
|
|
29
|
-
'export { POST } from "@sentry/junior/handlers/queue-callback";\n' +
|
|
30
|
-
'export const runtime = "nodejs";\n'
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
// app/layout.js
|
|
34
|
-
fs.mkdirSync(path.join(targetDir, "app"), { recursive: true });
|
|
35
|
-
fs.writeFileSync(
|
|
36
|
-
path.join(targetDir, "app", "layout.js"),
|
|
37
|
-
'export { default } from "@sentry/junior/app/layout";\n'
|
|
38
|
-
);
|
|
14
|
+
async function loadCliFunction(moduleName, exportName, unavailableMessage) {
|
|
15
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
16
|
+
const modulePath = path.join(path.dirname(currentFile), "..", "dist", "cli", `${moduleName}.js`);
|
|
17
|
+
const moduleUrl = pathToFileURL(modulePath).href;
|
|
18
|
+
const loadedModule = await import(moduleUrl);
|
|
19
|
+
if (typeof loadedModule[exportName] !== "function") {
|
|
20
|
+
throw new Error(unavailableMessage);
|
|
21
|
+
}
|
|
22
|
+
return loadedModule[exportName];
|
|
23
|
+
}
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
async function runSnapshotCreate() {
|
|
26
|
+
const runSnapshotCreateFn = await loadCliFunction(
|
|
27
|
+
"snapshot-warmup",
|
|
28
|
+
"runSnapshotCreate",
|
|
29
|
+
"Snapshot create module is unavailable; reinstall @sentry/junior and retry."
|
|
45
30
|
);
|
|
31
|
+
await runSnapshotCreateFn();
|
|
32
|
+
}
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
'export { register, onRequestError } from "@sentry/junior/instrumentation";\n'
|
|
51
|
-
);
|
|
34
|
+
async function runInit(dir) {
|
|
35
|
+
const runInitFn = await loadCliFunction("init", "runInit", "Init module is unavailable; reinstall @sentry/junior and retry.");
|
|
36
|
+
await runInitFn(dir);
|
|
52
37
|
}
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
39
|
+
async function main() {
|
|
40
|
+
const runCli = await loadCliFunction(
|
|
41
|
+
"run",
|
|
42
|
+
"runCli",
|
|
43
|
+
"CLI dispatcher module is unavailable; reinstall @sentry/junior and retry."
|
|
44
|
+
);
|
|
45
|
+
const exitCode = await runCli(positionals, {
|
|
46
|
+
runInit,
|
|
47
|
+
runSnapshotCreate
|
|
48
|
+
});
|
|
49
|
+
if (exitCode !== 0) {
|
|
50
|
+
process.exit(exitCode);
|
|
62
51
|
}
|
|
63
|
-
|
|
64
|
-
const target = path.resolve(dir);
|
|
65
|
-
fs.mkdirSync(target, { recursive: true });
|
|
66
|
-
|
|
67
|
-
const name = path.basename(target);
|
|
68
|
-
|
|
69
|
-
// package.json
|
|
70
|
-
const pkg = {
|
|
71
|
-
name,
|
|
72
|
-
version: "0.1.0",
|
|
73
|
-
private: true,
|
|
74
|
-
type: "module",
|
|
75
|
-
scripts: {
|
|
76
|
-
dev: "next dev",
|
|
77
|
-
build: "next build",
|
|
78
|
-
start: "next start"
|
|
79
|
-
},
|
|
80
|
-
dependencies: {
|
|
81
|
-
"@sentry/junior": "latest",
|
|
82
|
-
next: "^16.0.0",
|
|
83
|
-
react: "^19.0.0",
|
|
84
|
-
"react-dom": "^19.0.0",
|
|
85
|
-
"@sentry/nextjs": "^10.0.0"
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
fs.writeFileSync(
|
|
89
|
-
path.join(target, "package.json"),
|
|
90
|
-
JSON.stringify(pkg, null, 2) + "\n"
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
// app/data/SOUL.md
|
|
94
|
-
const dataDir = path.join(target, "app", "data");
|
|
95
|
-
fs.mkdirSync(dataDir, { recursive: true });
|
|
96
|
-
fs.writeFileSync(
|
|
97
|
-
path.join(dataDir, "SOUL.md"),
|
|
98
|
-
`# ${name}\n\nYou are ${name}, a helpful assistant.\n`
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
// app/skills/
|
|
102
|
-
const skillsDir = path.join(target, "app", "skills");
|
|
103
|
-
fs.mkdirSync(skillsDir, { recursive: true });
|
|
104
|
-
fs.writeFileSync(path.join(skillsDir, ".gitkeep"), "");
|
|
105
|
-
|
|
106
|
-
// app/plugins/
|
|
107
|
-
const pluginsDir = path.join(target, "app", "plugins");
|
|
108
|
-
fs.mkdirSync(pluginsDir, { recursive: true });
|
|
109
|
-
fs.writeFileSync(path.join(pluginsDir, ".gitkeep"), "");
|
|
110
|
-
|
|
111
|
-
// .gitignore
|
|
112
|
-
fs.writeFileSync(
|
|
113
|
-
path.join(target, ".gitignore"),
|
|
114
|
-
[
|
|
115
|
-
"node_modules/",
|
|
116
|
-
".next/",
|
|
117
|
-
".env",
|
|
118
|
-
".env.local",
|
|
119
|
-
""
|
|
120
|
-
].join("\n")
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// .env.example
|
|
124
|
-
fs.writeFileSync(
|
|
125
|
-
path.join(target, ".env.example"),
|
|
126
|
-
[
|
|
127
|
-
"SLACK_BOT_TOKEN=",
|
|
128
|
-
"SLACK_SIGNING_SECRET=",
|
|
129
|
-
"JUNIOR_BOT_NAME=",
|
|
130
|
-
"AI_MODEL=",
|
|
131
|
-
"AI_FAST_MODEL=",
|
|
132
|
-
"REDIS_URL=",
|
|
133
|
-
"NEXT_PUBLIC_SENTRY_DSN=",
|
|
134
|
-
""
|
|
135
|
-
].join("\n")
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
writeWrapperFiles(target);
|
|
139
|
-
|
|
140
|
-
console.log(`Created ${name} at ${target}`);
|
|
141
|
-
console.log();
|
|
142
|
-
console.log(` cd ${dir} && pnpm install && pnpm dev`);
|
|
143
|
-
console.log();
|
|
144
|
-
process.exit(0);
|
|
145
52
|
}
|
|
146
53
|
|
|
147
|
-
|
|
148
|
-
|
|
54
|
+
main().catch((error) => {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
console.error(`junior command failed: ${message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
});
|
package/dist/app/layout.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Minimal root layout export for apps that do not provide one yet.
|
|
6
|
+
*/
|
|
4
7
|
declare function RootLayout({ children }: {
|
|
5
8
|
children: ReactNode;
|
|
6
9
|
}): react_jsx_runtime.JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appSlackRuntime,
|
|
3
|
+
bot,
|
|
4
|
+
createNormalizingStream,
|
|
5
|
+
resetBotDepsForTests,
|
|
6
|
+
setBotDepsForTests
|
|
7
|
+
} from "./chunk-RXNMJQPY.js";
|
|
8
|
+
import "./chunk-QHDDCUTN.js";
|
|
9
|
+
import "./chunk-PY4AI2GZ.js";
|
|
10
|
+
export {
|
|
11
|
+
appSlackRuntime,
|
|
12
|
+
bot,
|
|
13
|
+
createNormalizingStream,
|
|
14
|
+
resetBotDepsForTests,
|
|
15
|
+
setBotDepsForTests
|
|
16
|
+
};
|
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
setSpanStatus,
|
|
7
7
|
withContext,
|
|
8
8
|
withSpan
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PY4AI2GZ.js";
|
|
10
10
|
|
|
11
11
|
// src/handlers/webhooks.ts
|
|
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-T73QBC4J.js");
|
|
16
16
|
return bot;
|
|
17
17
|
}
|
|
18
18
|
async function POST(request, context) {
|
|
@@ -225,13 +225,21 @@ function emitSentry(level, body, attributes) {
|
|
|
225
225
|
loggerFn(body, attributes);
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
228
|
+
const sentryWithScope = sentry.withScope;
|
|
229
|
+
const sentryCaptureMessage = sentry.captureMessage;
|
|
230
|
+
const sentryLevel = level === "warn" ? "warning" : level;
|
|
231
|
+
if (typeof sentryWithScope === "function" && typeof sentryCaptureMessage === "function") {
|
|
232
|
+
sentryWithScope((scope) => {
|
|
233
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
234
|
+
scope.setExtra(key, value);
|
|
235
|
+
}
|
|
236
|
+
sentryCaptureMessage(body, sentryLevel);
|
|
237
|
+
});
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (typeof sentryCaptureMessage === "function") {
|
|
241
|
+
sentryCaptureMessage(body, sentryLevel);
|
|
242
|
+
}
|
|
235
243
|
}
|
|
236
244
|
function formatConsoleLevel(level) {
|
|
237
245
|
if (level === "debug") return "DBG";
|
|
@@ -353,12 +361,22 @@ var log = {
|
|
|
353
361
|
"exception.message": normalizedError.message,
|
|
354
362
|
"exception.stacktrace": normalizedError.stack
|
|
355
363
|
}, body ?? normalizedError.message);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
364
|
+
let eventId;
|
|
365
|
+
const sentryWithScope = Sentry.withScope;
|
|
366
|
+
const sentryCaptureException = Sentry.captureException;
|
|
367
|
+
if (typeof sentryWithScope === "function" && typeof sentryCaptureException === "function") {
|
|
368
|
+
sentryWithScope((scope) => {
|
|
369
|
+
for (const [key, value] of Object.entries(mergeAttributes(contextStorage.getStore(), attrs))) {
|
|
370
|
+
scope.setExtra(key, value);
|
|
371
|
+
}
|
|
372
|
+
eventId = sentryCaptureException(normalizedError);
|
|
373
|
+
});
|
|
374
|
+
return eventId;
|
|
375
|
+
}
|
|
376
|
+
if (typeof sentryCaptureException === "function") {
|
|
377
|
+
eventId = sentryCaptureException(normalizedError);
|
|
378
|
+
}
|
|
379
|
+
return eventId;
|
|
362
380
|
}
|
|
363
381
|
};
|
|
364
382
|
function withLogContext(context, callback) {
|
|
@@ -437,7 +455,7 @@ function logError(eventName, context = {}, attributes = {}, body) {
|
|
|
437
455
|
}
|
|
438
456
|
function logException(error, eventName, context = {}, attributes = {}, body) {
|
|
439
457
|
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
440
|
-
log.exception(eventName, normalizedError, toContextAndAttributes(context, attributes), body);
|
|
458
|
+
return log.exception(eventName, normalizedError, toContextAndAttributes(context, attributes), body);
|
|
441
459
|
}
|
|
442
460
|
function setTags(context = {}) {
|
|
443
461
|
setLogContext(context);
|
|
@@ -504,6 +522,34 @@ function setSpanStatus(status) {
|
|
|
504
522
|
function toOptionalString(value) {
|
|
505
523
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
506
524
|
}
|
|
525
|
+
function getActiveTraceId() {
|
|
526
|
+
const sentry = Sentry2;
|
|
527
|
+
if (typeof sentry.getActiveSpan !== "function" || typeof sentry.spanToJSON !== "function") {
|
|
528
|
+
return void 0;
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
const span = sentry.getActiveSpan();
|
|
532
|
+
if (!span) {
|
|
533
|
+
return void 0;
|
|
534
|
+
}
|
|
535
|
+
return toOptionalString(sentry.spanToJSON(span).trace_id);
|
|
536
|
+
} catch {
|
|
537
|
+
return void 0;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
function resolveErrorReference(eventId) {
|
|
541
|
+
const traceId = getActiveTraceId();
|
|
542
|
+
if (!eventId && !traceId) {
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
if (!traceId) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
return {
|
|
549
|
+
traceId,
|
|
550
|
+
...eventId ? { eventId } : {}
|
|
551
|
+
};
|
|
552
|
+
}
|
|
507
553
|
|
|
508
554
|
export {
|
|
509
555
|
logInfo,
|
|
@@ -516,5 +562,6 @@ export {
|
|
|
516
562
|
withSpan,
|
|
517
563
|
setSpanAttributes,
|
|
518
564
|
setSpanStatus,
|
|
519
|
-
toOptionalString
|
|
565
|
+
toOptionalString,
|
|
566
|
+
resolveErrorReference
|
|
520
567
|
};
|