Skip to content

Commit 95f4bb4

Browse files
committed
refacotrs
1 parent 642b670 commit 95f4bb4

File tree

12 files changed

+507
-110
lines changed

12 files changed

+507
-110
lines changed

apps/api-v2/scripts/create-user.mts

Lines changed: 0 additions & 1 deletion
This file was deleted.

apps/api-v2/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import buildTasksRouter from "./routers/tasks";
99
import buildStatsRouter from "./routers/stats";
1010
import { loggerOptions } from "./logging";
1111
import responseTime from "response-time";
12+
import { errorHandler } from "./mws";
1213

1314
export const createApp = () => {
1415
const app = express();
@@ -22,6 +23,7 @@ export const createApp = () => {
2223
credentials: true, // accept cookies from clients
2324
})
2425
);
26+
app.use(errorHandler);
2527
app.use(cookieParser()); // parses the cookies because apparently express doesn't do this by default
2628
app.use(express.json()); // parses the request body
2729
const responseTimeMws = responseTime();

apps/api-v2/src/mws.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export const authenticateJWTMiddleware = async (
7070
);
7171
}
7272
} catch (err) {
73-
console.error("Could not connect to Redis: " + err);
73+
logger.error("Could not connect to Redis: " + err);
7474
return res.status(500).send(
7575
new SupernovaResponse({
7676
error: "Internal Server Error",
@@ -106,13 +106,31 @@ export const validateRequestSchema =
106106
);
107107
}
108108
// log the error because this is unknown
109-
logger.error(error);
110-
return res.status(500).json(
109+
res.status(500).json(
111110
new SupernovaResponse({
112111
message: "Internal Server Error",
113112
error:
114113
"An error occurred while validating the request; this is on us, not you. Please try again later.",
115114
})
116115
);
116+
next(error);
117117
}
118118
};
119+
120+
/**
121+
* Generic error handler for the application.
122+
* Expect to have handled error response before this middleware
123+
* @param err
124+
* @param req
125+
* @param res
126+
* @param next
127+
*/
128+
export function errorHandler(
129+
err: Error,
130+
req: Request,
131+
res: Response,
132+
next: NextFunction
133+
) {
134+
logger.error(err);
135+
next();
136+
}

apps/api-v2/src/routers/tasks.ts

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
export default function buildTasksRouter(): Router {
1414
const router = Router();
1515

16-
router.get("/tasks", authenticateJWTMiddleware, async (req, res) => {
16+
router.get("/tasks", authenticateJWTMiddleware, async (req, res, next) => {
1717
try {
1818
const authCtx = getAuthContext(req);
1919
// get all tasks for the user
@@ -43,16 +43,14 @@ export default function buildTasksRouter(): Router {
4343
data: tasks,
4444
})
4545
);
46-
} catch (err) {
47-
if (err instanceof Error) {
48-
console.error(err);
49-
return res.status(500).json(
50-
new SupernovaResponse({
51-
message: "Something went wrong. Please try again later.",
52-
error: "Internal Server Error",
53-
})
54-
);
55-
}
46+
} catch (e) {
47+
res.status(500).json(
48+
new SupernovaResponse({
49+
message: "Something went wrong. Please try again later.",
50+
error: "Internal Server Error",
51+
})
52+
);
53+
next(e);
5654
}
5755
});
5856

@@ -61,7 +59,7 @@ export default function buildTasksRouter(): Router {
6159
"/tasks",
6260
authenticateJWTMiddleware,
6361
validateRequestSchema(createTaskRequestSchema),
64-
async (req, res) => {
62+
async (req, res, next) => {
6563
try {
6664
const authCtx = getAuthContext(req);
6765
const task = await prisma.task.create({
@@ -81,15 +79,13 @@ export default function buildTasksRouter(): Router {
8179
})
8280
);
8381
} catch (e) {
84-
if (e instanceof Error) {
85-
console.error(e);
86-
return res.status(500).json(
87-
new SupernovaResponse({
88-
message: "Something went wrong. Please try again later.",
89-
error: "Internal Server Error",
90-
})
91-
);
92-
}
82+
res.status(500).json(
83+
new SupernovaResponse({
84+
message: "Something went wrong. Please try again later.",
85+
error: "Internal Server Error",
86+
})
87+
);
88+
next(e);
9389
}
9490
}
9591
);
@@ -100,7 +96,7 @@ export default function buildTasksRouter(): Router {
10096
"/tasks/:id",
10197
authenticateJWTMiddleware,
10298
validateRequestSchema(updateTaskRequestSchema),
103-
async (req, res) => {
99+
async (req, res, next) => {
104100
try {
105101
const authCtx = getAuthContext(req);
106102
const task = await prisma.task.update({
@@ -123,15 +119,13 @@ export default function buildTasksRouter(): Router {
123119
})
124120
);
125121
} catch (e) {
126-
if (e instanceof Error) {
127-
console.error(e);
128-
return res.status(500).json(
129-
new SupernovaResponse({
130-
message: "Something went wrong. Please try again later.",
131-
error: "Internal Server Error",
132-
})
133-
);
134-
}
122+
res.status(500).json(
123+
new SupernovaResponse({
124+
message: "Something went wrong. Please try again later.",
125+
error: "Internal Server Error",
126+
})
127+
);
128+
next(e);
135129
}
136130
}
137131
);
@@ -141,7 +135,7 @@ export default function buildTasksRouter(): Router {
141135
"/tasks/:id",
142136
authenticateJWTMiddleware,
143137
validateRequestSchema(deleteTaskRequestSchema),
144-
async (req, res) => {
138+
async (req, res, next) => {
145139
try {
146140
const authCtx = getAuthContext(req);
147141
const task = await prisma.task.update({
@@ -160,15 +154,13 @@ export default function buildTasksRouter(): Router {
160154
})
161155
);
162156
} catch (e) {
163-
if (e instanceof Error) {
164-
console.error(e);
165-
return res.status(500).json(
166-
new SupernovaResponse({
167-
message: "Something went wrong. Please try again later.",
168-
error: "Internal Server Error",
169-
})
170-
);
171-
}
157+
res.status(500).json(
158+
new SupernovaResponse({
159+
message: "Something went wrong. Please try again later.",
160+
error: "Internal Server Error",
161+
})
162+
);
163+
next(e);
172164
}
173165
}
174166
);
@@ -178,7 +170,7 @@ export default function buildTasksRouter(): Router {
178170
"/tasks/:id/toggle-complete",
179171
authenticateJWTMiddleware,
180172
validateRequestSchema(toggleCompleteTaskRequestSchema),
181-
async (req, res) => {
173+
async (req, res, next) => {
182174
try {
183175
const authCtx = getAuthContext(req);
184176
// find the task
@@ -213,15 +205,13 @@ export default function buildTasksRouter(): Router {
213205
})
214206
);
215207
} catch (e) {
216-
if (e instanceof Error) {
217-
console.error(e);
218-
return res.status(500).json(
219-
new SupernovaResponse({
220-
message: "Something went wrong. Please try again later.",
221-
error: "Internal Server Error",
222-
})
223-
);
224-
}
208+
res.status(500).json(
209+
new SupernovaResponse({
210+
message: "Something went wrong. Please try again later.",
211+
error: "Internal Server Error",
212+
})
213+
);
214+
next(e);
225215
}
226216
}
227217
);

apps/desktop-v2/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ yarn-error.log*
3333
# typescript
3434
*.tsbuildinfo
3535
next-env.d.ts
36+
37+
# Sentry Auth Token
38+
.sentryclirc

apps/desktop-v2/hooks/useSupernovaTasksUI.tsx

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ export default function useSupernovaTasksUI() {
7979
});
8080
}
8181
console.log("updated successfully");
82-
} catch (e: any) {
83-
console.error(e);
82+
} catch (e) {
8483
// TODO: show error toast
8584
makeToast("Something went wrong", "error", {
8685
description: `This is something on our side.`,
@@ -143,29 +142,31 @@ export default function useSupernovaTasksUI() {
143142
};
144143
// optimistically update the task in the frontend
145144
setTasks(
146-
tasks.map((task) => {
147-
if (task.id === chosenTask.id) {
148-
return {
149-
...task,
150-
title: newTask.title,
151-
originalBuildText: newTask.originalBuildText,
152-
description: newTask.description,
153-
startTime:
154-
updatePayload.startAt === null
155-
? undefined
156-
: updatePayload.startAt === undefined
157-
? chosenTask.startTime
158-
: newTask.startTime, // if it's null, then cleared, else if undefined then don't update
159-
expectedDurationSeconds:
160-
updatePayload.expectedDurationSeconds === null
161-
? undefined
162-
: updatePayload.expectedDurationSeconds === undefined
163-
? chosenTask.expectedDurationSeconds
164-
: newTask.expectedDurationSeconds, // if it's null, then cleared, else if undefined then don't update
165-
};
166-
}
167-
return task;
168-
})
145+
reorderTaskList(
146+
tasks.map((task) => {
147+
if (task.id === chosenTask.id) {
148+
return {
149+
...task,
150+
title: newTask.title,
151+
originalBuildText: newTask.originalBuildText,
152+
description: newTask.description,
153+
startTime:
154+
updatePayload.startAt === null
155+
? undefined
156+
: updatePayload.startAt === undefined
157+
? chosenTask.startTime
158+
: newTask.startTime, // if it's null, then cleared, else if undefined then don't update
159+
expectedDurationSeconds:
160+
updatePayload.expectedDurationSeconds === null
161+
? undefined
162+
: updatePayload.expectedDurationSeconds === undefined
163+
? chosenTask.expectedDurationSeconds
164+
: newTask.expectedDurationSeconds, // if it's null, then cleared, else if undefined then don't update
165+
};
166+
}
167+
return task;
168+
})
169+
)
169170
);
170171
makeToast("Task updated successfully", "success");
171172

apps/desktop-v2/next.config.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,38 @@ const nextConfig = {
44
transpilePackages: ["@supernova/api-client"],
55
}
66

7-
module.exports = nextConfig
7+
// Injected content via Sentry wizard below
8+
9+
const { withSentryConfig } = require("@sentry/nextjs");
10+
11+
module.exports = withSentryConfig(
12+
nextConfig,
13+
{
14+
// For all available options, see:
15+
// https://github.com/getsentry/sentry-webpack-plugin#options
16+
17+
// Suppresses source map uploading logs during build
18+
silent: true,
19+
org: "supernova-0z",
20+
project: "javascript-nextjs",
21+
},
22+
{
23+
// For all available options, see:
24+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
25+
26+
// Upload a larger set of source maps for prettier stack traces (increases build time)
27+
widenClientFileUpload: true,
28+
29+
// Transpiles SDK to be compatible with IE11 (increases bundle size)
30+
transpileClientSDK: true,
31+
32+
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
33+
tunnelRoute: "/monitoring",
34+
35+
// Hides source maps from generated client bundles
36+
hideSourceMaps: true,
37+
38+
// Automatically tree-shake Sentry logger statements to reduce bundle size
39+
disableLogger: true,
40+
}
41+
);

apps/desktop-v2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@radix-ui/react-checkbox": "^1.0.4",
1414
"@radix-ui/react-dialog": "^1.0.4",
1515
"@radix-ui/react-icons": "^1.3.0",
16+
"@sentry/nextjs": "^7.72.0",
1617
"@supernova/api-client": "workspace:*",
1718
"@supernova/types": "workspace:*",
1819
"@tauri-apps/api": "^1.4.0",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This file configures the initialization of Sentry on the client.
2+
// The config you add here will be used whenever a users loads a page in their browser.
3+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
4+
5+
import * as Sentry from "@sentry/nextjs";
6+
7+
Sentry.init({
8+
dsn: "https://6f6f7fe2b894e163826396f63d7a2eec@o4505948505702400.ingest.sentry.io/4505948506816512",
9+
10+
// Adjust this value in production, or use tracesSampler for greater control
11+
tracesSampleRate: 1,
12+
13+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
14+
debug: false,
15+
16+
replaysOnErrorSampleRate: 1.0,
17+
18+
// This sets the sample rate to be 10%. You may want this to be 100% while
19+
// in development and sample at a lower rate in production
20+
replaysSessionSampleRate: 0.1,
21+
22+
// You can remove this option if you're not planning to use the Sentry Session Replay feature:
23+
integrations: [
24+
new Sentry.Replay({
25+
// Additional Replay configuration goes in here, for example:
26+
maskAllText: true,
27+
blockAllMedia: true,
28+
}),
29+
],
30+
});

apps/desktop-v2/sentry.edge.config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
2+
// The config you add here will be used whenever one of the edge features is loaded.
3+
// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.
4+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
5+
6+
import * as Sentry from "@sentry/nextjs";
7+
8+
Sentry.init({
9+
dsn: "https://6f6f7fe2b894e163826396f63d7a2eec@o4505948505702400.ingest.sentry.io/4505948506816512",
10+
11+
// Adjust this value in production, or use tracesSampler for greater control
12+
tracesSampleRate: 1,
13+
14+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
15+
debug: false,
16+
});

0 commit comments

Comments
 (0)