@sentry/junior-dashboard 0.77.0 → 0.78.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/dist/app.d.ts +10 -1
- package/dist/app.js +56 -1
- package/dist/client/api.d.ts +6 -6
- package/dist/index.d.ts +0 -7
- package/dist/index.js +71 -92
- package/dist/url.d.ts +1 -1
- package/package.json +3 -11
- package/src/app.ts +95 -1
- package/src/index.ts +0 -82
- package/src/url.ts +1 -1
- package/dist/config.d.ts +0 -4
- package/dist/handler.d.ts +0 -2
- package/dist/handler.js +0 -2133
- package/dist/nitro.d.ts +0 -22
- package/dist/nitro.js +0 -116
- package/src/config.ts +0 -76
- package/src/handler.ts +0 -26
- package/src/nitro.ts +0 -157
- package/src/virtual-modules.d.ts +0 -5
package/dist/url.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface DashboardConversationURLConfig extends DashboardBaseURLConfig {
|
|
|
5
5
|
basePath?: string;
|
|
6
6
|
conversationId: string;
|
|
7
7
|
}
|
|
8
|
-
/** Normalize dashboard route prefixes
|
|
8
|
+
/** Normalize dashboard route prefixes for host routes and external links. */
|
|
9
9
|
export declare function normalizeDashboardPath(path: string | undefined, fallback: string): string;
|
|
10
10
|
/** Resolve the dashboard origin used for browser auth and external links. */
|
|
11
11
|
export declare function resolveDashboardBaseURL(config?: DashboardBaseURLConfig): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-dashboard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.78.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -15,14 +15,6 @@
|
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
17
|
"default": "./dist/index.js"
|
|
18
|
-
},
|
|
19
|
-
"./nitro": {
|
|
20
|
-
"types": "./dist/nitro.d.ts",
|
|
21
|
-
"default": "./dist/nitro.js"
|
|
22
|
-
},
|
|
23
|
-
"./handler": {
|
|
24
|
-
"types": "./dist/handler.d.ts",
|
|
25
|
-
"default": "./dist/handler.js"
|
|
26
18
|
}
|
|
27
19
|
},
|
|
28
20
|
"files": [
|
|
@@ -41,8 +33,8 @@
|
|
|
41
33
|
"react-router": "^7.16.0",
|
|
42
34
|
"recharts": "^3.8.1",
|
|
43
35
|
"shiki": "4.1.0",
|
|
44
|
-
"@sentry/junior-plugin-api": "0.
|
|
45
|
-
"@sentry/junior": "0.
|
|
36
|
+
"@sentry/junior-plugin-api": "0.78.0",
|
|
37
|
+
"@sentry/junior": "0.78.0"
|
|
46
38
|
},
|
|
47
39
|
"devDependencies": {
|
|
48
40
|
"@tailwindcss/cli": "^4.3.0",
|
package/src/app.ts
CHANGED
|
@@ -38,6 +38,17 @@ export interface JuniorDashboardOptions {
|
|
|
38
38
|
mockConversations?: boolean;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
interface DashboardRuntimeOptions extends JuniorDashboardOptions {
|
|
42
|
+
pluginRoutes?: DashboardPluginRoute[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface DashboardPluginRoute {
|
|
46
|
+
app: {
|
|
47
|
+
fetch(request: Request): Promise<Response> | Response;
|
|
48
|
+
};
|
|
49
|
+
pluginName: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
type Variables = {
|
|
42
53
|
dashboardSession: DashboardSession;
|
|
43
54
|
};
|
|
@@ -70,6 +81,66 @@ function normalizeValues(values: string[] | undefined): string[] {
|
|
|
70
81
|
];
|
|
71
82
|
}
|
|
72
83
|
|
|
84
|
+
/** Read dashboard list env vars as comma-separated strings or JSON arrays. */
|
|
85
|
+
function readEnvList(name: string): string[] | undefined {
|
|
86
|
+
const value = process.env[name];
|
|
87
|
+
if (!value?.trim()) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (value.trim().startsWith("[")) {
|
|
92
|
+
let parsed: unknown;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(value);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw new Error(`${name} must be a JSON string array`, {
|
|
97
|
+
cause: error,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (
|
|
101
|
+
!Array.isArray(parsed) ||
|
|
102
|
+
parsed.some((item) => typeof item !== "string")
|
|
103
|
+
) {
|
|
104
|
+
throw new Error(`${name} must be a JSON string array`);
|
|
105
|
+
}
|
|
106
|
+
return parsed;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return value
|
|
110
|
+
.split(",")
|
|
111
|
+
.map((item) => item.trim())
|
|
112
|
+
.filter(Boolean);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Read dashboard boolean env vars; only explicit true/false values apply. */
|
|
116
|
+
function readEnvFlag(name: string): boolean | undefined {
|
|
117
|
+
const value = process.env[name]?.trim();
|
|
118
|
+
if (!value) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
return value === "true" ? true : value === "false" ? false : undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function resolveDashboardOptions(
|
|
125
|
+
options: DashboardRuntimeOptions,
|
|
126
|
+
): DashboardRuntimeOptions {
|
|
127
|
+
return {
|
|
128
|
+
...options,
|
|
129
|
+
authRequired:
|
|
130
|
+
options.authRequired ?? readEnvFlag("JUNIOR_DASHBOARD_AUTH_REQUIRED"),
|
|
131
|
+
allowedGoogleDomains:
|
|
132
|
+
options.allowedGoogleDomains ??
|
|
133
|
+
readEnvList("JUNIOR_DASHBOARD_GOOGLE_DOMAINS"),
|
|
134
|
+
allowedEmails:
|
|
135
|
+
options.allowedEmails ?? readEnvList("JUNIOR_DASHBOARD_ALLOWED_EMAILS"),
|
|
136
|
+
trustedOrigins:
|
|
137
|
+
options.trustedOrigins ?? readEnvList("JUNIOR_DASHBOARD_TRUSTED_ORIGINS"),
|
|
138
|
+
mockConversations:
|
|
139
|
+
options.mockConversations ??
|
|
140
|
+
readEnvFlag("JUNIOR_DASHBOARD_MOCK_CONVERSATIONS"),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
73
144
|
function isJsonRoute(pathname: string): boolean {
|
|
74
145
|
return pathname.startsWith("/api/");
|
|
75
146
|
}
|
|
@@ -397,10 +468,26 @@ function renderFavicon(): Response {
|
|
|
397
468
|
);
|
|
398
469
|
}
|
|
399
470
|
|
|
471
|
+
function pluginRoutePrefix(pluginName: string): string {
|
|
472
|
+
return `/api/dashboard/plugins/${pluginName}`;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** Strip the core-owned plugin prefix before dispatching to a plugin app. */
|
|
476
|
+
function pluginRouteRequest(request: Request, prefix: string): Request {
|
|
477
|
+
const url = new URL(request.url);
|
|
478
|
+
const pathname = url.pathname;
|
|
479
|
+
const nextPath =
|
|
480
|
+
pathname === prefix ? "/" : pathname.slice(prefix.length) || "/";
|
|
481
|
+
url.pathname = nextPath.startsWith("/") ? nextPath : `/${nextPath}`;
|
|
482
|
+
return new Request(url, request);
|
|
483
|
+
}
|
|
484
|
+
|
|
400
485
|
/** Create the authenticated dashboard Hono app mounted by Nitro. */
|
|
401
486
|
export function createDashboardApp(
|
|
402
|
-
|
|
487
|
+
rawOptions: DashboardRuntimeOptions,
|
|
403
488
|
): Hono<{ Variables: Variables }> {
|
|
489
|
+
const options = resolveDashboardOptions(rawOptions);
|
|
490
|
+
|
|
404
491
|
if (process.env.SENTRY_DSN?.trim()) {
|
|
405
492
|
initSentry();
|
|
406
493
|
}
|
|
@@ -518,6 +605,13 @@ export function createDashboardApp(
|
|
|
518
605
|
app.get("/api/dashboard/sessions", async () => {
|
|
519
606
|
return Response.json(await reporting.getSessions());
|
|
520
607
|
});
|
|
608
|
+
for (const route of options.pluginRoutes ?? []) {
|
|
609
|
+
const prefix = pluginRoutePrefix(route.pluginName);
|
|
610
|
+
const handler = (c: Context<{ Variables: Variables }>) =>
|
|
611
|
+
route.app.fetch(pluginRouteRequest(c.req.raw, prefix));
|
|
612
|
+
app.all(prefix, handler);
|
|
613
|
+
app.all(`${prefix}/*`, handler);
|
|
614
|
+
}
|
|
521
615
|
app.get("/api/dashboard/conversation-stats", async () => {
|
|
522
616
|
try {
|
|
523
617
|
return Response.json(await readConversationStats(reporting));
|
package/src/index.ts
CHANGED
|
@@ -1,83 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type PluginRoute,
|
|
3
|
-
defineJuniorPlugin,
|
|
4
|
-
type PluginRegistration,
|
|
5
|
-
} from "@sentry/junior-plugin-api";
|
|
6
|
-
import { buildDashboardConversationURL, normalizeDashboardPath } from "./url";
|
|
7
|
-
import { createDashboardApp, type JuniorDashboardOptions } from "./app";
|
|
8
|
-
|
|
9
1
|
export { createDashboardApp, type JuniorDashboardOptions } from "./app";
|
|
10
|
-
|
|
11
|
-
export interface JuniorDashboardPluginOptions extends JuniorDashboardOptions {
|
|
12
|
-
disabled?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function dashboardRoutePaths(options: JuniorDashboardPluginOptions): string[] {
|
|
16
|
-
const basePath = normalizeDashboardPath(options.basePath, "/");
|
|
17
|
-
const authPath = normalizeDashboardPath(options.authPath, "/api/auth");
|
|
18
|
-
const pagePaths =
|
|
19
|
-
basePath === "/"
|
|
20
|
-
? [
|
|
21
|
-
"/",
|
|
22
|
-
"/conversations",
|
|
23
|
-
"/conversations/*",
|
|
24
|
-
"/plugins",
|
|
25
|
-
"/sessions",
|
|
26
|
-
"/sessions/*",
|
|
27
|
-
]
|
|
28
|
-
: [basePath, `${basePath}/*`];
|
|
29
|
-
|
|
30
|
-
return [
|
|
31
|
-
...pagePaths,
|
|
32
|
-
"/favicon.ico",
|
|
33
|
-
"/api/dashboard/*",
|
|
34
|
-
authPath,
|
|
35
|
-
`${authPath}/*`,
|
|
36
|
-
];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function dashboardRoutes(options: JuniorDashboardPluginOptions): PluginRoute[] {
|
|
40
|
-
let app: ReturnType<typeof createDashboardApp> | undefined;
|
|
41
|
-
const fetch = (request: Request) => {
|
|
42
|
-
app ??= createDashboardApp(options);
|
|
43
|
-
return app.fetch(request);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
return dashboardRoutePaths(options).map((path) => ({
|
|
47
|
-
handler: fetch,
|
|
48
|
-
path,
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Register dashboard routes and Slack footer links through plugin hooks. */
|
|
53
|
-
export function juniorDashboardPlugin(
|
|
54
|
-
options: JuniorDashboardPluginOptions = {},
|
|
55
|
-
): PluginRegistration {
|
|
56
|
-
return defineJuniorPlugin({
|
|
57
|
-
manifest: {
|
|
58
|
-
name: "dashboard",
|
|
59
|
-
displayName: "Dashboard",
|
|
60
|
-
description: "Junior dashboard routes and Slack footer links",
|
|
61
|
-
},
|
|
62
|
-
hooks: {
|
|
63
|
-
routes() {
|
|
64
|
-
if (options.disabled) {
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
return dashboardRoutes(options);
|
|
68
|
-
},
|
|
69
|
-
slackConversationLink(ctx) {
|
|
70
|
-
if (options.disabled) {
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
return {
|
|
74
|
-
url: buildDashboardConversationURL({
|
|
75
|
-
basePath: options.basePath,
|
|
76
|
-
baseURL: options.baseURL,
|
|
77
|
-
conversationId: ctx.conversationId,
|
|
78
|
-
}),
|
|
79
|
-
};
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
}
|
package/src/url.ts
CHANGED
|
@@ -19,7 +19,7 @@ function stripTrailingSlashes(value: string): string {
|
|
|
19
19
|
return end === value.length ? value : value.slice(0, end);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/** Normalize dashboard route prefixes
|
|
22
|
+
/** Normalize dashboard route prefixes for host routes and external links. */
|
|
23
23
|
export function normalizeDashboardPath(
|
|
24
24
|
path: string | undefined,
|
|
25
25
|
fallback: string,
|
package/dist/config.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { JuniorDashboardOptions } from "./app";
|
|
2
|
-
export type JuniorDashboardRuntimeConfig = Omit<JuniorDashboardOptions, "auth" | "reporting">;
|
|
3
|
-
/** Read dashboard runtime config injected by the Nitro module. */
|
|
4
|
-
export declare function resolveDashboardConfig(): Promise<JuniorDashboardRuntimeConfig>;
|
package/dist/handler.d.ts
DELETED